Merge branch 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc
* 'for-2.6.25' of git://git.kernel.org/pub/scm/linux/kernel/git/paulus/powerpc: (69 commits) [POWERPC] Add SPE registers to core dumps [POWERPC] Use regset code for compat PTRACE_*REGS* calls [POWERPC] Use generic compat_sys_ptrace [POWERPC] Use generic compat_ptrace_request [POWERPC] Use generic ptrace peekdata/pokedata [POWERPC] Use regset code for PTRACE_*REGS* requests [POWERPC] Switch to generic compat_binfmt_elf code [POWERPC] Switch to using user_regset-based core dumps [POWERPC] Add user_regset compat support [POWERPC] Add user_regset_view definitions [POWERPC] Use user_regset accessors for GPRs [POWERPC] ptrace accessors for special regs MSR and TRAP [POWERPC] Use user_regset accessors for SPE regs [POWERPC] Use user_regset accessors for altivec regs [POWERPC] Use user_regset accessors for FP regs [POWERPC] mpc52xx: fix compile error introduce when rebasing patch [POWERPC] 4xx: PCIe indirect DCR spinlock fix. [POWERPC] Add missing native dcr dcr_ind_lock spinlock [POWERPC] 4xx: Fix offset value on Warp board [POWERPC] 4xx: Add 440EPx Sequoia ehci dts entry ...
This commit is contained in:
commit
3796958130
102 changed files with 4181 additions and 977 deletions
|
@ -57,6 +57,7 @@ Table of Contents
|
|||
n) 4xx/Axon EMAC ethernet nodes
|
||||
o) Xilinx IP cores
|
||||
p) Freescale Synchronous Serial Interface
|
||||
q) USB EHCI controllers
|
||||
|
||||
VII - Specifying interrupt information for devices
|
||||
1) interrupts property
|
||||
|
@ -2577,6 +2578,20 @@ platforms are moved over to use the flattened-device-tree model.
|
|||
Requred properties:
|
||||
- current-speed : Baud rate of uartlite
|
||||
|
||||
v) Xilinx hwicap
|
||||
|
||||
Xilinx hwicap devices provide access to the configuration logic
|
||||
of the FPGA through the Internal Configuration Access Port
|
||||
(ICAP). The ICAP enables partial reconfiguration of the FPGA,
|
||||
readback of the configuration information, and some control over
|
||||
'warm boots' of the FPGA fabric.
|
||||
|
||||
Required properties:
|
||||
- xlnx,family : The family of the FPGA, necessary since the
|
||||
capabilities of the underlying ICAP hardware
|
||||
differ between different families. May be
|
||||
'virtex2p', 'virtex4', or 'virtex5'.
|
||||
|
||||
p) Freescale Synchronous Serial Interface
|
||||
|
||||
The SSI is a serial device that communicates with audio codecs. It can
|
||||
|
@ -2775,6 +2790,33 @@ platforms are moved over to use the flattened-device-tree model.
|
|||
interrupt-parent = < &ipic >;
|
||||
};
|
||||
|
||||
q) USB EHCI controllers
|
||||
|
||||
Required properties:
|
||||
- compatible : should be "usb-ehci".
|
||||
- reg : should contain at least address and length of the standard EHCI
|
||||
register set for the device. Optional platform-dependent registers
|
||||
(debug-port or other) can be also specified here, but only after
|
||||
definition of standard EHCI registers.
|
||||
- interrupts : one EHCI interrupt should be described here.
|
||||
If device registers are implemented in big endian mode, the device
|
||||
node should have "big-endian-regs" property.
|
||||
If controller implementation operates with big endian descriptors,
|
||||
"big-endian-desc" property should be specified.
|
||||
If both big endian registers and descriptors are used by the controller
|
||||
implementation, "big-endian" property can be specified instead of having
|
||||
both "big-endian-regs" and "big-endian-desc".
|
||||
|
||||
Example (Sequoia 440EPx):
|
||||
ehci@e0000300 {
|
||||
compatible = "ibm,usb-ehci-440epx", "usb-ehci";
|
||||
interrupt-parent = <&UIC0>;
|
||||
interrupts = <1a 4>;
|
||||
reg = <0 e0000300 90 0 e0000390 70>;
|
||||
big-endian;
|
||||
};
|
||||
|
||||
|
||||
More devices will be defined as this spec matures.
|
||||
|
||||
VII - Specifying interrupt information for devices
|
||||
|
|
|
@ -97,6 +97,7 @@ config EARLY_PRINTK
|
|||
config COMPAT
|
||||
bool
|
||||
default y if PPC64
|
||||
select COMPAT_BINFMT_ELF
|
||||
|
||||
config SYSVIPC_COMPAT
|
||||
bool
|
||||
|
@ -438,25 +439,6 @@ config WANT_DEVICE_TREE
|
|||
bool
|
||||
default n
|
||||
|
||||
config DEVICE_TREE
|
||||
string "Static device tree source file"
|
||||
depends on WANT_DEVICE_TREE
|
||||
help
|
||||
This specifies the device tree source (.dts) file to be
|
||||
compiled and included when building the bootwrapper. If a
|
||||
relative filename is given, then it will be relative to
|
||||
arch/powerpc/boot/dts. If you are not using the bootwrapper,
|
||||
or do not need to build a dts into the bootwrapper, this
|
||||
field is ignored.
|
||||
|
||||
For example, this is required when building a cuImage target
|
||||
for an older U-Boot, which cannot pass a device tree itself.
|
||||
Such a kernel will not work with a newer U-Boot that tries to
|
||||
pass a device tree (unless you tell it not to). If your U-Boot
|
||||
does not mention a device tree in "help bootm", then use the
|
||||
cuImage target and specify a device tree here. Otherwise, use
|
||||
the uImage target and leave this field blank.
|
||||
|
||||
endmenu
|
||||
|
||||
config ISA_DMA_API
|
||||
|
@ -512,7 +494,7 @@ config PCI
|
|||
bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
|
||||
|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
|
||||
|| PPC_PS3 || 44x
|
||||
default y if !40x && !CPM2 && !8xx && !PPC_83xx \
|
||||
default y if !40x && !CPM2 && !8xx && !PPC_MPC512x && !PPC_83xx \
|
||||
&& !PPC_85xx && !PPC_86xx
|
||||
default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
|
||||
default PCI_QSPAN if !4xx && !CPM2 && 8xx
|
||||
|
|
|
@ -151,14 +151,11 @@ core-$(CONFIG_XMON) += arch/powerpc/xmon/
|
|||
drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
|
||||
|
||||
# Default to zImage, override when needed
|
||||
defaultimage-y := zImage
|
||||
defaultimage-$(CONFIG_DEFAULT_UIMAGE) := uImage
|
||||
KBUILD_IMAGE := $(defaultimage-y)
|
||||
all: $(KBUILD_IMAGE)
|
||||
all: zImage
|
||||
|
||||
CPPFLAGS_vmlinux.lds := -Upowerpc
|
||||
|
||||
BOOT_TARGETS = zImage zImage.initrd uImage
|
||||
BOOT_TARGETS = zImage zImage.initrd uImage treeImage.% cuImage.%
|
||||
|
||||
PHONY += $(BOOT_TARGETS)
|
||||
|
||||
|
@ -180,7 +177,7 @@ define archhelp
|
|||
endef
|
||||
|
||||
install: vdso_install
|
||||
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
|
||||
$(Q)$(MAKE) $(build)=$(boot) install
|
||||
|
||||
vdso_install:
|
||||
ifeq ($(CONFIG_PPC64),y)
|
||||
|
|
|
@ -60,8 +60,9 @@ src-wlib := string.S crt0.S stdio.c main.c \
|
|||
src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \
|
||||
cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
|
||||
ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
|
||||
cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c cuboot-bamboo.c \
|
||||
fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c cuboot-taishan.c \
|
||||
cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \
|
||||
cuboot-bamboo.c cuboot-mpc7448hpc2.c cuboot-taishan.c \
|
||||
fixed-head.S ep88xc.c ep405.c \
|
||||
cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \
|
||||
cuboot-warp.c cuboot-85xx-cpm2.c
|
||||
src-boot := $(src-wlib) $(src-plat) empty.c
|
||||
|
@ -123,6 +124,8 @@ targets += $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a)
|
|||
extra-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
|
||||
$(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds
|
||||
|
||||
dtstree := $(srctree)/$(src)/dts
|
||||
|
||||
wrapper :=$(srctree)/$(src)/wrapper
|
||||
wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc) \
|
||||
$(wrapper) FORCE
|
||||
|
@ -181,7 +184,7 @@ quiet_cmd_wrap = WRAP $@
|
|||
image-$(CONFIG_PPC_PSERIES) += zImage.pseries
|
||||
image-$(CONFIG_PPC_MAPLE) += zImage.pseries
|
||||
image-$(CONFIG_PPC_IBM_CELL_BLADE) += zImage.pseries
|
||||
image-$(CONFIG_PPC_PS3) += zImage.ps3
|
||||
image-$(CONFIG_PPC_PS3) += zImage-dtb.ps3
|
||||
image-$(CONFIG_PPC_CELLEB) += zImage.pseries
|
||||
image-$(CONFIG_PPC_CHRP) += zImage.chrp
|
||||
image-$(CONFIG_PPC_EFIKA) += zImage.chrp
|
||||
|
@ -191,33 +194,69 @@ image-$(CONFIG_PPC_PRPMC2800) += zImage.prpmc2800
|
|||
image-$(CONFIG_PPC_ISERIES) += zImage.iseries
|
||||
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
|
||||
|
||||
ifneq ($(CONFIG_DEVICE_TREE),"")
|
||||
image-$(CONFIG_PPC_8xx) += cuImage.8xx
|
||||
image-$(CONFIG_PPC_EP88XC) += zImage.ep88xc
|
||||
image-$(CONFIG_EP405) += zImage.ep405
|
||||
image-$(CONFIG_8260) += cuImage.pq2
|
||||
image-$(CONFIG_EP8248E) += zImage.ep8248e
|
||||
image-$(CONFIG_PPC_MPC52xx) += cuImage.52xx
|
||||
image-$(CONFIG_STORCENTER) += cuImage.824x
|
||||
image-$(CONFIG_PPC_83xx) += cuImage.83xx
|
||||
image-$(CONFIG_PPC_85xx) += cuImage.85xx
|
||||
ifeq ($(CONFIG_CPM2),y)
|
||||
image-$(CONFIG_PPC_85xx) += cuImage.85xx-cpm2
|
||||
endif
|
||||
image-$(CONFIG_MPC7448HPC2) += cuImage.hpc2
|
||||
#
|
||||
# Targets which embed a device tree blob
|
||||
#
|
||||
# Theses are default targets to build images which embed device tree blobs.
|
||||
# They are only required on boards which do not have FDT support in firmware.
|
||||
# Boards with newish u-boot firmare can use the uImage target above
|
||||
#
|
||||
|
||||
# Board ports in arch/powerpc/platform/40x/Kconfig
|
||||
image-$(CONFIG_EP405) += zImage-dtb.ep405
|
||||
image-$(CONFIG_WALNUT) += treeImage.walnut
|
||||
|
||||
# Board ports in arch/powerpc/platform/44x/Kconfig
|
||||
image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony
|
||||
image-$(CONFIG_BAMBOO) += treeImage.bamboo cuImage.bamboo
|
||||
image-$(CONFIG_SEQUOIA) += cuImage.sequoia
|
||||
image-$(CONFIG_RAINIER) += cuImage.rainier
|
||||
image-$(CONFIG_WALNUT) += treeImage.walnut
|
||||
image-$(CONFIG_TAISHAN) += cuImage.taishan
|
||||
image-$(CONFIG_KATMAI) += cuImage.katmai
|
||||
image-$(CONFIG_WARP) += cuImage.warp
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_REDBOOT),"")
|
||||
image-$(CONFIG_PPC_8xx) += zImage.redboot-8xx
|
||||
endif
|
||||
# Board ports in arch/powerpc/platform/8xx/Kconfig
|
||||
image-$(CONFIG_PPC_MPC86XADS) += cuImage.mpc866ads
|
||||
image-$(CONFIG_PPC_MPC885ADS) += cuImage.mpc885ads
|
||||
image-$(CONFIG_PPC_EP88XC) += zImage-dtb.ep88xc
|
||||
image-$(CONFIG_PPC_ADDER875) += cuImage.adder875-uboot \
|
||||
zImage-dtb.adder875-redboot
|
||||
|
||||
# Board ports in arch/powerpc/platform/52xx/Kconfig
|
||||
image-$(CONFIG_PPC_LITE5200) += cuImage.lite5200 cuImage.lite5200b
|
||||
|
||||
# Board ports in arch/powerpc/platform/82xx/Kconfig
|
||||
image-$(CONFIG_MPC8272_ADS) += cuImage.mpc8272ads
|
||||
image-$(CONFIG_PQ2FADS) += cuImage.pq2fads
|
||||
image-$(CONFIG_EP8248E) += zImage-dtb.ep8248e
|
||||
|
||||
# Board ports in arch/powerpc/platform/83xx/Kconfig
|
||||
image-$(CONFIG_MPC832x_MDS) += cuImage.mpc832x_mds
|
||||
image-$(CONFIG_MPC832x_RDB) += cuImage.mpc832x_rdb
|
||||
image-$(CONFIG_MPC834x_ITX) += cuImage.mpc8349emitx \
|
||||
cuImage.mpc8349emitxgp
|
||||
image-$(CONFIG_MPC834x_MDS) += cuImage.mpc834x_mds
|
||||
image-$(CONFIG_MPC836x_MDS) += cuImage.mpc836x_mds
|
||||
|
||||
# Board ports in arch/powerpc/platform/85xx/Kconfig
|
||||
image-$(CONFIG_MPC8540_ADS) += cuImage.mpc8540ads
|
||||
image-$(CONFIG_MPC8560_ADS) += cuImage.mpc8560ads
|
||||
image-$(CONFIG_MPC85xx_CDS) += cuImage.mpc8541cds \
|
||||
cuImage.mpc8548cds \
|
||||
cuImage.mpc8555cds
|
||||
image-$(CONFIG_MPC85xx_MDS) += cuImage.mpc8568mds
|
||||
image-$(CONFIG_MPC85xx_DS) += cuImage.mpc8544ds \
|
||||
cuImage.mpc8572ds
|
||||
image-$(CONFIG_TQM8540) += cuImage.tqm8540
|
||||
image-$(CONFIG_TQM8541) += cuImage.tqm8541
|
||||
image-$(CONFIG_TQM8555) += cuImage.tqm8555
|
||||
image-$(CONFIG_TQM8560) += cuImage.tqm8560
|
||||
image-$(CONFIG_SBC8548) += cuImage.tqm8548
|
||||
image-$(CONFIG_SBC8560) += cuImage.tqm8560
|
||||
|
||||
# Board ports in arch/powerpc/platform/embedded6xx/Kconfig
|
||||
image-$(CONFIG_STORCENTER) += cuImage.storcenter
|
||||
image-$(CONFIG_MPC7448HPC2) += cuImage.mpc7448hpc2
|
||||
|
||||
# For 32-bit powermacs, build the COFF and miboot images
|
||||
# as well as the ELF images.
|
||||
|
@ -233,24 +272,20 @@ targets += $(image-y) $(initrd-y)
|
|||
|
||||
$(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz
|
||||
|
||||
# If CONFIG_WANT_DEVICE_TREE is set and CONFIG_DEVICE_TREE isn't an
|
||||
# empty string, define 'dts' to be path to the dts
|
||||
# CONFIG_DEVICE_TREE will have "" around it, make sure to strip them
|
||||
ifeq ($(CONFIG_WANT_DEVICE_TREE),y)
|
||||
ifneq ($(CONFIG_DEVICE_TREE),"")
|
||||
dts = $(if $(shell echo $(CONFIG_DEVICE_TREE) | grep '^/'),\
|
||||
,$(srctree)/$(src)/dts/)$(CONFIG_DEVICE_TREE:"%"=%)
|
||||
endif
|
||||
endif
|
||||
|
||||
# Don't put the ramdisk on the pattern rule; when its missing make will try
|
||||
# the pattern rule with less dependencies that also matches (even with the
|
||||
# hard dependency listed).
|
||||
$(obj)/zImage.initrd.%: vmlinux $(wrapperbits) $(dts)
|
||||
$(call if_changed,wrap,$*,$(dts),,$(obj)/ramdisk.image.gz)
|
||||
$(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
|
||||
$(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
|
||||
|
||||
$(obj)/zImage.%: vmlinux $(wrapperbits) $(dts)
|
||||
$(call if_changed,wrap,$*,$(dts))
|
||||
$(obj)/zImage.%: vmlinux $(wrapperbits)
|
||||
$(call if_changed,wrap,$*)
|
||||
|
||||
$(obj)/zImage-dtb.initrd.%: vmlinux $(wrapperbits) $(dtstree)/%.dts
|
||||
$(call if_changed,wrap,$*,$(dtstree)/$*.dts,,$(obj)/ramdisk.image.gz)
|
||||
|
||||
$(obj)/zImage-dtb.%: vmlinux $(wrapperbits) $(dtstree)/%.dts
|
||||
$(call if_changed,wrap,$*,$(dtstree)/$*.dts)
|
||||
|
||||
# This cannot be in the root of $(src) as the zImage rule always adds a $(obj)
|
||||
# prefix
|
||||
|
@ -260,24 +295,17 @@ $(obj)/vmlinux.strip: vmlinux
|
|||
$(obj)/zImage.iseries: vmlinux
|
||||
$(STRIP) -s -R .comment $< -o $@
|
||||
|
||||
$(obj)/zImage.ps3: vmlinux $(wrapper) $(wrapperbits) $(srctree)/$(src)/dts/ps3.dts
|
||||
$(STRIP) -s -R .comment $< -o vmlinux.strip
|
||||
$(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,)
|
||||
|
||||
$(obj)/zImage.initrd.ps3: vmlinux $(wrapper) $(wrapperbits) $(srctree)/$(src)/dts/ps3.dts $(obj)/ramdisk.image.gz
|
||||
$(call cmd,wrap,ps3,$(srctree)/$(src)/dts/ps3.dts,,$(obj)/ramdisk.image.gz)
|
||||
|
||||
$(obj)/uImage: vmlinux $(wrapperbits)
|
||||
$(call if_changed,wrap,uboot)
|
||||
|
||||
$(obj)/cuImage.%: vmlinux $(dts) $(wrapperbits)
|
||||
$(call if_changed,wrap,cuboot-$*,$(dts))
|
||||
$(obj)/cuImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
|
||||
$(call if_changed,wrap,cuboot-$*,$(dtstree)/$*.dts)
|
||||
|
||||
$(obj)/treeImage.initrd.%: vmlinux $(dts) $(wrapperbits)
|
||||
$(call if_changed,wrap,treeboot-$*,$(dts),,$(obj)/ramdisk.image.gz)
|
||||
$(obj)/treeImage.initrd.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
|
||||
$(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts,,$(obj)/ramdisk.image.gz)
|
||||
|
||||
$(obj)/treeImage.%: vmlinux $(dts) $(wrapperbits)
|
||||
$(call if_changed,wrap,treeboot-$*,$(dts))
|
||||
$(obj)/treeImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
|
||||
$(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts)
|
||||
|
||||
# If there isn't a platform selected then just strip the vmlinux.
|
||||
ifeq (,$(image-y))
|
||||
|
|
|
@ -151,6 +151,7 @@
|
|||
compatible = "fsl,mpc875-brg",
|
||||
"fsl,cpm1-brg",
|
||||
"fsl,cpm-brg";
|
||||
clock-frequency = <50000000>;
|
||||
reg = <0x9f0 0x10>;
|
||||
};
|
||||
|
||||
|
|
|
@ -150,6 +150,7 @@
|
|||
compatible = "fsl,mpc875-brg",
|
||||
"fsl,cpm1-brg",
|
||||
"fsl,cpm-brg";
|
||||
clock-frequency = <50000000>;
|
||||
reg = <0x9f0 0x10>;
|
||||
};
|
||||
|
||||
|
|
122
arch/powerpc/boot/dts/mpc5121ads.dts
Normal file
122
arch/powerpc/boot/dts/mpc5121ads.dts
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* MPC5121E MDS Device Tree Source
|
||||
*
|
||||
* Copyright 2007 Freescale Semiconductor Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/dts-v1/;
|
||||
|
||||
/ {
|
||||
model = "mpc5121ads";
|
||||
compatible = "fsl,mpc5121ads";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
cpus {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
PowerPC,5121@0 {
|
||||
device_type = "cpu";
|
||||
reg = <0>;
|
||||
d-cache-line-size = <0x20>; // 32 bytes
|
||||
i-cache-line-size = <0x20>; // 32 bytes
|
||||
d-cache-size = <0x8000>; // L1, 32K
|
||||
i-cache-size = <0x8000>; // L1, 32K
|
||||
timebase-frequency = <49500000>;// 49.5 MHz (csb/4)
|
||||
bus-frequency = <198000000>; // 198 MHz csb bus
|
||||
clock-frequency = <396000000>; // 396 MHz ppc core
|
||||
};
|
||||
};
|
||||
|
||||
memory {
|
||||
device_type = "memory";
|
||||
reg = <0x00000000 0x10000000>; // 256MB at 0
|
||||
};
|
||||
|
||||
localbus@80000020 {
|
||||
compatible = "fsl,mpc5121ads-localbus";
|
||||
#address-cells = <2>;
|
||||
#size-cells = <1>;
|
||||
reg = <0x80000020 0x40>;
|
||||
|
||||
ranges = <0x0 0x0 0xfc000000 0x04000000
|
||||
0x2 0x0 0x82000000 0x00008000>;
|
||||
|
||||
flash@0,0 {
|
||||
compatible = "cfi-flash";
|
||||
reg = <0 0x0 0x4000000>;
|
||||
bank-width = <4>;
|
||||
device-width = <1>;
|
||||
};
|
||||
|
||||
board-control@2,0 {
|
||||
compatible = "fsl,mpc5121ads-cpld";
|
||||
reg = <0x2 0x0 0x8000>;
|
||||
};
|
||||
};
|
||||
|
||||
soc@80000000 {
|
||||
compatible = "fsl,mpc5121-immr";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
#interrupt-cells = <2>;
|
||||
ranges = <0x0 0x80000000 0x400000>;
|
||||
reg = <0x80000000 0x400000>;
|
||||
bus-frequency = <66000000>; // 66 MHz ips bus
|
||||
|
||||
|
||||
// IPIC
|
||||
// interrupts cell = <intr #, sense>
|
||||
// sense values match linux IORESOURCE_IRQ_* defines:
|
||||
// sense == 8: Level, low assertion
|
||||
// sense == 2: Edge, high-to-low change
|
||||
//
|
||||
ipic: interrupt-controller@c00 {
|
||||
compatible = "fsl,mpc5121-ipic", "fsl,ipic";
|
||||
interrupt-controller;
|
||||
#address-cells = <0>;
|
||||
#interrupt-cells = <2>;
|
||||
reg = <0xc00 0x100>;
|
||||
};
|
||||
|
||||
// 512x PSCs are not 52xx PSCs compatible
|
||||
// PSC3 serial port A aka ttyPSC0
|
||||
serial@11300 {
|
||||
device_type = "serial";
|
||||
compatible = "fsl,mpc5121-psc-uart";
|
||||
// Logical port assignment needed until driver
|
||||
// learns to use aliases
|
||||
port-number = <0>;
|
||||
cell-index = <3>;
|
||||
reg = <0x11300 0x100>;
|
||||
interrupts = <0x28 0x8>; // actually the fifo irq
|
||||
interrupt-parent = < &ipic >;
|
||||
};
|
||||
|
||||
// PSC4 serial port B aka ttyPSC1
|
||||
serial@11400 {
|
||||
device_type = "serial";
|
||||
compatible = "fsl,mpc5121-psc-uart";
|
||||
// Logical port assignment needed until driver
|
||||
// learns to use aliases
|
||||
port-number = <1>;
|
||||
cell-index = <4>;
|
||||
reg = <0x11400 0x100>;
|
||||
interrupts = <0x28 0x8>; // actually the fifo irq
|
||||
interrupt-parent = < &ipic >;
|
||||
};
|
||||
|
||||
pscsfifo@11f00 {
|
||||
compatible = "fsl,mpc5121-psc-fifo";
|
||||
reg = <0x11f00 0x100>;
|
||||
interrupts = <0x28 0x8>;
|
||||
interrupt-parent = < &ipic >;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -118,6 +118,10 @@
|
|||
interrupts = <14 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
dfsrr;
|
||||
rtc@68 {
|
||||
compatible = "dallas,ds1339";
|
||||
reg = <0x68>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c@3100 {
|
||||
|
|
|
@ -96,7 +96,7 @@
|
|||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
device_type = "soc";
|
||||
compatible = "simple-bus";
|
||||
compatible = "fsl,mpc8315-immr", "simple-bus";
|
||||
ranges = <0 0xe0000000 0x00100000>;
|
||||
reg = <0xe0000000 0x00000200>;
|
||||
bus-frequency = <0>;
|
||||
|
|
|
@ -332,7 +332,7 @@
|
|||
0xc000 0x0 0x0 0x3 &ipic 23 0x8
|
||||
0xc000 0x0 0x0 0x4 &ipic 20 0x8>;
|
||||
interrupt-parent = <&ipic>;
|
||||
interrupts = <66 0x8>;
|
||||
interrupts = <67 0x8>;
|
||||
bus-range = <0 0>;
|
||||
ranges = <0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000
|
||||
0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
|
||||
|
|
|
@ -42,6 +42,18 @@
|
|||
bus-frequency = <0>;
|
||||
clock-frequency = <0>;
|
||||
};
|
||||
|
||||
PowerPC,8572@1 {
|
||||
device_type = "cpu";
|
||||
reg = <1>;
|
||||
d-cache-line-size = <20>; // 32 bytes
|
||||
i-cache-line-size = <20>; // 32 bytes
|
||||
d-cache-size = <8000>; // L1, 32K
|
||||
i-cache-size = <8000>; // L1, 32K
|
||||
timebase-frequency = <0>;
|
||||
bus-frequency = <0>;
|
||||
clock-frequency = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
memory {
|
||||
|
|
|
@ -166,6 +166,7 @@
|
|||
compatible = "fsl,mpc885-brg",
|
||||
"fsl,cpm1-brg",
|
||||
"fsl,cpm-brg";
|
||||
clock-frequency = <0>;
|
||||
reg = <9f0 10>;
|
||||
};
|
||||
|
||||
|
|
|
@ -138,6 +138,14 @@
|
|||
interrupts = <15 8>;
|
||||
};
|
||||
|
||||
USB0: ehci@e0000300 {
|
||||
compatible = "ibm,usb-ehci-440epx", "usb-ehci";
|
||||
interrupt-parent = <&UIC0>;
|
||||
interrupts = <1a 4>;
|
||||
reg = <0 e0000300 90 0 e0000390 70>;
|
||||
big-endian;
|
||||
};
|
||||
|
||||
POB0: opb {
|
||||
compatible = "ibm,opb-440epx", "ibm,opb";
|
||||
#address-cells = <1>;
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
/ {
|
||||
model = "StorCenter";
|
||||
compatible = "storcenter";
|
||||
compatible = "iomega,storcenter";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
|
@ -62,12 +62,12 @@
|
|||
#size-cells = <0>;
|
||||
compatible = "fsl-i2c";
|
||||
reg = <0x3000 0x100>;
|
||||
interrupts = <5 2>;
|
||||
interrupts = <17 2>;
|
||||
interrupt-parent = <&mpic>;
|
||||
|
||||
rtc@68 {
|
||||
compatible = "dallas,ds1337";
|
||||
reg = <68>;
|
||||
reg = <0x68>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -78,7 +78,7 @@
|
|||
reg = <0x4500 0x20>;
|
||||
clock-frequency = <97553800>; /* Hz */
|
||||
current-speed = <115200>;
|
||||
interrupts = <9 2>;
|
||||
interrupts = <25 2>;
|
||||
interrupt-parent = <&mpic>;
|
||||
};
|
||||
|
||||
|
@ -89,7 +89,7 @@
|
|||
reg = <0x4600 0x20>;
|
||||
clock-frequency = <97553800>; /* Hz */
|
||||
current-speed = <9600>;
|
||||
interrupts = <10 2>;
|
||||
interrupts = <26 2>;
|
||||
interrupt-parent = <&mpic>;
|
||||
};
|
||||
|
||||
|
@ -136,6 +136,6 @@
|
|||
};
|
||||
|
||||
chosen {
|
||||
linux,stdout-path = "/soc/serial@4500";
|
||||
linux,stdout-path = &serial0;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -158,6 +158,29 @@ miboot|uboot)
|
|||
cuboot*)
|
||||
binary=y
|
||||
gzip=
|
||||
case "$platform" in
|
||||
*-mpc885ads|*-adder875*|*-ep88xc)
|
||||
platformo=$object/cuboot-8xx.o
|
||||
;;
|
||||
*5200*|*-motionpro)
|
||||
platformo=$object/cuboot-52xx.o
|
||||
;;
|
||||
*-pq2fads|*-ep8248e|*-mpc8272*|*-storcenter)
|
||||
platformo=$object/cuboot-pq2.o
|
||||
;;
|
||||
*-mpc824*)
|
||||
platformo=$object/cuboot-824x.o
|
||||
;;
|
||||
*-mpc83*)
|
||||
platformo=$object/cuboot-83xx.o
|
||||
;;
|
||||
*-tqm8541|*-mpc8560*|*-tqm8560|*-tqm8555*)
|
||||
platformo=$object/cuboot-85xx-cpm2.o
|
||||
;;
|
||||
*-mpc85*)
|
||||
platformo=$object/cuboot-85xx.o
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
ps3)
|
||||
platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o"
|
||||
|
|
|
@ -186,7 +186,7 @@ CONFIG_PREEMPT_NONE=y
|
|||
# CONFIG_PREEMPT is not set
|
||||
CONFIG_BINFMT_ELF=y
|
||||
# CONFIG_BINFMT_MISC is not set
|
||||
# CONFIG_MATH_EMULATION is not set
|
||||
CONFIG_MATH_EMULATION=y
|
||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||
CONFIG_ARCH_FLATMEM_ENABLE=y
|
||||
CONFIG_ARCH_POPULATES_NODE_MAP=y
|
||||
|
@ -416,14 +416,14 @@ CONFIG_PHYLIB=y
|
|||
# MII PHY device drivers
|
||||
#
|
||||
CONFIG_MARVELL_PHY=y
|
||||
# CONFIG_DAVICOM_PHY is not set
|
||||
CONFIG_DAVICOM_PHY=y
|
||||
# CONFIG_QSEMI_PHY is not set
|
||||
# CONFIG_LXT_PHY is not set
|
||||
# CONFIG_CICADA_PHY is not set
|
||||
# CONFIG_VITESSE_PHY is not set
|
||||
CONFIG_VITESSE_PHY=y
|
||||
# CONFIG_SMSC_PHY is not set
|
||||
# CONFIG_BROADCOM_PHY is not set
|
||||
# CONFIG_ICPLUS_PHY is not set
|
||||
CONFIG_ICPLUS_PHY=y
|
||||
# CONFIG_FIXED_PHY is not set
|
||||
# CONFIG_MDIO_BITBANG is not set
|
||||
CONFIG_NET_ETHERNET=y
|
||||
|
@ -436,7 +436,7 @@ CONFIG_MII=y
|
|||
CONFIG_NETDEV_1000=y
|
||||
CONFIG_GIANFAR=y
|
||||
# CONFIG_GFAR_NAPI is not set
|
||||
# CONFIG_UCC_GETH is not set
|
||||
CONFIG_UCC_GETH=y
|
||||
CONFIG_NETDEV_10000=y
|
||||
|
||||
#
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
# Makefile for the linux kernel.
|
||||
#
|
||||
|
||||
CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
|
||||
|
||||
ifeq ($(CONFIG_PPC64),y)
|
||||
CFLAGS_prom_init.o += -mno-minimal-toc
|
||||
endif
|
||||
|
@ -15,7 +17,7 @@ obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
|
|||
init_task.o process.o systbl.o idle.o \
|
||||
signal.o
|
||||
obj-y += vdso32/
|
||||
obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
|
||||
obj-$(CONFIG_PPC64) += setup_64.o sys_ppc32.o \
|
||||
signal_64.o ptrace32.o \
|
||||
paca.o cpu_setup_ppc970.o \
|
||||
cpu_setup_pa6t.o \
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <linux/mman.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#ifdef CONFIG_PPC64
|
||||
#include <linux/time.h>
|
||||
#include <linux/hardirq.h>
|
||||
|
@ -312,7 +313,7 @@ int main(void)
|
|||
DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
|
||||
DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
|
||||
DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
|
||||
DEFINE(CLOCK_REALTIME_RES, TICK_NSEC);
|
||||
DEFINE(CLOCK_REALTIME_RES, (KTIME_MONOTONIC_RES).tv64);
|
||||
|
||||
#ifdef CONFIG_BUG
|
||||
DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry));
|
||||
|
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* binfmt_elf32.c: Support 32-bit PPC ELF binaries on Power3 and followons.
|
||||
* based on the SPARC64 version.
|
||||
* Copyright (C) 1995, 1996, 1997, 1998 David S. Miller (davem@redhat.com)
|
||||
* Copyright (C) 1995, 1996, 1997, 1998 Jakub Jelinek (jj@ultra.linux.cz)
|
||||
*
|
||||
* Copyright (C) 2000,2001 Ken Aaker (kdaaker@rchland.vnet.ibm.com), IBM Corp
|
||||
* Copyright (C) 2001 Anton Blanchard (anton@au.ibm.com), IBM
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/elfcore-compat.h>
|
||||
|
||||
#undef ELF_ARCH
|
||||
#undef ELF_CLASS
|
||||
#define ELF_CLASS ELFCLASS32
|
||||
#define ELF_ARCH EM_PPC
|
||||
|
||||
#undef elfhdr
|
||||
#undef elf_phdr
|
||||
#undef elf_note
|
||||
#undef elf_addr_t
|
||||
#define elfhdr elf32_hdr
|
||||
#define elf_phdr elf32_phdr
|
||||
#define elf_note elf32_note
|
||||
#define elf_addr_t Elf32_Off
|
||||
|
||||
#define elf_prstatus compat_elf_prstatus
|
||||
#define elf_prpsinfo compat_elf_prpsinfo
|
||||
|
||||
#define elf_core_copy_regs compat_elf_core_copy_regs
|
||||
static inline void compat_elf_core_copy_regs(compat_elf_gregset_t *elf_regs,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
PPC_ELF_CORE_COPY_REGS((*elf_regs), regs);
|
||||
}
|
||||
|
||||
#define elf_core_copy_task_regs compat_elf_core_copy_task_regs
|
||||
static int compat_elf_core_copy_task_regs(struct task_struct *tsk,
|
||||
compat_elf_gregset_t *elf_regs)
|
||||
{
|
||||
struct pt_regs *regs = tsk->thread.regs;
|
||||
if (regs)
|
||||
compat_elf_core_copy_regs(elf_regs, regs);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#include <linux/time.h>
|
||||
|
||||
#undef cputime_to_timeval
|
||||
#define cputime_to_timeval cputime_to_compat_timeval
|
||||
static __inline__ void
|
||||
cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
|
||||
{
|
||||
unsigned long jiffies = cputime_to_jiffies(cputime);
|
||||
value->tv_usec = (jiffies % HZ) * (1000000L / HZ);
|
||||
value->tv_sec = jiffies / HZ;
|
||||
}
|
||||
|
||||
#define init_elf_binfmt init_elf32_binfmt
|
||||
|
||||
#include "../../../fs/binfmt_elf.c"
|
|
@ -959,6 +959,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
|||
.icache_bsize = 32,
|
||||
.dcache_bsize = 32,
|
||||
.cpu_setup = __setup_cpu_603,
|
||||
.num_pmcs = 4,
|
||||
.oprofile_cpu_type = "ppc/e300",
|
||||
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||
.platform = "ppc603",
|
||||
},
|
||||
{ /* e300c4 (e300c1, plus one IU) */
|
||||
|
@ -971,6 +974,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
|||
.dcache_bsize = 32,
|
||||
.cpu_setup = __setup_cpu_603,
|
||||
.machine_check = machine_check_generic,
|
||||
.num_pmcs = 4,
|
||||
.oprofile_cpu_type = "ppc/e300",
|
||||
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||
.platform = "ppc603",
|
||||
},
|
||||
{ /* default match, we assume split I/D cache & TB (non-601)... */
|
||||
|
@ -1435,7 +1441,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
|||
.dcache_bsize = 32,
|
||||
.num_pmcs = 4,
|
||||
.oprofile_cpu_type = "ppc/e500",
|
||||
.oprofile_type = PPC_OPROFILE_BOOKE,
|
||||
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||
.machine_check = machine_check_e500,
|
||||
.platform = "ppc8540",
|
||||
},
|
||||
|
@ -1453,7 +1459,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
|||
.dcache_bsize = 32,
|
||||
.num_pmcs = 4,
|
||||
.oprofile_cpu_type = "ppc/e500",
|
||||
.oprofile_type = PPC_OPROFILE_BOOKE,
|
||||
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||
.machine_check = machine_check_e500,
|
||||
.platform = "ppc8548",
|
||||
},
|
||||
|
|
|
@ -36,7 +36,8 @@ static struct legacy_serial_info {
|
|||
static struct __initdata of_device_id parents[] = {
|
||||
{.type = "soc",},
|
||||
{.type = "tsi-bridge",},
|
||||
{.type = "opb", .compatible = "ibm,opb",},
|
||||
{.type = "opb", },
|
||||
{.compatible = "ibm,opb",},
|
||||
{.compatible = "simple-bus",},
|
||||
{.compatible = "wrs,epld-localbus",},
|
||||
};
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
|
||||
static void dummy_perf(struct pt_regs *regs)
|
||||
{
|
||||
#if defined(CONFIG_FSL_BOOKE) && !defined(CONFIG_E200)
|
||||
#if defined(CONFIG_FSL_EMB_PERFMON)
|
||||
mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE);
|
||||
#elif defined(CONFIG_PPC64) || defined(CONFIG_6xx)
|
||||
if (cur_cpu_spec->pmc_type == PPC_PMC_IBM)
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <linux/smp.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/regset.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/signal.h>
|
||||
|
@ -58,20 +60,38 @@
|
|||
#define PT_MAX_PUT_REG PT_CCR
|
||||
#endif
|
||||
|
||||
static unsigned long get_user_msr(struct task_struct *task)
|
||||
{
|
||||
return task->thread.regs->msr | task->thread.fpexc_mode;
|
||||
}
|
||||
|
||||
static int set_user_msr(struct task_struct *task, unsigned long msr)
|
||||
{
|
||||
task->thread.regs->msr &= ~MSR_DEBUGCHANGE;
|
||||
task->thread.regs->msr |= msr & MSR_DEBUGCHANGE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We prevent mucking around with the reserved area of trap
|
||||
* which are used internally by the kernel.
|
||||
*/
|
||||
static int set_user_trap(struct task_struct *task, unsigned long trap)
|
||||
{
|
||||
task->thread.regs->trap = trap & 0xfff0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get contents of register REGNO in task TASK.
|
||||
*/
|
||||
unsigned long ptrace_get_reg(struct task_struct *task, int regno)
|
||||
{
|
||||
unsigned long tmp = 0;
|
||||
|
||||
if (task->thread.regs == NULL)
|
||||
return -EIO;
|
||||
|
||||
if (regno == PT_MSR) {
|
||||
tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
|
||||
return tmp | task->thread.fpexc_mode;
|
||||
}
|
||||
if (regno == PT_MSR)
|
||||
return get_user_msr(task);
|
||||
|
||||
if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
|
||||
return ((unsigned long *)task->thread.regs)[regno];
|
||||
|
@ -87,40 +107,134 @@ int ptrace_put_reg(struct task_struct *task, int regno, unsigned long data)
|
|||
if (task->thread.regs == NULL)
|
||||
return -EIO;
|
||||
|
||||
if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) {
|
||||
if (regno == PT_MSR)
|
||||
data = (data & MSR_DEBUGCHANGE)
|
||||
| (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
|
||||
/* We prevent mucking around with the reserved area of trap
|
||||
* which are used internally by the kernel
|
||||
*/
|
||||
if (regno == PT_TRAP)
|
||||
data &= 0xfff0;
|
||||
if (regno == PT_MSR)
|
||||
return set_user_msr(task, data);
|
||||
if (regno == PT_TRAP)
|
||||
return set_user_trap(task, data);
|
||||
|
||||
if (regno <= PT_MAX_PUT_REG) {
|
||||
((unsigned long *)task->thread.regs)[regno] = data;
|
||||
return 0;
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
|
||||
static int get_fpregs(void __user *data, struct task_struct *task,
|
||||
int has_fpscr)
|
||||
static int gpr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
unsigned int count = has_fpscr ? 33 : 32;
|
||||
int ret;
|
||||
|
||||
if (copy_to_user(data, task->thread.fpr, count * sizeof(double)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
if (target->thread.regs == NULL)
|
||||
return -EIO;
|
||||
|
||||
CHECK_FULL_REGS(target->thread.regs);
|
||||
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
target->thread.regs,
|
||||
0, offsetof(struct pt_regs, msr));
|
||||
if (!ret) {
|
||||
unsigned long msr = get_user_msr(target);
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &msr,
|
||||
offsetof(struct pt_regs, msr),
|
||||
offsetof(struct pt_regs, msr) +
|
||||
sizeof(msr));
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
|
||||
offsetof(struct pt_regs, msr) + sizeof(long));
|
||||
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.regs->orig_gpr3,
|
||||
offsetof(struct pt_regs, orig_gpr3),
|
||||
sizeof(struct pt_regs));
|
||||
if (!ret)
|
||||
ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
sizeof(struct pt_regs), -1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_fpregs(void __user *data, struct task_struct *task,
|
||||
int has_fpscr)
|
||||
static int gpr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
unsigned int count = has_fpscr ? 33 : 32;
|
||||
unsigned long reg;
|
||||
int ret;
|
||||
|
||||
if (copy_from_user(task->thread.fpr, data, count * sizeof(double)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
if (target->thread.regs == NULL)
|
||||
return -EIO;
|
||||
|
||||
CHECK_FULL_REGS(target->thread.regs);
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
target->thread.regs,
|
||||
0, PT_MSR * sizeof(reg));
|
||||
|
||||
if (!ret && count > 0) {
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®,
|
||||
PT_MSR * sizeof(reg),
|
||||
(PT_MSR + 1) * sizeof(reg));
|
||||
if (!ret)
|
||||
ret = set_user_msr(target, reg);
|
||||
}
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct pt_regs, orig_gpr3) !=
|
||||
offsetof(struct pt_regs, msr) + sizeof(long));
|
||||
|
||||
if (!ret)
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.regs->orig_gpr3,
|
||||
PT_ORIG_R3 * sizeof(reg),
|
||||
(PT_MAX_PUT_REG + 1) * sizeof(reg));
|
||||
|
||||
if (PT_MAX_PUT_REG + 1 < PT_TRAP && !ret)
|
||||
ret = user_regset_copyin_ignore(
|
||||
&pos, &count, &kbuf, &ubuf,
|
||||
(PT_MAX_PUT_REG + 1) * sizeof(reg),
|
||||
PT_TRAP * sizeof(reg));
|
||||
|
||||
if (!ret && count > 0) {
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®,
|
||||
PT_TRAP * sizeof(reg),
|
||||
(PT_TRAP + 1) * sizeof(reg));
|
||||
if (!ret)
|
||||
ret = set_user_trap(target, reg);
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = user_regset_copyin_ignore(
|
||||
&pos, &count, &kbuf, &ubuf,
|
||||
(PT_TRAP + 1) * sizeof(reg), -1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fpr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
flush_fp_to_thread(target);
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
|
||||
offsetof(struct thread_struct, fpr[32]));
|
||||
|
||||
return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.fpr, 0, -1);
|
||||
}
|
||||
|
||||
static int fpr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
flush_fp_to_thread(target);
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct thread_struct, fpscr) !=
|
||||
offsetof(struct thread_struct, fpr[32]));
|
||||
|
||||
return user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.fpr, 0, -1);
|
||||
}
|
||||
|
||||
|
||||
|
@ -138,56 +252,74 @@ static int set_fpregs(void __user *data, struct task_struct *task,
|
|||
* (combined (32- and 64-bit) gdb.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get contents of AltiVec register state in task TASK
|
||||
*/
|
||||
static int get_vrregs(unsigned long __user *data, struct task_struct *task)
|
||||
static int vr_active(struct task_struct *target,
|
||||
const struct user_regset *regset)
|
||||
{
|
||||
unsigned long regsize;
|
||||
|
||||
/* copy AltiVec registers VR[0] .. VR[31] */
|
||||
regsize = 32 * sizeof(vector128);
|
||||
if (copy_to_user(data, task->thread.vr, regsize))
|
||||
return -EFAULT;
|
||||
data += (regsize / sizeof(unsigned long));
|
||||
|
||||
/* copy VSCR */
|
||||
regsize = 1 * sizeof(vector128);
|
||||
if (copy_to_user(data, &task->thread.vscr, regsize))
|
||||
return -EFAULT;
|
||||
data += (regsize / sizeof(unsigned long));
|
||||
|
||||
/* copy VRSAVE */
|
||||
if (put_user(task->thread.vrsave, (u32 __user *)data))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
flush_altivec_to_thread(target);
|
||||
return target->thread.used_vr ? regset->n : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write contents of AltiVec register state into task TASK.
|
||||
*/
|
||||
static int set_vrregs(struct task_struct *task, unsigned long __user *data)
|
||||
static int vr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
unsigned long regsize;
|
||||
int ret;
|
||||
|
||||
/* copy AltiVec registers VR[0] .. VR[31] */
|
||||
regsize = 32 * sizeof(vector128);
|
||||
if (copy_from_user(task->thread.vr, data, regsize))
|
||||
return -EFAULT;
|
||||
data += (regsize / sizeof(unsigned long));
|
||||
flush_altivec_to_thread(target);
|
||||
|
||||
/* copy VSCR */
|
||||
regsize = 1 * sizeof(vector128);
|
||||
if (copy_from_user(&task->thread.vscr, data, regsize))
|
||||
return -EFAULT;
|
||||
data += (regsize / sizeof(unsigned long));
|
||||
BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
|
||||
offsetof(struct thread_struct, vr[32]));
|
||||
|
||||
/* copy VRSAVE */
|
||||
if (get_user(task->thread.vrsave, (u32 __user *)data))
|
||||
return -EFAULT;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.vr, 0,
|
||||
33 * sizeof(vector128));
|
||||
if (!ret) {
|
||||
/*
|
||||
* Copy out only the low-order word of vrsave.
|
||||
*/
|
||||
union {
|
||||
elf_vrreg_t reg;
|
||||
u32 word;
|
||||
} vrsave;
|
||||
memset(&vrsave, 0, sizeof(vrsave));
|
||||
vrsave.word = target->thread.vrsave;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, &vrsave,
|
||||
33 * sizeof(vector128), -1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int vr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
flush_altivec_to_thread(target);
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
|
||||
offsetof(struct thread_struct, vr[32]));
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.vr, 0, 33 * sizeof(vector128));
|
||||
if (!ret && count > 0) {
|
||||
/*
|
||||
* We use only the first word of vrsave.
|
||||
*/
|
||||
union {
|
||||
elf_vrreg_t reg;
|
||||
u32 word;
|
||||
} vrsave;
|
||||
memset(&vrsave, 0, sizeof(vrsave));
|
||||
vrsave.word = target->thread.vrsave;
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &vrsave,
|
||||
33 * sizeof(vector128), -1);
|
||||
if (!ret)
|
||||
target->thread.vrsave = vrsave.word;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_ALTIVEC */
|
||||
|
||||
|
@ -203,59 +335,275 @@ static int set_vrregs(struct task_struct *task, unsigned long __user *data)
|
|||
* }
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get contents of SPE register state in task TASK.
|
||||
*/
|
||||
static int get_evrregs(unsigned long *data, struct task_struct *task)
|
||||
static int evr_active(struct task_struct *target,
|
||||
const struct user_regset *regset)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, data, 35 * sizeof(unsigned long)))
|
||||
return -EFAULT;
|
||||
|
||||
/* copy SPEFSCR */
|
||||
if (__put_user(task->thread.spefscr, &data[34]))
|
||||
return -EFAULT;
|
||||
|
||||
/* copy SPE registers EVR[0] .. EVR[31] */
|
||||
for (i = 0; i < 32; i++, data++)
|
||||
if (__put_user(task->thread.evr[i], data))
|
||||
return -EFAULT;
|
||||
|
||||
/* copy ACC */
|
||||
if (__put_user64(task->thread.acc, (unsigned long long *)data))
|
||||
return -EFAULT;
|
||||
|
||||
return 0;
|
||||
flush_spe_to_thread(target);
|
||||
return target->thread.used_spe ? regset->n : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write contents of SPE register state into task TASK.
|
||||
*/
|
||||
static int set_evrregs(struct task_struct *task, unsigned long *data)
|
||||
static int evr_get(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
|
||||
return -EFAULT;
|
||||
flush_spe_to_thread(target);
|
||||
|
||||
/* copy SPEFSCR */
|
||||
if (__get_user(task->thread.spefscr, &data[34]))
|
||||
return -EFAULT;
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.evr,
|
||||
0, sizeof(target->thread.evr));
|
||||
|
||||
/* copy SPE registers EVR[0] .. EVR[31] */
|
||||
for (i = 0; i < 32; i++, data++)
|
||||
if (__get_user(task->thread.evr[i], data))
|
||||
return -EFAULT;
|
||||
/* copy ACC */
|
||||
if (__get_user64(task->thread.acc, (unsigned long long*)data))
|
||||
return -EFAULT;
|
||||
BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
|
||||
offsetof(struct thread_struct, spefscr));
|
||||
|
||||
return 0;
|
||||
if (!ret)
|
||||
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.acc,
|
||||
sizeof(target->thread.evr), -1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int evr_set(struct task_struct *target, const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
int ret;
|
||||
|
||||
flush_spe_to_thread(target);
|
||||
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.evr,
|
||||
0, sizeof(target->thread.evr));
|
||||
|
||||
BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
|
||||
offsetof(struct thread_struct, spefscr));
|
||||
|
||||
if (!ret)
|
||||
ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf,
|
||||
&target->thread.acc,
|
||||
sizeof(target->thread.evr), -1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_SPE */
|
||||
|
||||
|
||||
/*
|
||||
* These are our native regset flavors.
|
||||
*/
|
||||
enum powerpc_regset {
|
||||
REGSET_GPR,
|
||||
REGSET_FPR,
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
REGSET_VMX,
|
||||
#endif
|
||||
#ifdef CONFIG_SPE
|
||||
REGSET_SPE,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct user_regset native_regsets[] = {
|
||||
[REGSET_GPR] = {
|
||||
.core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
|
||||
.size = sizeof(long), .align = sizeof(long),
|
||||
.get = gpr_get, .set = gpr_set
|
||||
},
|
||||
[REGSET_FPR] = {
|
||||
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
|
||||
.size = sizeof(double), .align = sizeof(double),
|
||||
.get = fpr_get, .set = fpr_set
|
||||
},
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
[REGSET_VMX] = {
|
||||
.core_note_type = NT_PPC_VMX, .n = 34,
|
||||
.size = sizeof(vector128), .align = sizeof(vector128),
|
||||
.active = vr_active, .get = vr_get, .set = vr_set
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_SPE
|
||||
[REGSET_SPE] = {
|
||||
.n = 35,
|
||||
.size = sizeof(u32), .align = sizeof(u32),
|
||||
.active = evr_active, .get = evr_get, .set = evr_set
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_ppc_native_view = {
|
||||
.name = UTS_MACHINE, .e_machine = ELF_ARCH, .ei_osabi = ELF_OSABI,
|
||||
.regsets = native_regsets, .n = ARRAY_SIZE(native_regsets)
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
#include <linux/compat.h>
|
||||
|
||||
static int gpr32_get(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
void *kbuf, void __user *ubuf)
|
||||
{
|
||||
const unsigned long *regs = &target->thread.regs->gpr[0];
|
||||
compat_ulong_t *k = kbuf;
|
||||
compat_ulong_t __user *u = ubuf;
|
||||
compat_ulong_t reg;
|
||||
|
||||
if (target->thread.regs == NULL)
|
||||
return -EIO;
|
||||
|
||||
CHECK_FULL_REGS(target->thread.regs);
|
||||
|
||||
pos /= sizeof(reg);
|
||||
count /= sizeof(reg);
|
||||
|
||||
if (kbuf)
|
||||
for (; count > 0 && pos < PT_MSR; --count)
|
||||
*k++ = regs[pos++];
|
||||
else
|
||||
for (; count > 0 && pos < PT_MSR; --count)
|
||||
if (__put_user((compat_ulong_t) regs[pos++], u++))
|
||||
return -EFAULT;
|
||||
|
||||
if (count > 0 && pos == PT_MSR) {
|
||||
reg = get_user_msr(target);
|
||||
if (kbuf)
|
||||
*k++ = reg;
|
||||
else if (__put_user(reg, u++))
|
||||
return -EFAULT;
|
||||
++pos;
|
||||
--count;
|
||||
}
|
||||
|
||||
if (kbuf)
|
||||
for (; count > 0 && pos < PT_REGS_COUNT; --count)
|
||||
*k++ = regs[pos++];
|
||||
else
|
||||
for (; count > 0 && pos < PT_REGS_COUNT; --count)
|
||||
if (__put_user((compat_ulong_t) regs[pos++], u++))
|
||||
return -EFAULT;
|
||||
|
||||
kbuf = k;
|
||||
ubuf = u;
|
||||
pos *= sizeof(reg);
|
||||
count *= sizeof(reg);
|
||||
return user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
|
||||
PT_REGS_COUNT * sizeof(reg), -1);
|
||||
}
|
||||
|
||||
static int gpr32_set(struct task_struct *target,
|
||||
const struct user_regset *regset,
|
||||
unsigned int pos, unsigned int count,
|
||||
const void *kbuf, const void __user *ubuf)
|
||||
{
|
||||
unsigned long *regs = &target->thread.regs->gpr[0];
|
||||
const compat_ulong_t *k = kbuf;
|
||||
const compat_ulong_t __user *u = ubuf;
|
||||
compat_ulong_t reg;
|
||||
|
||||
if (target->thread.regs == NULL)
|
||||
return -EIO;
|
||||
|
||||
CHECK_FULL_REGS(target->thread.regs);
|
||||
|
||||
pos /= sizeof(reg);
|
||||
count /= sizeof(reg);
|
||||
|
||||
if (kbuf)
|
||||
for (; count > 0 && pos < PT_MSR; --count)
|
||||
regs[pos++] = *k++;
|
||||
else
|
||||
for (; count > 0 && pos < PT_MSR; --count) {
|
||||
if (__get_user(reg, u++))
|
||||
return -EFAULT;
|
||||
regs[pos++] = reg;
|
||||
}
|
||||
|
||||
|
||||
if (count > 0 && pos == PT_MSR) {
|
||||
if (kbuf)
|
||||
reg = *k++;
|
||||
else if (__get_user(reg, u++))
|
||||
return -EFAULT;
|
||||
set_user_msr(target, reg);
|
||||
++pos;
|
||||
--count;
|
||||
}
|
||||
|
||||
if (kbuf)
|
||||
for (; count > 0 && pos <= PT_MAX_PUT_REG; --count)
|
||||
regs[pos++] = *k++;
|
||||
else
|
||||
for (; count > 0 && pos <= PT_MAX_PUT_REG; --count) {
|
||||
if (__get_user(reg, u++))
|
||||
return -EFAULT;
|
||||
regs[pos++] = reg;
|
||||
}
|
||||
|
||||
if (count > 0 && pos == PT_TRAP) {
|
||||
if (kbuf)
|
||||
reg = *k++;
|
||||
else if (__get_user(reg, u++))
|
||||
return -EFAULT;
|
||||
set_user_trap(target, reg);
|
||||
++pos;
|
||||
--count;
|
||||
}
|
||||
|
||||
kbuf = k;
|
||||
ubuf = u;
|
||||
pos *= sizeof(reg);
|
||||
count *= sizeof(reg);
|
||||
return user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
|
||||
(PT_TRAP + 1) * sizeof(reg), -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* These are the regset flavors matching the CONFIG_PPC32 native set.
|
||||
*/
|
||||
static const struct user_regset compat_regsets[] = {
|
||||
[REGSET_GPR] = {
|
||||
.core_note_type = NT_PRSTATUS, .n = ELF_NGREG,
|
||||
.size = sizeof(compat_long_t), .align = sizeof(compat_long_t),
|
||||
.get = gpr32_get, .set = gpr32_set
|
||||
},
|
||||
[REGSET_FPR] = {
|
||||
.core_note_type = NT_PRFPREG, .n = ELF_NFPREG,
|
||||
.size = sizeof(double), .align = sizeof(double),
|
||||
.get = fpr_get, .set = fpr_set
|
||||
},
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
[REGSET_VMX] = {
|
||||
.core_note_type = NT_PPC_VMX, .n = 34,
|
||||
.size = sizeof(vector128), .align = sizeof(vector128),
|
||||
.active = vr_active, .get = vr_get, .set = vr_set
|
||||
},
|
||||
#endif
|
||||
#ifdef CONFIG_SPE
|
||||
[REGSET_SPE] = {
|
||||
.core_note_type = NT_PPC_SPE, .n = 35,
|
||||
.size = sizeof(u32), .align = sizeof(u32),
|
||||
.active = evr_active, .get = evr_get, .set = evr_set
|
||||
},
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct user_regset_view user_ppc_compat_view = {
|
||||
.name = "ppc", .e_machine = EM_PPC, .ei_osabi = ELF_OSABI,
|
||||
.regsets = compat_regsets, .n = ARRAY_SIZE(compat_regsets)
|
||||
};
|
||||
#endif /* CONFIG_PPC64 */
|
||||
|
||||
const struct user_regset_view *task_user_regset_view(struct task_struct *task)
|
||||
{
|
||||
#ifdef CONFIG_PPC64
|
||||
if (test_tsk_thread_flag(task, TIF_32BIT))
|
||||
return &user_ppc_compat_view;
|
||||
#endif
|
||||
return &user_ppc_native_view;
|
||||
}
|
||||
|
||||
|
||||
void user_enable_single_step(struct task_struct *task)
|
||||
{
|
||||
struct pt_regs *regs = task->thread.regs;
|
||||
|
@ -323,55 +671,29 @@ void ptrace_disable(struct task_struct *child)
|
|||
static long arch_ptrace_old(struct task_struct *child, long request, long addr,
|
||||
long data)
|
||||
{
|
||||
int ret = -EPERM;
|
||||
switch (request) {
|
||||
case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
|
||||
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||
REGSET_GPR, 0, 32 * sizeof(long),
|
||||
(void __user *) data);
|
||||
|
||||
switch(request) {
|
||||
case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
|
||||
int i;
|
||||
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
|
||||
unsigned long __user *tmp = (unsigned long __user *)addr;
|
||||
case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
|
||||
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||
REGSET_GPR, 0, 32 * sizeof(long),
|
||||
(const void __user *) data);
|
||||
|
||||
CHECK_FULL_REGS(child->thread.regs);
|
||||
for (i = 0; i < 32; i++) {
|
||||
ret = put_user(*reg, tmp);
|
||||
if (ret)
|
||||
break;
|
||||
reg++;
|
||||
tmp++;
|
||||
}
|
||||
break;
|
||||
case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
|
||||
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||
REGSET_FPR, 0, 32 * sizeof(double),
|
||||
(void __user *) data);
|
||||
|
||||
case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */
|
||||
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||
REGSET_FPR, 0, 32 * sizeof(double),
|
||||
(const void __user *) data);
|
||||
}
|
||||
|
||||
case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
|
||||
int i;
|
||||
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
|
||||
unsigned long __user *tmp = (unsigned long __user *)addr;
|
||||
|
||||
CHECK_FULL_REGS(child->thread.regs);
|
||||
for (i = 0; i < 32; i++) {
|
||||
ret = get_user(*reg, tmp);
|
||||
if (ret)
|
||||
break;
|
||||
reg++;
|
||||
tmp++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PPC_PTRACE_GETFPREGS: { /* Get FPRs 0 - 31. */
|
||||
flush_fp_to_thread(child);
|
||||
ret = get_fpregs((void __user *)addr, child, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
case PPC_PTRACE_SETFPREGS: { /* Get FPRs 0 - 31. */
|
||||
flush_fp_to_thread(child);
|
||||
ret = set_fpregs((void __user *)addr, child, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return ret;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
||||
|
@ -379,12 +701,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
int ret = -EPERM;
|
||||
|
||||
switch (request) {
|
||||
/* when I and D space are separate, these will need to be fixed. */
|
||||
case PTRACE_PEEKTEXT: /* read word at location addr. */
|
||||
case PTRACE_PEEKDATA:
|
||||
ret = generic_ptrace_peekdata(child, addr, data);
|
||||
break;
|
||||
|
||||
/* read the word at location addr in the USER area. */
|
||||
case PTRACE_PEEKUSR: {
|
||||
unsigned long index, tmp;
|
||||
|
@ -412,12 +728,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
break;
|
||||
}
|
||||
|
||||
/* If I and D space are separate, this will have to be fixed. */
|
||||
case PTRACE_POKETEXT: /* write the word at location addr. */
|
||||
case PTRACE_POKEDATA:
|
||||
ret = generic_ptrace_pokedata(child, addr, data);
|
||||
break;
|
||||
|
||||
/* write the word at location addr in the USER area */
|
||||
case PTRACE_POKEUSR: {
|
||||
unsigned long index;
|
||||
|
@ -462,85 +772,60 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||
#ifdef CONFIG_PPC64
|
||||
case PTRACE_GETREGS64:
|
||||
#endif
|
||||
case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
|
||||
int ui;
|
||||
if (!access_ok(VERIFY_WRITE, (void __user *)data,
|
||||
sizeof(struct pt_regs))) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
CHECK_FULL_REGS(child->thread.regs);
|
||||
ret = 0;
|
||||
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
|
||||
ret |= __put_user(ptrace_get_reg(child, ui),
|
||||
(unsigned long __user *) data);
|
||||
data += sizeof(long);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTRACE_GETREGS: /* Get all pt_regs from the child. */
|
||||
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||
REGSET_GPR,
|
||||
0, sizeof(struct pt_regs),
|
||||
(void __user *) data);
|
||||
|
||||
#ifdef CONFIG_PPC64
|
||||
case PTRACE_SETREGS64:
|
||||
#endif
|
||||
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
|
||||
unsigned long tmp;
|
||||
int ui;
|
||||
if (!access_ok(VERIFY_READ, (void __user *)data,
|
||||
sizeof(struct pt_regs))) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
CHECK_FULL_REGS(child->thread.regs);
|
||||
ret = 0;
|
||||
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
|
||||
ret = __get_user(tmp, (unsigned long __user *) data);
|
||||
if (ret)
|
||||
break;
|
||||
ptrace_put_reg(child, ui, tmp);
|
||||
data += sizeof(long);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTRACE_SETREGS: /* Set all gp regs in the child. */
|
||||
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||
REGSET_GPR,
|
||||
0, sizeof(struct pt_regs),
|
||||
(const void __user *) data);
|
||||
|
||||
case PTRACE_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
|
||||
flush_fp_to_thread(child);
|
||||
ret = get_fpregs((void __user *)data, child, 1);
|
||||
break;
|
||||
}
|
||||
case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */
|
||||
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||
REGSET_FPR,
|
||||
0, sizeof(elf_fpregset_t),
|
||||
(void __user *) data);
|
||||
|
||||
case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
|
||||
flush_fp_to_thread(child);
|
||||
ret = set_fpregs((void __user *)data, child, 1);
|
||||
break;
|
||||
}
|
||||
case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */
|
||||
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||
REGSET_FPR,
|
||||
0, sizeof(elf_fpregset_t),
|
||||
(const void __user *) data);
|
||||
|
||||
#ifdef CONFIG_ALTIVEC
|
||||
case PTRACE_GETVRREGS:
|
||||
/* Get the child altivec register state. */
|
||||
flush_altivec_to_thread(child);
|
||||
ret = get_vrregs((unsigned long __user *)data, child);
|
||||
break;
|
||||
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||
REGSET_VMX,
|
||||
0, (33 * sizeof(vector128) +
|
||||
sizeof(u32)),
|
||||
(void __user *) data);
|
||||
|
||||
case PTRACE_SETVRREGS:
|
||||
/* Set the child altivec register state. */
|
||||
flush_altivec_to_thread(child);
|
||||
ret = set_vrregs(child, (unsigned long __user *)data);
|
||||
break;
|
||||
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||
REGSET_VMX,
|
||||
0, (33 * sizeof(vector128) +
|
||||
sizeof(u32)),
|
||||
(const void __user *) data);
|
||||
#endif
|
||||
#ifdef CONFIG_SPE
|
||||
case PTRACE_GETEVRREGS:
|
||||
/* Get the child spe register state. */
|
||||
flush_spe_to_thread(child);
|
||||
ret = get_evrregs((unsigned long __user *)data, child);
|
||||
break;
|
||||
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||
REGSET_SPE, 0, 35 * sizeof(u32),
|
||||
(void __user *) data);
|
||||
|
||||
case PTRACE_SETEVRREGS:
|
||||
/* Set the child spe register state. */
|
||||
/* this is to clear the MSR_SPE bit to force a reload
|
||||
* of register state from memory */
|
||||
flush_spe_to_thread(child);
|
||||
ret = set_evrregs(child, (unsigned long __user *)data);
|
||||
break;
|
||||
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||
REGSET_SPE, 0, 35 * sizeof(u32),
|
||||
(const void __user *) data);
|
||||
#endif
|
||||
|
||||
/* Old reverse args ptrace callss */
|
||||
|
|
|
@ -24,9 +24,11 @@
|
|||
#include <linux/smp_lock.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/regset.h>
|
||||
#include <linux/user.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/page.h>
|
||||
|
@ -45,87 +47,31 @@
|
|||
static long compat_ptrace_old(struct task_struct *child, long request,
|
||||
long addr, long data)
|
||||
{
|
||||
int ret = -EPERM;
|
||||
switch (request) {
|
||||
case PPC_PTRACE_GETREGS: /* Get GPRs 0 - 31. */
|
||||
return copy_regset_to_user(child,
|
||||
task_user_regset_view(current), 0,
|
||||
0, 32 * sizeof(compat_long_t),
|
||||
compat_ptr(data));
|
||||
|
||||
switch(request) {
|
||||
case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
|
||||
int i;
|
||||
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
|
||||
unsigned int __user *tmp = (unsigned int __user *)addr;
|
||||
|
||||
CHECK_FULL_REGS(child->thread.regs);
|
||||
for (i = 0; i < 32; i++) {
|
||||
ret = put_user(*reg, tmp);
|
||||
if (ret)
|
||||
break;
|
||||
reg++;
|
||||
tmp++;
|
||||
}
|
||||
break;
|
||||
case PPC_PTRACE_SETREGS: /* Set GPRs 0 - 31. */
|
||||
return copy_regset_from_user(child,
|
||||
task_user_regset_view(current), 0,
|
||||
0, 32 * sizeof(compat_long_t),
|
||||
compat_ptr(data));
|
||||
}
|
||||
|
||||
case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
|
||||
int i;
|
||||
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
|
||||
unsigned int __user *tmp = (unsigned int __user *)addr;
|
||||
|
||||
CHECK_FULL_REGS(child->thread.regs);
|
||||
for (i = 0; i < 32; i++) {
|
||||
ret = get_user(*reg, tmp);
|
||||
if (ret)
|
||||
break;
|
||||
reg++;
|
||||
tmp++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
return ret;
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
long compat_sys_ptrace(int request, int pid, unsigned long addr,
|
||||
unsigned long data)
|
||||
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||
compat_ulong_t caddr, compat_ulong_t cdata)
|
||||
{
|
||||
struct task_struct *child;
|
||||
unsigned long addr = caddr;
|
||||
unsigned long data = cdata;
|
||||
int ret;
|
||||
|
||||
lock_kernel();
|
||||
if (request == PTRACE_TRACEME) {
|
||||
ret = ptrace_traceme();
|
||||
goto out;
|
||||
}
|
||||
|
||||
child = ptrace_get_task_struct(pid);
|
||||
if (IS_ERR(child)) {
|
||||
ret = PTR_ERR(child);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (request == PTRACE_ATTACH) {
|
||||
ret = ptrace_attach(child);
|
||||
goto out_tsk;
|
||||
}
|
||||
|
||||
ret = ptrace_check_attach(child, request == PTRACE_KILL);
|
||||
if (ret < 0)
|
||||
goto out_tsk;
|
||||
|
||||
switch (request) {
|
||||
/* when I and D space are separate, these will need to be fixed. */
|
||||
case PTRACE_PEEKTEXT: /* read word at location addr. */
|
||||
case PTRACE_PEEKDATA: {
|
||||
unsigned int tmp;
|
||||
int copied;
|
||||
|
||||
copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
|
||||
ret = -EIO;
|
||||
if (copied != sizeof(tmp))
|
||||
break;
|
||||
ret = put_user(tmp, (u32 __user *)data);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read 4 bytes of the other process' storage
|
||||
* data is a pointer specifying where the user wants the
|
||||
|
@ -225,19 +171,6 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
|
|||
break;
|
||||
}
|
||||
|
||||
/* If I and D space are separate, this will have to be fixed. */
|
||||
case PTRACE_POKETEXT: /* write the word at location addr. */
|
||||
case PTRACE_POKEDATA: {
|
||||
unsigned int tmp;
|
||||
tmp = data;
|
||||
ret = 0;
|
||||
if (access_process_vm(child, addr, &tmp, sizeof(tmp), 1)
|
||||
== sizeof(tmp))
|
||||
break;
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write 4 bytes into the other process' storage
|
||||
* data is the 4 bytes that the user wants written
|
||||
|
@ -337,46 +270,17 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
|
|||
break;
|
||||
}
|
||||
|
||||
case PTRACE_GETEVENTMSG:
|
||||
ret = put_user(child->ptrace_message, (unsigned int __user *) data);
|
||||
break;
|
||||
case PTRACE_GETREGS: /* Get all pt_regs from the child. */
|
||||
return copy_regset_to_user(
|
||||
child, task_user_regset_view(current), 0,
|
||||
0, PT_REGS_COUNT * sizeof(compat_long_t),
|
||||
compat_ptr(data));
|
||||
|
||||
case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
|
||||
int ui;
|
||||
if (!access_ok(VERIFY_WRITE, (void __user *)data,
|
||||
PT_REGS_COUNT * sizeof(int))) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
CHECK_FULL_REGS(child->thread.regs);
|
||||
ret = 0;
|
||||
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
|
||||
ret |= __put_user(ptrace_get_reg(child, ui),
|
||||
(unsigned int __user *) data);
|
||||
data += sizeof(int);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
|
||||
unsigned long tmp;
|
||||
int ui;
|
||||
if (!access_ok(VERIFY_READ, (void __user *)data,
|
||||
PT_REGS_COUNT * sizeof(int))) {
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
CHECK_FULL_REGS(child->thread.regs);
|
||||
ret = 0;
|
||||
for (ui = 0; ui < PT_REGS_COUNT; ui ++) {
|
||||
ret = __get_user(tmp, (unsigned int __user *) data);
|
||||
if (ret)
|
||||
break;
|
||||
ptrace_put_reg(child, ui, tmp);
|
||||
data += sizeof(int);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PTRACE_SETREGS: /* Set all gp regs in the child. */
|
||||
return copy_regset_from_user(
|
||||
child, task_user_regset_view(current), 0,
|
||||
0, PT_REGS_COUNT * sizeof(compat_long_t),
|
||||
compat_ptr(data));
|
||||
|
||||
case PTRACE_GETFPREGS:
|
||||
case PTRACE_SETFPREGS:
|
||||
|
@ -402,12 +306,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
|
|||
break;
|
||||
|
||||
default:
|
||||
ret = ptrace_request(child, request, addr, data);
|
||||
ret = compat_ptrace_request(child, request, addr, data);
|
||||
break;
|
||||
}
|
||||
out_tsk:
|
||||
put_task_struct(child);
|
||||
out:
|
||||
unlock_kernel();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
#endif
|
||||
#include <asm/kexec.h>
|
||||
|
||||
#ifdef CONFIG_DEBUGGER
|
||||
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
|
||||
int (*__debugger)(struct pt_regs *regs);
|
||||
int (*__debugger_ipi)(struct pt_regs *regs);
|
||||
int (*__debugger_bpt)(struct pt_regs *regs);
|
||||
|
|
|
@ -176,7 +176,7 @@ static void __devinit vio_dev_release(struct device *dev)
|
|||
* Returns a pointer to the created vio_dev or NULL if node has
|
||||
* NULL device_type or compatible fields.
|
||||
*/
|
||||
struct vio_dev * __devinit vio_register_device_node(struct device_node *of_node)
|
||||
struct vio_dev *vio_register_device_node(struct device_node *of_node)
|
||||
{
|
||||
struct vio_dev *viodev;
|
||||
const unsigned int *unit_address;
|
||||
|
|
|
@ -485,7 +485,12 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
|
|||
*/
|
||||
_tlbie(address, 0 /* 8xx doesn't care about PID */);
|
||||
#endif
|
||||
if (!PageReserved(page)
|
||||
/* The _PAGE_USER test should really be _PAGE_EXEC, but
|
||||
* older glibc versions execute some code from no-exec
|
||||
* pages, which for now we are supporting. If exec-only
|
||||
* pages are ever implemented, this will have to change.
|
||||
*/
|
||||
if (!PageReserved(page) && (pte_val(pte) & _PAGE_USER)
|
||||
&& !test_bit(PG_arch_1, &page->flags)) {
|
||||
if (vma->vm_mm == current->active_mm) {
|
||||
__flush_dcache_icache((void *) address);
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
static int numa_enabled = 1;
|
||||
|
||||
static char *cmdline __initdata;
|
||||
|
||||
static int numa_debug;
|
||||
#define dbg(args...) if (numa_debug) { printk(KERN_INFO args); }
|
||||
|
||||
|
@ -39,6 +41,53 @@ static bootmem_data_t __initdata plat_node_bdata[MAX_NUMNODES];
|
|||
static int min_common_depth;
|
||||
static int n_mem_addr_cells, n_mem_size_cells;
|
||||
|
||||
static int __cpuinit fake_numa_create_new_node(unsigned long end_pfn,
|
||||
unsigned int *nid)
|
||||
{
|
||||
unsigned long long mem;
|
||||
char *p = cmdline;
|
||||
static unsigned int fake_nid;
|
||||
static unsigned long long curr_boundary;
|
||||
|
||||
/*
|
||||
* Modify node id, iff we started creating NUMA nodes
|
||||
* We want to continue from where we left of the last time
|
||||
*/
|
||||
if (fake_nid)
|
||||
*nid = fake_nid;
|
||||
/*
|
||||
* In case there are no more arguments to parse, the
|
||||
* node_id should be the same as the last fake node id
|
||||
* (we've handled this above).
|
||||
*/
|
||||
if (!p)
|
||||
return 0;
|
||||
|
||||
mem = memparse(p, &p);
|
||||
if (!mem)
|
||||
return 0;
|
||||
|
||||
if (mem < curr_boundary)
|
||||
return 0;
|
||||
|
||||
curr_boundary = mem;
|
||||
|
||||
if ((end_pfn << PAGE_SHIFT) > mem) {
|
||||
/*
|
||||
* Skip commas and spaces
|
||||
*/
|
||||
while (*p == ',' || *p == ' ' || *p == '\t')
|
||||
p++;
|
||||
|
||||
cmdline = p;
|
||||
fake_nid++;
|
||||
*nid = fake_nid;
|
||||
dbg("created new fake_node with id %d\n", fake_nid);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __cpuinit map_cpu_to_node(int cpu, int node)
|
||||
{
|
||||
numa_cpu_lookup_table[cpu] = node;
|
||||
|
@ -344,6 +393,9 @@ static void __init parse_drconf_memory(struct device_node *memory)
|
|||
if (nid == 0xffff || nid >= MAX_NUMNODES)
|
||||
nid = default_nid;
|
||||
}
|
||||
|
||||
fake_numa_create_new_node(((start + lmb_size) >> PAGE_SHIFT),
|
||||
&nid);
|
||||
node_set_online(nid);
|
||||
|
||||
size = numa_enforce_memory_limit(start, lmb_size);
|
||||
|
@ -429,6 +481,8 @@ new_range:
|
|||
nid = of_node_to_nid_single(memory);
|
||||
if (nid < 0)
|
||||
nid = default_nid;
|
||||
|
||||
fake_numa_create_new_node(((start + size) >> PAGE_SHIFT), &nid);
|
||||
node_set_online(nid);
|
||||
|
||||
if (!(size = numa_enforce_memory_limit(start, size))) {
|
||||
|
@ -461,7 +515,7 @@ static void __init setup_nonnuma(void)
|
|||
unsigned long top_of_ram = lmb_end_of_DRAM();
|
||||
unsigned long total_ram = lmb_phys_mem_size();
|
||||
unsigned long start_pfn, end_pfn;
|
||||
unsigned int i;
|
||||
unsigned int i, nid = 0;
|
||||
|
||||
printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
|
||||
top_of_ram, total_ram);
|
||||
|
@ -471,9 +525,11 @@ static void __init setup_nonnuma(void)
|
|||
for (i = 0; i < lmb.memory.cnt; ++i) {
|
||||
start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
|
||||
end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
|
||||
add_active_range(0, start_pfn, end_pfn);
|
||||
|
||||
fake_numa_create_new_node(end_pfn, &nid);
|
||||
add_active_range(nid, start_pfn, end_pfn);
|
||||
node_set_online(nid);
|
||||
}
|
||||
node_set_online(0);
|
||||
}
|
||||
|
||||
void __init dump_numa_cpu_topology(void)
|
||||
|
@ -702,6 +758,10 @@ static int __init early_numa(char *p)
|
|||
if (strstr(p, "debug"))
|
||||
numa_debug = 1;
|
||||
|
||||
p = strstr(p, "fake=");
|
||||
if (p)
|
||||
cmdline = p + strlen("fake=");
|
||||
|
||||
return 0;
|
||||
}
|
||||
early_param("numa", early_numa);
|
||||
|
|
|
@ -15,5 +15,5 @@ oprofile-$(CONFIG_OPROFILE_CELL) += op_model_cell.o \
|
|||
cell/spu_profiler.o cell/vma_map.o \
|
||||
cell/spu_task_sync.o
|
||||
oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.o
|
||||
oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
|
||||
oprofile-$(CONFIG_FSL_EMB_PERFMON) += op_model_fsl_emb.o
|
||||
oprofile-$(CONFIG_6xx) += op_model_7450.o
|
||||
|
|
|
@ -202,9 +202,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
|
|||
model = &op_model_7450;
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_FSL_BOOKE
|
||||
case PPC_OPROFILE_BOOKE:
|
||||
model = &op_model_fsl_booke;
|
||||
#if defined(CONFIG_FSL_EMB_PERFMON)
|
||||
case PPC_OPROFILE_FSL_EMB:
|
||||
model = &op_model_fsl_emb;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
/*
|
||||
* arch/powerpc/oprofile/op_model_fsl_booke.c
|
||||
*
|
||||
* Freescale Book-E oprofile support, based on ppc64 oprofile support
|
||||
* Freescale Embedded oprofile support, based on ppc64 oprofile support
|
||||
* Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
|
||||
*
|
||||
* Copyright (c) 2004 Freescale Semiconductor, Inc
|
||||
|
@ -22,7 +20,7 @@
|
|||
#include <asm/system.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/cputable.h>
|
||||
#include <asm/reg_booke.h>
|
||||
#include <asm/reg_fsl_emb.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pmc.h>
|
||||
#include <asm/oprofile_impl.h>
|
||||
|
@ -244,7 +242,7 @@ static void dump_pmcs(void)
|
|||
mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
|
||||
}
|
||||
|
||||
static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
|
||||
static int fsl_emb_cpu_setup(struct op_counter_config *ctr)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -262,7 +260,7 @@ static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_booke_reg_setup(struct op_counter_config *ctr,
|
||||
static int fsl_emb_reg_setup(struct op_counter_config *ctr,
|
||||
struct op_system_config *sys,
|
||||
int num_ctrs)
|
||||
{
|
||||
|
@ -281,7 +279,7 @@ static int fsl_booke_reg_setup(struct op_counter_config *ctr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int fsl_booke_start(struct op_counter_config *ctr)
|
||||
static int fsl_emb_start(struct op_counter_config *ctr)
|
||||
{
|
||||
int i;
|
||||
|
||||
|
@ -315,7 +313,7 @@ static int fsl_booke_start(struct op_counter_config *ctr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void fsl_booke_stop(void)
|
||||
static void fsl_emb_stop(void)
|
||||
{
|
||||
/* freeze counters */
|
||||
pmc_stop_ctrs();
|
||||
|
@ -329,7 +327,7 @@ static void fsl_booke_stop(void)
|
|||
}
|
||||
|
||||
|
||||
static void fsl_booke_handle_interrupt(struct pt_regs *regs,
|
||||
static void fsl_emb_handle_interrupt(struct pt_regs *regs,
|
||||
struct op_counter_config *ctr)
|
||||
{
|
||||
unsigned long pc;
|
||||
|
@ -362,10 +360,10 @@ static void fsl_booke_handle_interrupt(struct pt_regs *regs,
|
|||
pmc_start_ctrs(1);
|
||||
}
|
||||
|
||||
struct op_powerpc_model op_model_fsl_booke = {
|
||||
.reg_setup = fsl_booke_reg_setup,
|
||||
.cpu_setup = fsl_booke_cpu_setup,
|
||||
.start = fsl_booke_start,
|
||||
.stop = fsl_booke_stop,
|
||||
.handle_interrupt = fsl_booke_handle_interrupt,
|
||||
struct op_powerpc_model op_model_fsl_emb = {
|
||||
.reg_setup = fsl_emb_reg_setup,
|
||||
.cpu_setup = fsl_emb_cpu_setup,
|
||||
.start = fsl_emb_start,
|
||||
.stop = fsl_emb_stop,
|
||||
.handle_interrupt = fsl_emb_handle_interrupt,
|
||||
};
|
|
@ -72,6 +72,7 @@ config WALNUT
|
|||
default y
|
||||
select 405GP
|
||||
select PCI
|
||||
select OF_RTC
|
||||
help
|
||||
This option enables support for the IBM PPC405GP evaluation board.
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ static int __init virtex_probe(void)
|
|||
{
|
||||
unsigned long root = of_get_flat_dt_root();
|
||||
|
||||
if (!of_flat_dt_is_compatible(root, "xilinx,virtex"))
|
||||
if (!of_flat_dt_is_compatible(root, "xlnx,virtex"))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/prom.h>
|
||||
|
|
|
@ -137,7 +137,7 @@ static int __init pika_dtm_start(void)
|
|||
}
|
||||
of_node_put(np);
|
||||
|
||||
fpga = ioremap(res.start + 0x20, 4);
|
||||
fpga = ioremap(res.start, 0x24);
|
||||
if (fpga == NULL)
|
||||
return -ENOENT;
|
||||
|
||||
|
|
20
arch/powerpc/platforms/512x/Kconfig
Normal file
20
arch/powerpc/platforms/512x/Kconfig
Normal file
|
@ -0,0 +1,20 @@
|
|||
config PPC_MPC512x
|
||||
bool
|
||||
select FSL_SOC
|
||||
select IPIC
|
||||
default n
|
||||
|
||||
config PPC_MPC5121
|
||||
bool
|
||||
select PPC_MPC512x
|
||||
default n
|
||||
|
||||
config MPC5121_ADS
|
||||
bool "Freescale MPC5121E ADS"
|
||||
depends on PPC_MULTIPLATFORM && PPC32
|
||||
select DEFAULT_UIMAGE
|
||||
select WANT_DEVICE_TREE
|
||||
select PPC_MPC5121
|
||||
help
|
||||
This option enables support for the MPC5121E ADS board.
|
||||
default n
|
4
arch/powerpc/platforms/512x/Makefile
Normal file
4
arch/powerpc/platforms/512x/Makefile
Normal file
|
@ -0,0 +1,4 @@
|
|||
#
|
||||
# Makefile for the Freescale PowerPC 512x linux kernel.
|
||||
#
|
||||
obj-$(CONFIG_MPC5121_ADS) += mpc5121_ads.o
|
104
arch/powerpc/platforms/512x/mpc5121_ads.c
Normal file
104
arch/powerpc/platforms/512x/mpc5121_ads.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Author: John Rigby, <jrigby@freescale.com>, Thur Mar 29 2007
|
||||
*
|
||||
* Description:
|
||||
* MPC5121 ADS board setup
|
||||
*
|
||||
* This is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/ipic.h>
|
||||
#include <asm/prom.h>
|
||||
#include <asm/time.h>
|
||||
|
||||
/**
|
||||
* mpc512x_find_ips_freq - Find the IPS bus frequency for a device
|
||||
* @node: device node
|
||||
*
|
||||
* Returns IPS bus frequency, or 0 if the bus frequency cannot be found.
|
||||
*/
|
||||
unsigned long
|
||||
mpc512x_find_ips_freq(struct device_node *node)
|
||||
{
|
||||
struct device_node *np;
|
||||
const unsigned int *p_ips_freq = NULL;
|
||||
|
||||
of_node_get(node);
|
||||
while (node) {
|
||||
p_ips_freq = of_get_property(node, "bus-frequency", NULL);
|
||||
if (p_ips_freq)
|
||||
break;
|
||||
|
||||
np = of_get_parent(node);
|
||||
of_node_put(node);
|
||||
node = np;
|
||||
}
|
||||
if (node)
|
||||
of_node_put(node);
|
||||
|
||||
return p_ips_freq ? *p_ips_freq : 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mpc512x_find_ips_freq);
|
||||
|
||||
static struct of_device_id __initdata of_bus_ids[] = {
|
||||
{ .name = "soc", },
|
||||
{ .name = "localbus", },
|
||||
{},
|
||||
};
|
||||
|
||||
static void __init mpc5121_ads_declare_of_platform_devices(void)
|
||||
{
|
||||
/* Find every child of the SOC node and add it to of_platform */
|
||||
if (of_platform_bus_probe(NULL, of_bus_ids, NULL))
|
||||
printk(KERN_ERR __FILE__ ": "
|
||||
"Error while probing of_platform bus\n");
|
||||
}
|
||||
|
||||
static void __init mpc5121_ads_init_IRQ(void)
|
||||
{
|
||||
struct device_node *np;
|
||||
|
||||
np = of_find_compatible_node(NULL, NULL, "fsl,ipic");
|
||||
if (!np)
|
||||
return;
|
||||
|
||||
ipic_init(np, 0);
|
||||
of_node_put(np);
|
||||
|
||||
/*
|
||||
* Initialize the default interrupt mapping priorities,
|
||||
* in case the boot rom changed something on us.
|
||||
*/
|
||||
ipic_set_default_priority();
|
||||
}
|
||||
|
||||
/*
|
||||
* Called very early, MMU is off, device-tree isn't unflattened
|
||||
*/
|
||||
static int __init mpc5121_ads_probe(void)
|
||||
{
|
||||
unsigned long root = of_get_flat_dt_root();
|
||||
|
||||
return of_flat_dt_is_compatible(root, "fsl,mpc5121ads");
|
||||
}
|
||||
|
||||
define_machine(mpc5121_ads) {
|
||||
.name = "MPC5121 ADS",
|
||||
.probe = mpc5121_ads_probe,
|
||||
.init = mpc5121_ads_declare_of_platform_devices,
|
||||
.init_IRQ = mpc5121_ads_init_IRQ,
|
||||
.get_irq = ipic_get_irq,
|
||||
.calibrate_decr = generic_calibrate_decr,
|
||||
};
|
|
@ -134,13 +134,12 @@ static void __init mpc8272_ads_setup_arch(void)
|
|||
}
|
||||
|
||||
bcsr = of_iomap(np, 0);
|
||||
of_node_put(np);
|
||||
if (!bcsr) {
|
||||
printk(KERN_ERR "Cannot map BCSR registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
|
||||
setbits32(&bcsr[1], BCSR1_FETH_RST);
|
||||
|
||||
|
|
|
@ -130,13 +130,12 @@ static void __init pq2fads_setup_arch(void)
|
|||
}
|
||||
|
||||
bcsr = of_iomap(np, 0);
|
||||
of_node_put(np);
|
||||
if (!bcsr) {
|
||||
printk(KERN_ERR "Cannot map BCSR registers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
|
||||
/* Enable the serial and ethernet ports */
|
||||
|
||||
clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
|
||||
|
|
|
@ -101,7 +101,7 @@ static void __init mpc832x_rdb_setup_arch(void)
|
|||
#ifdef CONFIG_QUICC_ENGINE
|
||||
qe_reset();
|
||||
|
||||
if ((np = of_find_node_by_name(np, "par_io")) != NULL) {
|
||||
if ((np = of_find_node_by_name(NULL, "par_io")) != NULL) {
|
||||
par_io_init(np);
|
||||
of_node_put(np);
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#define MPC83XX_SCCR_USB_DRCM_11 0x00300000
|
||||
#define MPC83XX_SCCR_USB_DRCM_01 0x00100000
|
||||
#define MPC83XX_SCCR_USB_DRCM_10 0x00200000
|
||||
#define MPC8315_SCCR_USB_MASK 0x00c00000
|
||||
#define MPC8315_SCCR_USB_DRCM_11 0x00c00000
|
||||
#define MPC837X_SCCR_USB_DRCM_11 0x00c00000
|
||||
|
||||
/* system i/o configuration register low */
|
||||
|
|
|
@ -104,6 +104,7 @@ int mpc831x_usb_cfg(void)
|
|||
u32 temp;
|
||||
void __iomem *immap, *usb_regs;
|
||||
struct device_node *np = NULL;
|
||||
struct device_node *immr_node = NULL;
|
||||
const void *prop;
|
||||
struct resource res;
|
||||
int ret = 0;
|
||||
|
@ -124,10 +125,15 @@ int mpc831x_usb_cfg(void)
|
|||
}
|
||||
|
||||
/* Configure clock */
|
||||
temp = in_be32(immap + MPC83XX_SCCR_OFFS);
|
||||
temp &= ~MPC83XX_SCCR_USB_MASK;
|
||||
temp |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */
|
||||
out_be32(immap + MPC83XX_SCCR_OFFS, temp);
|
||||
immr_node = of_get_parent(np);
|
||||
if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
|
||||
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
|
||||
MPC8315_SCCR_USB_MASK,
|
||||
MPC8315_SCCR_USB_DRCM_11);
|
||||
else
|
||||
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
|
||||
MPC83XX_SCCR_USB_MASK,
|
||||
MPC83XX_SCCR_USB_DRCM_11);
|
||||
|
||||
/* Configure pin mux for ULPI. There is no pin mux for UTMI */
|
||||
if (prop && !strcmp(prop, "ulpi")) {
|
||||
|
@ -144,6 +150,9 @@ int mpc831x_usb_cfg(void)
|
|||
|
||||
iounmap(immap);
|
||||
|
||||
if (immr_node)
|
||||
of_node_put(immr_node);
|
||||
|
||||
/* Map USB SOC space */
|
||||
ret = of_address_to_resource(np, 0, &res);
|
||||
if (ret) {
|
||||
|
|
|
@ -15,12 +15,12 @@
|
|||
|
||||
#include <asm/time.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/commproc.h>
|
||||
#include <asm/cpm1.h>
|
||||
#include <asm/fs_pd.h>
|
||||
#include <asm/udbg.h>
|
||||
#include <asm/prom.h>
|
||||
|
||||
#include <sysdev/commproc.h>
|
||||
#include "mpc8xx.h"
|
||||
|
||||
struct cpm_pin {
|
||||
int port, pin, flags;
|
||||
|
@ -108,7 +108,7 @@ define_machine(adder875) {
|
|||
.name = "Adder MPC875",
|
||||
.probe = adder875_probe,
|
||||
.setup_arch = adder875_setup,
|
||||
.init_IRQ = m8xx_pic_init,
|
||||
.init_IRQ = mpc8xx_pics_init,
|
||||
.get_irq = mpc8xx_get_irq,
|
||||
.restart = mpc8xx_restart,
|
||||
.calibrate_decr = generic_calibrate_decr,
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include <asm/machdep.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/udbg.h>
|
||||
#include <asm/commproc.h>
|
||||
#include <asm/cpm1.h>
|
||||
|
||||
#include "mpc8xx.h"
|
||||
|
|
|
@ -24,6 +24,7 @@ config PPC_83xx
|
|||
select MPC83xx
|
||||
select IPIC
|
||||
select WANT_DEVICE_TREE
|
||||
select FSL_EMB_PERFMON
|
||||
|
||||
config PPC_86xx
|
||||
bool "Freescale 86xx"
|
||||
|
@ -41,6 +42,7 @@ config CLASSIC32
|
|||
source "arch/powerpc/platforms/pseries/Kconfig"
|
||||
source "arch/powerpc/platforms/iseries/Kconfig"
|
||||
source "arch/powerpc/platforms/chrp/Kconfig"
|
||||
source "arch/powerpc/platforms/512x/Kconfig"
|
||||
source "arch/powerpc/platforms/52xx/Kconfig"
|
||||
source "arch/powerpc/platforms/powermac/Kconfig"
|
||||
source "arch/powerpc/platforms/prep/Kconfig"
|
||||
|
|
|
@ -14,7 +14,7 @@ choice
|
|||
There are five families of 32 bit PowerPC chips supported.
|
||||
The most common ones are the desktop and server CPUs (601, 603,
|
||||
604, 740, 750, 74xx) CPUs from Freescale and IBM, with their
|
||||
embedded 52xx/82xx/83xx/86xx counterparts.
|
||||
embedded 512x/52xx/82xx/83xx/86xx counterparts.
|
||||
The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500
|
||||
(85xx) each form a family of their own that is not compatible
|
||||
with the others.
|
||||
|
@ -22,7 +22,7 @@ choice
|
|||
If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx.
|
||||
|
||||
config 6xx
|
||||
bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx"
|
||||
bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
|
||||
select PPC_FPU
|
||||
|
||||
config PPC_85xx
|
||||
|
@ -94,6 +94,7 @@ config 8xx
|
|||
bool
|
||||
|
||||
config E500
|
||||
select FSL_EMB_PERFMON
|
||||
bool
|
||||
|
||||
config PPC_FPU
|
||||
|
@ -115,6 +116,9 @@ config FSL_BOOKE
|
|||
depends on E200 || E500
|
||||
default y
|
||||
|
||||
config FSL_EMB_PERFMON
|
||||
bool
|
||||
|
||||
config PTE_64BIT
|
||||
bool
|
||||
depends on 44x || E500
|
||||
|
@ -221,7 +225,7 @@ config NR_CPUS
|
|||
|
||||
config NOT_COHERENT_CACHE
|
||||
bool
|
||||
depends on 4xx || 8xx || E200
|
||||
depends on 4xx || 8xx || E200 || PPC_MPC512x
|
||||
default y
|
||||
|
||||
config CHECK_CACHE_COHERENCY
|
||||
|
|
|
@ -11,6 +11,7 @@ endif
|
|||
obj-$(CONFIG_PPC_CHRP) += chrp/
|
||||
obj-$(CONFIG_40x) += 40x/
|
||||
obj-$(CONFIG_44x) += 44x/
|
||||
obj-$(CONFIG_PPC_MPC512x) += 512x/
|
||||
obj-$(CONFIG_PPC_MPC52xx) += 52xx/
|
||||
obj-$(CONFIG_PPC_8xx) += 8xx/
|
||||
obj-$(CONFIG_PPC_82xx) += 82xx/
|
||||
|
|
|
@ -54,6 +54,13 @@ config SPU_FS_64K_LS
|
|||
uses 4K pages. This can improve performances of applications
|
||||
using multiple SPEs by lowering the TLB pressure on them.
|
||||
|
||||
config SPU_TRACE
|
||||
tristate "SPU event tracing support"
|
||||
depends on SPU_FS && MARKERS
|
||||
help
|
||||
This option allows reading a trace of spu-related events through
|
||||
the sputrace file in procfs.
|
||||
|
||||
config SPU_BASE
|
||||
bool
|
||||
default n
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
#include <asm/dcr.h>
|
||||
#include <asm/machdep.h>
|
||||
|
@ -65,14 +65,12 @@
|
|||
|
||||
struct axon_msic {
|
||||
struct irq_host *irq_host;
|
||||
__le32 *fifo;
|
||||
__le32 *fifo_virt;
|
||||
dma_addr_t fifo_phys;
|
||||
dcr_host_t dcr_host;
|
||||
struct list_head list;
|
||||
u32 read_offset;
|
||||
};
|
||||
|
||||
static LIST_HEAD(axon_msic_list);
|
||||
|
||||
static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
|
||||
{
|
||||
pr_debug("axon_msi: dcr_write(0x%x, 0x%x)\n", val, dcr_n);
|
||||
|
@ -94,7 +92,7 @@ static void axon_msi_cascade(unsigned int irq, struct irq_desc *desc)
|
|||
|
||||
while (msic->read_offset != write_offset) {
|
||||
idx = msic->read_offset / sizeof(__le32);
|
||||
msi = le32_to_cpu(msic->fifo[idx]);
|
||||
msi = le32_to_cpu(msic->fifo_virt[idx]);
|
||||
msi &= 0xFFFF;
|
||||
|
||||
pr_debug("axon_msi: woff %x roff %x msi %x\n",
|
||||
|
@ -139,6 +137,7 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
|
|||
|
||||
tmp = dn;
|
||||
dn = of_find_node_by_phandle(*ph);
|
||||
of_node_put(tmp);
|
||||
if (!dn) {
|
||||
dev_dbg(&dev->dev,
|
||||
"axon_msi: msi-translator doesn't point to a node\n");
|
||||
|
@ -156,7 +155,6 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
|
|||
|
||||
out_error:
|
||||
of_node_put(dn);
|
||||
of_node_put(tmp);
|
||||
|
||||
return msic;
|
||||
}
|
||||
|
@ -292,30 +290,24 @@ static struct irq_host_ops msic_host_ops = {
|
|||
.map = msic_host_map,
|
||||
};
|
||||
|
||||
static int axon_msi_notify_reboot(struct notifier_block *nb,
|
||||
unsigned long code, void *data)
|
||||
static int axon_msi_shutdown(struct of_device *device)
|
||||
{
|
||||
struct axon_msic *msic;
|
||||
struct axon_msic *msic = device->dev.platform_data;
|
||||
u32 tmp;
|
||||
|
||||
list_for_each_entry(msic, &axon_msic_list, list) {
|
||||
pr_debug("axon_msi: disabling %s\n",
|
||||
msic->irq_host->of_node->full_name);
|
||||
tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
|
||||
tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
|
||||
msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
|
||||
}
|
||||
pr_debug("axon_msi: disabling %s\n",
|
||||
msic->irq_host->of_node->full_name);
|
||||
tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
|
||||
tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
|
||||
msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block axon_msi_reboot_notifier = {
|
||||
.notifier_call = axon_msi_notify_reboot
|
||||
};
|
||||
|
||||
static int axon_msi_setup_one(struct device_node *dn)
|
||||
static int axon_msi_probe(struct of_device *device,
|
||||
const struct of_device_id *device_id)
|
||||
{
|
||||
struct page *page;
|
||||
struct device_node *dn = device->node;
|
||||
struct axon_msic *msic;
|
||||
unsigned int virq;
|
||||
int dcr_base, dcr_len;
|
||||
|
@ -346,16 +338,14 @@ static int axon_msi_setup_one(struct device_node *dn)
|
|||
goto out_free_msic;
|
||||
}
|
||||
|
||||
page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
|
||||
get_order(MSIC_FIFO_SIZE_BYTES));
|
||||
if (!page) {
|
||||
msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES,
|
||||
&msic->fifo_phys, GFP_KERNEL);
|
||||
if (!msic->fifo_virt) {
|
||||
printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
|
||||
dn->full_name);
|
||||
goto out_free_msic;
|
||||
}
|
||||
|
||||
msic->fifo = page_address(page);
|
||||
|
||||
msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP,
|
||||
NR_IRQS, &msic_host_ops, 0);
|
||||
if (!msic->irq_host) {
|
||||
|
@ -378,14 +368,18 @@ static int axon_msi_setup_one(struct device_node *dn)
|
|||
pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
|
||||
|
||||
/* Enable the MSIC hardware */
|
||||
msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, (u64)msic->fifo >> 32);
|
||||
msic_dcr_write(msic, MSIC_BASE_ADDR_HI_REG, msic->fifo_phys >> 32);
|
||||
msic_dcr_write(msic, MSIC_BASE_ADDR_LO_REG,
|
||||
(u64)msic->fifo & 0xFFFFFFFF);
|
||||
msic->fifo_phys & 0xFFFFFFFF);
|
||||
msic_dcr_write(msic, MSIC_CTRL_REG,
|
||||
MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
|
||||
MSIC_CTRL_FIFO_SIZE);
|
||||
|
||||
list_add(&msic->list, &axon_msic_list);
|
||||
device->dev.platform_data = msic;
|
||||
|
||||
ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
|
||||
ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
|
||||
ppc_md.msi_check_device = axon_msi_check_device;
|
||||
|
||||
printk(KERN_DEBUG "axon_msi: setup MSIC on %s\n", dn->full_name);
|
||||
|
||||
|
@ -394,7 +388,8 @@ static int axon_msi_setup_one(struct device_node *dn)
|
|||
out_free_host:
|
||||
kfree(msic->irq_host);
|
||||
out_free_fifo:
|
||||
__free_pages(virt_to_page(msic->fifo), get_order(MSIC_FIFO_SIZE_BYTES));
|
||||
dma_free_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES, msic->fifo_virt,
|
||||
msic->fifo_phys);
|
||||
out_free_msic:
|
||||
kfree(msic);
|
||||
out:
|
||||
|
@ -402,28 +397,24 @@ out:
|
|||
return -1;
|
||||
}
|
||||
|
||||
static int axon_msi_init(void)
|
||||
static const struct of_device_id axon_msi_device_id[] = {
|
||||
{
|
||||
.compatible = "ibm,axon-msic"
|
||||
},
|
||||
{}
|
||||
};
|
||||
|
||||
static struct of_platform_driver axon_msi_driver = {
|
||||
.match_table = axon_msi_device_id,
|
||||
.probe = axon_msi_probe,
|
||||
.shutdown = axon_msi_shutdown,
|
||||
.driver = {
|
||||
.name = "axon-msi"
|
||||
},
|
||||
};
|
||||
|
||||
static int __init axon_msi_init(void)
|
||||
{
|
||||
struct device_node *dn;
|
||||
int found = 0;
|
||||
|
||||
pr_debug("axon_msi: initialising ...\n");
|
||||
|
||||
for_each_compatible_node(dn, NULL, "ibm,axon-msic") {
|
||||
if (axon_msi_setup_one(dn) == 0)
|
||||
found++;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
|
||||
ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
|
||||
ppc_md.msi_check_device = axon_msi_check_device;
|
||||
|
||||
register_reboot_notifier(&axon_msi_reboot_notifier);
|
||||
|
||||
pr_debug("axon_msi: registered callbacks!\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
return of_register_platform_driver(&axon_msi_driver);
|
||||
}
|
||||
arch_initcall(axon_msi_init);
|
||||
subsys_initcall(axon_msi_init);
|
||||
|
|
|
@ -98,7 +98,7 @@ static int __init cell_publish_devices(void)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
machine_device_initcall(cell, cell_publish_devices);
|
||||
machine_subsys_initcall(cell, cell_publish_devices);
|
||||
|
||||
static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
|
|
|
@ -4,6 +4,8 @@ spufs-y += inode.o file.o context.o syscalls.o coredump.o
|
|||
spufs-y += sched.o backing_ops.o hw_ops.o run.o gang.o
|
||||
spufs-y += switch.o fault.o lscsa_alloc.o
|
||||
|
||||
obj-$(CONFIG_SPU_TRACE) += sputrace.o
|
||||
|
||||
# Rules to build switch.o with the help of SPU tool chain
|
||||
SPU_CROSS := spu-
|
||||
SPU_CC := $(SPU_CROSS)gcc
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include <linux/poll.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/marker.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/semaphore.h>
|
||||
|
@ -358,6 +359,8 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
|
|||
struct spu_context *ctx = vma->vm_file->private_data;
|
||||
unsigned long area, offset = address - vma->vm_start;
|
||||
|
||||
spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx);
|
||||
|
||||
offset += vma->vm_pgoff << PAGE_SHIFT;
|
||||
if (offset >= ps_size)
|
||||
return NOPFN_SIGBUS;
|
||||
|
@ -375,11 +378,14 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
|
|||
|
||||
if (ctx->state == SPU_STATE_SAVED) {
|
||||
up_read(¤t->mm->mmap_sem);
|
||||
spu_context_nospu_trace(spufs_ps_nopfn__sleep, ctx);
|
||||
spufs_wait(ctx->run_wq, ctx->state == SPU_STATE_RUNNABLE);
|
||||
spu_context_trace(spufs_ps_nopfn__wake, ctx, ctx->spu);
|
||||
down_read(¤t->mm->mmap_sem);
|
||||
} else {
|
||||
area = ctx->spu->problem_phys + ps_offs;
|
||||
vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT);
|
||||
spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu);
|
||||
}
|
||||
|
||||
spu_release(ctx);
|
||||
|
|
|
@ -322,7 +322,7 @@ static struct spu_context *
|
|||
spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
|
||||
struct file *filp)
|
||||
{
|
||||
struct spu_context *tmp, *neighbor;
|
||||
struct spu_context *tmp, *neighbor, *err;
|
||||
int count, node;
|
||||
int aff_supp;
|
||||
|
||||
|
@ -354,11 +354,15 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
|
|||
if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
|
||||
!list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
|
||||
!list_entry(neighbor->aff_list.next, struct spu_context,
|
||||
aff_list)->aff_head)
|
||||
return ERR_PTR(-EEXIST);
|
||||
aff_list)->aff_head) {
|
||||
err = ERR_PTR(-EEXIST);
|
||||
goto out_put_neighbor;
|
||||
}
|
||||
|
||||
if (gang != neighbor->gang)
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (gang != neighbor->gang) {
|
||||
err = ERR_PTR(-EINVAL);
|
||||
goto out_put_neighbor;
|
||||
}
|
||||
|
||||
count = 1;
|
||||
list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
|
||||
|
@ -372,11 +376,17 @@ spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
|
|||
break;
|
||||
}
|
||||
|
||||
if (node == MAX_NUMNODES)
|
||||
return ERR_PTR(-EEXIST);
|
||||
if (node == MAX_NUMNODES) {
|
||||
err = ERR_PTR(-EEXIST);
|
||||
goto out_put_neighbor;
|
||||
}
|
||||
}
|
||||
|
||||
return neighbor;
|
||||
|
||||
out_put_neighbor:
|
||||
put_spu_context(neighbor);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -454,9 +464,12 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
|
|||
if (ret)
|
||||
goto out_aff_unlock;
|
||||
|
||||
if (affinity)
|
||||
if (affinity) {
|
||||
spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
|
||||
neighbor);
|
||||
if (neighbor)
|
||||
put_spu_context(neighbor);
|
||||
}
|
||||
|
||||
/*
|
||||
* get references for dget and mntget, will be released
|
||||
|
|
|
@ -410,8 +410,11 @@ long spufs_run_spu(struct spu_context *ctx, u32 *npc, u32 *event)
|
|||
* since we have TIF_SINGLESTEP set, thus the kernel will do
|
||||
* it upon return from the syscall anyawy
|
||||
*/
|
||||
if ((status & SPU_STATUS_STOPPED_BY_STOP)
|
||||
&& (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
|
||||
if (unlikely(status & SPU_STATUS_SINGLE_STEP))
|
||||
ret = -ERESTARTSYS;
|
||||
|
||||
else if (unlikely((status & SPU_STATUS_STOPPED_BY_STOP)
|
||||
&& (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff)) {
|
||||
force_sig(SIGTRAP, current);
|
||||
ret = -ERESTARTSYS;
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <linux/pid_namespace.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/marker.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/mmu_context.h>
|
||||
|
@ -216,8 +217,8 @@ void do_notify_spus_active(void)
|
|||
*/
|
||||
static void spu_bind_context(struct spu *spu, struct spu_context *ctx)
|
||||
{
|
||||
pr_debug("%s: pid=%d SPU=%d NODE=%d\n", __FUNCTION__, current->pid,
|
||||
spu->number, spu->node);
|
||||
spu_context_trace(spu_bind_context__enter, ctx, spu);
|
||||
|
||||
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
|
||||
|
||||
if (ctx->flags & SPU_CREATE_NOSCHED)
|
||||
|
@ -399,8 +400,8 @@ static int has_affinity(struct spu_context *ctx)
|
|||
*/
|
||||
static void spu_unbind_context(struct spu *spu, struct spu_context *ctx)
|
||||
{
|
||||
pr_debug("%s: unbind pid=%d SPU=%d NODE=%d\n", __FUNCTION__,
|
||||
spu->pid, spu->number, spu->node);
|
||||
spu_context_trace(spu_unbind_context__enter, ctx, spu);
|
||||
|
||||
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
|
||||
|
||||
if (spu->ctx->flags & SPU_CREATE_NOSCHED)
|
||||
|
@ -528,6 +529,8 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
|
|||
struct spu *spu, *aff_ref_spu;
|
||||
int node, n;
|
||||
|
||||
spu_context_nospu_trace(spu_get_idle__enter, ctx);
|
||||
|
||||
if (ctx->gang) {
|
||||
mutex_lock(&ctx->gang->aff_mutex);
|
||||
if (has_affinity(ctx)) {
|
||||
|
@ -546,8 +549,7 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
|
|||
if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
|
||||
ctx->gang->aff_ref_spu = NULL;
|
||||
mutex_unlock(&ctx->gang->aff_mutex);
|
||||
|
||||
return NULL;
|
||||
goto not_found;
|
||||
}
|
||||
mutex_unlock(&ctx->gang->aff_mutex);
|
||||
}
|
||||
|
@ -565,12 +567,14 @@ static struct spu *spu_get_idle(struct spu_context *ctx)
|
|||
mutex_unlock(&cbe_spu_info[node].list_mutex);
|
||||
}
|
||||
|
||||
not_found:
|
||||
spu_context_nospu_trace(spu_get_idle__not_found, ctx);
|
||||
return NULL;
|
||||
|
||||
found:
|
||||
spu->alloc_state = SPU_USED;
|
||||
mutex_unlock(&cbe_spu_info[node].list_mutex);
|
||||
pr_debug("Got SPU %d %d\n", spu->number, spu->node);
|
||||
spu_context_trace(spu_get_idle__found, ctx, spu);
|
||||
spu_init_channels(spu);
|
||||
return spu;
|
||||
}
|
||||
|
@ -587,6 +591,8 @@ static struct spu *find_victim(struct spu_context *ctx)
|
|||
struct spu *spu;
|
||||
int node, n;
|
||||
|
||||
spu_context_nospu_trace(spu_find_vitim__enter, ctx);
|
||||
|
||||
/*
|
||||
* Look for a possible preemption candidate on the local node first.
|
||||
* If there is no candidate look at the other nodes. This isn't
|
||||
|
@ -640,6 +646,8 @@ static struct spu *find_victim(struct spu_context *ctx)
|
|||
goto restart;
|
||||
}
|
||||
|
||||
spu_context_trace(__spu_deactivate__unload, ctx, spu);
|
||||
|
||||
mutex_lock(&cbe_spu_info[node].list_mutex);
|
||||
cbe_spu_info[node].nr_active--;
|
||||
spu_unbind_context(spu, victim);
|
||||
|
@ -822,6 +830,7 @@ static int __spu_deactivate(struct spu_context *ctx, int force, int max_prio)
|
|||
*/
|
||||
void spu_deactivate(struct spu_context *ctx)
|
||||
{
|
||||
spu_context_nospu_trace(spu_deactivate__enter, ctx);
|
||||
__spu_deactivate(ctx, 1, MAX_PRIO);
|
||||
}
|
||||
|
||||
|
@ -835,6 +844,7 @@ void spu_deactivate(struct spu_context *ctx)
|
|||
*/
|
||||
void spu_yield(struct spu_context *ctx)
|
||||
{
|
||||
spu_context_nospu_trace(spu_yield__enter, ctx);
|
||||
if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
|
||||
mutex_lock(&ctx->state_mutex);
|
||||
__spu_deactivate(ctx, 0, MAX_PRIO);
|
||||
|
@ -864,11 +874,15 @@ static noinline void spusched_tick(struct spu_context *ctx)
|
|||
goto out;
|
||||
|
||||
spu = ctx->spu;
|
||||
|
||||
spu_context_trace(spusched_tick__preempt, ctx, spu);
|
||||
|
||||
new = grab_runnable_context(ctx->prio + 1, spu->node);
|
||||
if (new) {
|
||||
spu_unschedule(spu, ctx);
|
||||
spu_add_to_rq(ctx);
|
||||
} else {
|
||||
spu_context_nospu_trace(spusched_tick__newslice, ctx);
|
||||
ctx->time_slice++;
|
||||
}
|
||||
out:
|
||||
|
|
|
@ -325,4 +325,9 @@ extern void spu_free_lscsa(struct spu_state *csa);
|
|||
extern void spuctx_switch_state(struct spu_context *ctx,
|
||||
enum spu_utilization_state new_state);
|
||||
|
||||
#define spu_context_trace(name, ctx, spu) \
|
||||
trace_mark(name, "%p %p", ctx, spu);
|
||||
#define spu_context_nospu_trace(name, ctx) \
|
||||
trace_mark(name, "%p", ctx);
|
||||
|
||||
#endif
|
||||
|
|
250
arch/powerpc/platforms/cell/spufs/sputrace.c
Normal file
250
arch/powerpc/platforms/cell/spufs/sputrace.c
Normal file
|
@ -0,0 +1,250 @@
|
|||
/*
|
||||
* Copyright (C) 2007 IBM Deutschland Entwicklung GmbH
|
||||
* Released under GPL v2.
|
||||
*
|
||||
* Partially based on net/ipv4/tcp_probe.c.
|
||||
*
|
||||
* Simple tracing facility for spu contexts.
|
||||
*/
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/marker.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/wait.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include "spufs.h"
|
||||
|
||||
struct spu_probe {
|
||||
const char *name;
|
||||
const char *format;
|
||||
marker_probe_func *probe_func;
|
||||
};
|
||||
|
||||
struct sputrace {
|
||||
ktime_t tstamp;
|
||||
int owner_tid; /* owner */
|
||||
int curr_tid;
|
||||
const char *name;
|
||||
int number;
|
||||
};
|
||||
|
||||
static int bufsize __read_mostly = 16384;
|
||||
MODULE_PARM_DESC(bufsize, "Log buffer size (number of records)");
|
||||
module_param(bufsize, int, 0);
|
||||
|
||||
|
||||
static DEFINE_SPINLOCK(sputrace_lock);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(sputrace_wait);
|
||||
static ktime_t sputrace_start;
|
||||
static unsigned long sputrace_head, sputrace_tail;
|
||||
static struct sputrace *sputrace_log;
|
||||
|
||||
static int sputrace_used(void)
|
||||
{
|
||||
return (sputrace_head - sputrace_tail) % bufsize;
|
||||
}
|
||||
|
||||
static inline int sputrace_avail(void)
|
||||
{
|
||||
return bufsize - sputrace_used();
|
||||
}
|
||||
|
||||
static int sputrace_sprint(char *tbuf, int n)
|
||||
{
|
||||
const struct sputrace *t = sputrace_log + sputrace_tail % bufsize;
|
||||
struct timespec tv =
|
||||
ktime_to_timespec(ktime_sub(t->tstamp, sputrace_start));
|
||||
|
||||
return snprintf(tbuf, n,
|
||||
"[%lu.%09lu] %d: %s (thread = %d, spu = %d)\n",
|
||||
(unsigned long) tv.tv_sec,
|
||||
(unsigned long) tv.tv_nsec,
|
||||
t->owner_tid,
|
||||
t->name,
|
||||
t->curr_tid,
|
||||
t->number);
|
||||
}
|
||||
|
||||
static ssize_t sputrace_read(struct file *file, char __user *buf,
|
||||
size_t len, loff_t *ppos)
|
||||
{
|
||||
int error = 0, cnt = 0;
|
||||
|
||||
if (!buf || len < 0)
|
||||
return -EINVAL;
|
||||
|
||||
while (cnt < len) {
|
||||
char tbuf[128];
|
||||
int width;
|
||||
|
||||
error = wait_event_interruptible(sputrace_wait,
|
||||
sputrace_used() > 0);
|
||||
if (error)
|
||||
break;
|
||||
|
||||
spin_lock(&sputrace_lock);
|
||||
if (sputrace_head == sputrace_tail) {
|
||||
spin_unlock(&sputrace_lock);
|
||||
continue;
|
||||
}
|
||||
|
||||
width = sputrace_sprint(tbuf, sizeof(tbuf));
|
||||
if (width < len)
|
||||
sputrace_tail = (sputrace_tail + 1) % bufsize;
|
||||
spin_unlock(&sputrace_lock);
|
||||
|
||||
if (width >= len)
|
||||
break;
|
||||
|
||||
error = copy_to_user(buf + cnt, tbuf, width);
|
||||
if (error)
|
||||
break;
|
||||
cnt += width;
|
||||
}
|
||||
|
||||
return cnt == 0 ? error : cnt;
|
||||
}
|
||||
|
||||
static int sputrace_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
spin_lock(&sputrace_lock);
|
||||
sputrace_head = sputrace_tail = 0;
|
||||
sputrace_start = ktime_get();
|
||||
spin_unlock(&sputrace_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations sputrace_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = sputrace_open,
|
||||
.read = sputrace_read,
|
||||
};
|
||||
|
||||
static void sputrace_log_item(const char *name, struct spu_context *ctx,
|
||||
struct spu *spu)
|
||||
{
|
||||
spin_lock(&sputrace_lock);
|
||||
if (sputrace_avail() > 1) {
|
||||
struct sputrace *t = sputrace_log + sputrace_head;
|
||||
|
||||
t->tstamp = ktime_get();
|
||||
t->owner_tid = ctx->tid;
|
||||
t->name = name;
|
||||
t->curr_tid = current->pid;
|
||||
t->number = spu ? spu->number : -1;
|
||||
|
||||
sputrace_head = (sputrace_head + 1) % bufsize;
|
||||
} else {
|
||||
printk(KERN_WARNING
|
||||
"sputrace: lost samples due to full buffer.\n");
|
||||
}
|
||||
spin_unlock(&sputrace_lock);
|
||||
|
||||
wake_up(&sputrace_wait);
|
||||
}
|
||||
|
||||
static void spu_context_event(const struct marker *mdata,
|
||||
void *private, const char *format, ...)
|
||||
{
|
||||
struct spu_probe *p = mdata->private;
|
||||
va_list ap;
|
||||
struct spu_context *ctx;
|
||||
struct spu *spu;
|
||||
|
||||
va_start(ap, format);
|
||||
ctx = va_arg(ap, struct spu_context *);
|
||||
spu = va_arg(ap, struct spu *);
|
||||
|
||||
sputrace_log_item(p->name, ctx, spu);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
static void spu_context_nospu_event(const struct marker *mdata,
|
||||
void *private, const char *format, ...)
|
||||
{
|
||||
struct spu_probe *p = mdata->private;
|
||||
va_list ap;
|
||||
struct spu_context *ctx;
|
||||
|
||||
va_start(ap, format);
|
||||
ctx = va_arg(ap, struct spu_context *);
|
||||
|
||||
sputrace_log_item(p->name, ctx, NULL);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
struct spu_probe spu_probes[] = {
|
||||
{ "spu_bind_context__enter", "%p %p", spu_context_event },
|
||||
{ "spu_unbind_context__enter", "%p %p", spu_context_event },
|
||||
{ "spu_get_idle__enter", "%p", spu_context_nospu_event },
|
||||
{ "spu_get_idle__found", "%p %p", spu_context_event },
|
||||
{ "spu_get_idle__not_found", "%p", spu_context_nospu_event },
|
||||
{ "spu_find_victim__enter", "%p", spu_context_nospu_event },
|
||||
{ "spusched_tick__preempt", "%p %p", spu_context_event },
|
||||
{ "spusched_tick__newslice", "%p", spu_context_nospu_event },
|
||||
{ "spu_yield__enter", "%p", spu_context_nospu_event },
|
||||
{ "spu_deactivate__enter", "%p", spu_context_nospu_event },
|
||||
{ "__spu_deactivate__unload", "%p %p", spu_context_event },
|
||||
{ "spufs_ps_nopfn__enter", "%p", spu_context_nospu_event },
|
||||
{ "spufs_ps_nopfn__sleep", "%p", spu_context_nospu_event },
|
||||
{ "spufs_ps_nopfn__wake", "%p %p", spu_context_event },
|
||||
{ "spufs_ps_nopfn__insert", "%p %p", spu_context_event },
|
||||
{ "spu_acquire_saved__enter", "%p", spu_context_nospu_event },
|
||||
{ "destroy_spu_context__enter", "%p", spu_context_nospu_event },
|
||||
};
|
||||
|
||||
static int __init sputrace_init(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
int i, error = -ENOMEM;
|
||||
|
||||
sputrace_log = kcalloc(sizeof(struct sputrace),
|
||||
bufsize, GFP_KERNEL);
|
||||
if (!sputrace_log)
|
||||
goto out;
|
||||
|
||||
entry = create_proc_entry("sputrace", S_IRUSR, NULL);
|
||||
if (!entry)
|
||||
goto out_free_log;
|
||||
entry->proc_fops = &sputrace_fops;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(spu_probes); i++) {
|
||||
struct spu_probe *p = &spu_probes[i];
|
||||
|
||||
error = marker_probe_register(p->name, p->format,
|
||||
p->probe_func, p);
|
||||
if (error)
|
||||
printk(KERN_INFO "Unable to register probe %s\n",
|
||||
p->name);
|
||||
|
||||
error = marker_arm(p->name);
|
||||
if (error)
|
||||
printk(KERN_INFO "Unable to arm probe %s\n", p->name);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_log:
|
||||
kfree(sputrace_log);
|
||||
out:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void __exit sputrace_exit(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(spu_probes); i++)
|
||||
marker_probe_unregister(spu_probes[i].name);
|
||||
|
||||
remove_proc_entry("sputrace", NULL);
|
||||
kfree(sputrace_log);
|
||||
}
|
||||
|
||||
module_init(sputrace_init);
|
||||
module_exit(sputrace_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
|
@ -132,33 +132,18 @@ static void __init storcenter_init_IRQ(void)
|
|||
|
||||
paddr = (phys_addr_t)of_translate_address(dnp, prop);
|
||||
mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET,
|
||||
4, 32, " EPIC ");
|
||||
16, 32, " OpenPIC ");
|
||||
|
||||
of_node_put(dnp);
|
||||
|
||||
BUG_ON(mpic == NULL);
|
||||
|
||||
/* PCI IRQs */
|
||||
/*
|
||||
* 2.6.12 patch:
|
||||
* openpic_set_sources(0, 5, OpenPIC_Addr + 0x10200);
|
||||
* openpic_set_sources(5, 2, OpenPIC_Addr + 0x11120);
|
||||
* first_irq, num_irqs, __iomem first_ISR
|
||||
* o_ss: i, src: 0, fdf50200
|
||||
* o_ss: i, src: 1, fdf50220
|
||||
* o_ss: i, src: 2, fdf50240
|
||||
* o_ss: i, src: 3, fdf50260
|
||||
* o_ss: i, src: 4, fdf50280
|
||||
* o_ss: i, src: 5, fdf51120
|
||||
* o_ss: i, src: 6, fdf51140
|
||||
* 16 Serial Interrupts followed by 16 Internal Interrupts.
|
||||
* I2C is the second internal, so it is at 17, 0x11020.
|
||||
*/
|
||||
mpic_assign_isu(mpic, 0, paddr + 0x10200);
|
||||
mpic_assign_isu(mpic, 1, paddr + 0x10220);
|
||||
mpic_assign_isu(mpic, 2, paddr + 0x10240);
|
||||
mpic_assign_isu(mpic, 3, paddr + 0x10260);
|
||||
mpic_assign_isu(mpic, 4, paddr + 0x10280);
|
||||
mpic_assign_isu(mpic, 5, paddr + 0x11120);
|
||||
mpic_assign_isu(mpic, 6, paddr + 0x11140);
|
||||
mpic_assign_isu(mpic, 1, paddr + 0x11000);
|
||||
|
||||
mpic_init(mpic);
|
||||
}
|
||||
|
@ -178,7 +163,7 @@ static int __init storcenter_probe(void)
|
|||
{
|
||||
unsigned long root = of_get_flat_dt_root();
|
||||
|
||||
return of_flat_dt_is_compatible(root, "storcenter");
|
||||
return of_flat_dt_is_compatible(root, "iomega,storcenter");
|
||||
}
|
||||
|
||||
define_machine(storcenter){
|
||||
|
|
|
@ -58,7 +58,7 @@ static void pseries_mach_cpu_die(void)
|
|||
{
|
||||
local_irq_disable();
|
||||
idle_task_exit();
|
||||
xics_teardown_cpu(0);
|
||||
xics_teardown_cpu();
|
||||
unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow()));
|
||||
rtas_stop_self();
|
||||
/* Should never get here... */
|
||||
|
|
|
@ -54,7 +54,7 @@ void __init setup_kexec_cpu_down_mpic(void)
|
|||
static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary)
|
||||
{
|
||||
pseries_kexec_cpu_down(crash_shutdown, secondary);
|
||||
xics_teardown_cpu(secondary);
|
||||
xics_kexec_teardown_cpu(secondary);
|
||||
}
|
||||
|
||||
void __init setup_kexec_cpu_down_xics(void)
|
||||
|
|
|
@ -167,6 +167,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np)
|
|||
|
||||
if ((child = of_get_next_child(np, NULL))) {
|
||||
of_node_put(child);
|
||||
of_node_put(parent);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
|
|
@ -160,6 +160,46 @@ static inline void lpar_qirr_info(int n_cpu , u8 value)
|
|||
|
||||
/* High level handlers and init code */
|
||||
|
||||
static void xics_update_irq_servers(void)
|
||||
{
|
||||
int i, j;
|
||||
struct device_node *np;
|
||||
u32 ilen;
|
||||
const u32 *ireg, *isize;
|
||||
u32 hcpuid;
|
||||
|
||||
/* Find the server numbers for the boot cpu. */
|
||||
np = of_get_cpu_node(boot_cpuid, NULL);
|
||||
BUG_ON(!np);
|
||||
|
||||
ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
|
||||
if (!ireg) {
|
||||
of_node_put(np);
|
||||
return;
|
||||
}
|
||||
|
||||
i = ilen / sizeof(int);
|
||||
hcpuid = get_hard_smp_processor_id(boot_cpuid);
|
||||
|
||||
/* Global interrupt distribution server is specified in the last
|
||||
* entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
|
||||
* entry fom this property for current boot cpu id and use it as
|
||||
* default distribution server
|
||||
*/
|
||||
for (j = 0; j < i; j += 2) {
|
||||
if (ireg[j] == hcpuid) {
|
||||
default_server = hcpuid;
|
||||
default_distrib_server = ireg[j+1];
|
||||
|
||||
isize = of_get_property(np,
|
||||
"ibm,interrupt-server#-size", NULL);
|
||||
if (isize)
|
||||
interrupt_server_size = *isize;
|
||||
}
|
||||
}
|
||||
|
||||
of_node_put(np);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static int get_irq_server(unsigned int virq, unsigned int strict_check)
|
||||
|
@ -169,6 +209,9 @@ static int get_irq_server(unsigned int virq, unsigned int strict_check)
|
|||
cpumask_t cpumask = irq_desc[virq].affinity;
|
||||
cpumask_t tmp = CPU_MASK_NONE;
|
||||
|
||||
if (! cpu_isset(default_server, cpu_online_map))
|
||||
xics_update_irq_servers();
|
||||
|
||||
if (!distribute_irqs)
|
||||
return default_server;
|
||||
|
||||
|
@ -658,39 +701,11 @@ static void __init xics_setup_8259_cascade(void)
|
|||
set_irq_chained_handler(cascade, pseries_8259_cascade);
|
||||
}
|
||||
|
||||
static struct device_node *cpuid_to_of_node(int cpu)
|
||||
{
|
||||
struct device_node *np;
|
||||
u32 hcpuid = get_hard_smp_processor_id(cpu);
|
||||
|
||||
for_each_node_by_type(np, "cpu") {
|
||||
int i, len;
|
||||
const u32 *intserv;
|
||||
|
||||
intserv = of_get_property(np, "ibm,ppc-interrupt-server#s",
|
||||
&len);
|
||||
|
||||
if (!intserv)
|
||||
intserv = of_get_property(np, "reg", &len);
|
||||
|
||||
i = len / sizeof(u32);
|
||||
|
||||
while (i--)
|
||||
if (intserv[i] == hcpuid)
|
||||
return np;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void __init xics_init_IRQ(void)
|
||||
{
|
||||
int i, j;
|
||||
struct device_node *np;
|
||||
u32 ilen, indx = 0;
|
||||
const u32 *ireg, *isize;
|
||||
u32 indx = 0;
|
||||
int found = 0;
|
||||
u32 hcpuid;
|
||||
|
||||
ppc64_boot_msg(0x20, "XICS Init");
|
||||
|
||||
|
@ -709,34 +724,7 @@ void __init xics_init_IRQ(void)
|
|||
return;
|
||||
|
||||
xics_init_host();
|
||||
|
||||
/* Find the server numbers for the boot cpu. */
|
||||
np = cpuid_to_of_node(boot_cpuid);
|
||||
BUG_ON(!np);
|
||||
ireg = of_get_property(np, "ibm,ppc-interrupt-gserver#s", &ilen);
|
||||
if (!ireg)
|
||||
goto skip_gserver_check;
|
||||
i = ilen / sizeof(int);
|
||||
hcpuid = get_hard_smp_processor_id(boot_cpuid);
|
||||
|
||||
/* Global interrupt distribution server is specified in the last
|
||||
* entry of "ibm,ppc-interrupt-gserver#s" property. Get the last
|
||||
* entry fom this property for current boot cpu id and use it as
|
||||
* default distribution server
|
||||
*/
|
||||
for (j = 0; j < i; j += 2) {
|
||||
if (ireg[j] == hcpuid) {
|
||||
default_server = hcpuid;
|
||||
default_distrib_server = ireg[j+1];
|
||||
|
||||
isize = of_get_property(np,
|
||||
"ibm,interrupt-server#-size", NULL);
|
||||
if (isize)
|
||||
interrupt_server_size = *isize;
|
||||
}
|
||||
}
|
||||
skip_gserver_check:
|
||||
of_node_put(np);
|
||||
xics_update_irq_servers();
|
||||
|
||||
if (firmware_has_feature(FW_FEATURE_LPAR))
|
||||
ppc_md.get_irq = xics_get_irq_lpar;
|
||||
|
@ -775,11 +763,9 @@ void xics_request_IPIs(void)
|
|||
}
|
||||
#endif /* CONFIG_SMP */
|
||||
|
||||
void xics_teardown_cpu(int secondary)
|
||||
void xics_teardown_cpu()
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
unsigned int ipi;
|
||||
struct irq_desc *desc;
|
||||
|
||||
xics_set_cpu_priority(0);
|
||||
|
||||
|
@ -790,9 +776,17 @@ void xics_teardown_cpu(int secondary)
|
|||
lpar_qirr_info(cpu, 0xff);
|
||||
else
|
||||
direct_qirr_info(cpu, 0xff);
|
||||
}
|
||||
|
||||
void xics_kexec_teardown_cpu(int secondary)
|
||||
{
|
||||
unsigned int ipi;
|
||||
struct irq_desc *desc;
|
||||
|
||||
xics_teardown_cpu();
|
||||
|
||||
/*
|
||||
* we need to EOI the IPI if we got here from kexec down IPI
|
||||
* we need to EOI the IPI
|
||||
*
|
||||
* probably need to check all the other interrupts too
|
||||
* should we be flagging idle loop instead?
|
||||
|
@ -880,8 +874,8 @@ void xics_migrate_irqs_away(void)
|
|||
virq, cpu);
|
||||
|
||||
/* Reset affinity to all cpus */
|
||||
irq_desc[virq].affinity = CPU_MASK_ALL;
|
||||
desc->chip->set_affinity(virq, CPU_MASK_ALL);
|
||||
irq_desc[irq].affinity = CPU_MASK_ALL;
|
||||
unlock:
|
||||
spin_unlock_irqrestore(&desc->lock, flags);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
|
||||
extern void xics_init_IRQ(void);
|
||||
extern void xics_setup_cpu(void);
|
||||
extern void xics_teardown_cpu(int secondary);
|
||||
extern void xics_teardown_cpu(void);
|
||||
extern void xics_kexec_teardown_cpu(int secondary);
|
||||
extern void xics_cause_IPI(int cpu);
|
||||
extern void xics_request_IPIs(void);
|
||||
extern void xics_migrate_irqs_away(void);
|
||||
|
|
|
@ -137,5 +137,6 @@ void dcr_unmap(dcr_host_t host, unsigned int dcr_c)
|
|||
h.token = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dcr_unmap);
|
||||
|
||||
#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */
|
||||
#else /* defined(CONFIG_PPC_DCR_NATIVE) */
|
||||
DEFINE_SPINLOCK(dcr_ind_lock);
|
||||
#endif /* !defined(CONFIG_PPC_DCR_NATIVE) */
|
||||
|
|
|
@ -1342,7 +1342,7 @@ static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
|
|||
if (ret)
|
||||
goto unreg;
|
||||
|
||||
ret = platform_device_register(pdev);
|
||||
ret = platform_device_add(pdev);
|
||||
if (ret)
|
||||
goto unreg;
|
||||
|
||||
|
|
|
@ -174,15 +174,19 @@ int mpc8xx_pic_init(void)
|
|||
goto out;
|
||||
|
||||
siu_reg = ioremap(res.start, res.end - res.start + 1);
|
||||
if (siu_reg == NULL)
|
||||
return -EINVAL;
|
||||
if (siu_reg == NULL) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mpc8xx_pic_host = irq_alloc_host(of_node_get(np), IRQ_HOST_MAP_LINEAR,
|
||||
mpc8xx_pic_host = irq_alloc_host(np, IRQ_HOST_MAP_LINEAR,
|
||||
64, &mpc8xx_pic_host_ops, 64);
|
||||
if (mpc8xx_pic_host == NULL) {
|
||||
printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
return 0;
|
||||
|
||||
out:
|
||||
of_node_put(np);
|
||||
|
|
|
@ -66,7 +66,7 @@ phys_addr_t get_qe_base(void)
|
|||
{
|
||||
struct device_node *qe;
|
||||
unsigned int size;
|
||||
const void *prop;
|
||||
const u32 *prop;
|
||||
|
||||
if (qebase != -1)
|
||||
return qebase;
|
||||
|
@ -79,7 +79,8 @@ phys_addr_t get_qe_base(void)
|
|||
}
|
||||
|
||||
prop = of_get_property(qe, "reg", &size);
|
||||
qebase = of_translate_address(qe, prop);
|
||||
if (prop && size >= sizeof(*prop))
|
||||
qebase = of_translate_address(qe, prop);
|
||||
of_node_put(qe);
|
||||
|
||||
return qebase;
|
||||
|
@ -172,10 +173,9 @@ unsigned int get_brg_clk(void)
|
|||
}
|
||||
|
||||
prop = of_get_property(qe, "brg-frequency", &size);
|
||||
if (!prop || size != sizeof(*prop))
|
||||
return brg_clk;
|
||||
if (prop && size == sizeof(*prop))
|
||||
brg_clk = *prop;
|
||||
|
||||
brg_clk = *prop;
|
||||
of_node_put(qe);
|
||||
|
||||
return brg_clk;
|
||||
|
|
|
@ -1202,8 +1202,10 @@ static int __devexit ace_of_remove(struct of_device *op)
|
|||
}
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static struct of_device_id __devinit ace_of_match[] = {
|
||||
{ .compatible = "xilinx,xsysace", },
|
||||
static struct of_device_id ace_of_match[] __devinitdata = {
|
||||
{ .compatible = "xlnx,opb-sysace-1.00.b", },
|
||||
{ .compatible = "xlnx,opb-sysace-1.00.c", },
|
||||
{ .compatible = "xlnx,xps-sysace-1.00.a", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ace_of_match);
|
||||
|
|
|
@ -558,7 +558,7 @@ static struct cdrom_device_ops viocd_dops = {
|
|||
.capability = CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_SELECT_SPEED | CDC_SELECT_DISC | CDC_MULTI_SESSION | CDC_MCN | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO | CDC_RESET | CDC_DRIVE_STATUS | CDC_GENERIC_PACKET | CDC_CD_R | CDC_CD_RW | CDC_DVD | CDC_DVD_R | CDC_DVD_RAM | CDC_RAM
|
||||
};
|
||||
|
||||
static int __init find_capability(const char *type)
|
||||
static int find_capability(const char *type)
|
||||
{
|
||||
struct capability_entry *entry;
|
||||
|
||||
|
|
|
@ -830,6 +830,16 @@ config DTLK
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called dtlk.
|
||||
|
||||
config XILINX_HWICAP
|
||||
tristate "Xilinx HWICAP Support"
|
||||
depends on XILINX_VIRTEX
|
||||
help
|
||||
This option enables support for Xilinx Internal Configuration
|
||||
Access Port (ICAP) driver. The ICAP is used on Xilinx Virtex
|
||||
FPGA platforms to partially reconfigure the FPGA at runtime.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config R3964
|
||||
tristate "Siemens R3964 line discipline"
|
||||
---help---
|
||||
|
|
|
@ -76,6 +76,7 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o
|
|||
obj-$(CONFIG_SGI_DS1286) += ds1286.o
|
||||
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
|
||||
obj-$(CONFIG_DS1302) += ds1302.o
|
||||
obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/
|
||||
ifeq ($(CONFIG_GENERIC_NVRAM),y)
|
||||
obj-$(CONFIG_NVRAM) += generic_nvram.o
|
||||
else
|
||||
|
|
7
drivers/char/xilinx_hwicap/Makefile
Normal file
7
drivers/char/xilinx_hwicap/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
#
|
||||
# Makefile for the Xilinx OPB hwicap driver
|
||||
#
|
||||
|
||||
obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap_m.o
|
||||
|
||||
xilinx_hwicap_m-y := xilinx_hwicap.o fifo_icap.o buffer_icap.o
|
380
drivers/char/xilinx_hwicap/buffer_icap.c
Normal file
380
drivers/char/xilinx_hwicap/buffer_icap.c
Normal file
|
@ -0,0 +1,380 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Author: Xilinx, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
|
||||
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
|
||||
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
|
||||
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
|
||||
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
|
||||
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
|
||||
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
|
||||
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
|
||||
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
|
||||
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Xilinx products are not intended for use in life support appliances,
|
||||
* devices, or systems. Use in such applications is expressly prohibited.
|
||||
*
|
||||
* (c) Copyright 2003-2008 Xilinx Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 "buffer_icap.h"
|
||||
|
||||
/* Indicates how many bytes will fit in a buffer. (1 BRAM) */
|
||||
#define XHI_MAX_BUFFER_BYTES 2048
|
||||
#define XHI_MAX_BUFFER_INTS (XHI_MAX_BUFFER_BYTES >> 2)
|
||||
|
||||
/* File access and error constants */
|
||||
#define XHI_DEVICE_READ_ERROR -1
|
||||
#define XHI_DEVICE_WRITE_ERROR -2
|
||||
#define XHI_BUFFER_OVERFLOW_ERROR -3
|
||||
|
||||
#define XHI_DEVICE_READ 0x1
|
||||
#define XHI_DEVICE_WRITE 0x0
|
||||
|
||||
/* Constants for checking transfer status */
|
||||
#define XHI_CYCLE_DONE 0
|
||||
#define XHI_CYCLE_EXECUTING 1
|
||||
|
||||
/* buffer_icap register offsets */
|
||||
|
||||
/* Size of transfer, read & write */
|
||||
#define XHI_SIZE_REG_OFFSET 0x800L
|
||||
/* offset into bram, read & write */
|
||||
#define XHI_BRAM_OFFSET_REG_OFFSET 0x804L
|
||||
/* Read not Configure, direction of transfer. Write only */
|
||||
#define XHI_RNC_REG_OFFSET 0x808L
|
||||
/* Indicates transfer complete. Read only */
|
||||
#define XHI_STATUS_REG_OFFSET 0x80CL
|
||||
|
||||
/* Constants for setting the RNC register */
|
||||
#define XHI_CONFIGURE 0x0UL
|
||||
#define XHI_READBACK 0x1UL
|
||||
|
||||
/* Constants for the Done register */
|
||||
#define XHI_NOT_FINISHED 0x0UL
|
||||
#define XHI_FINISHED 0x1UL
|
||||
|
||||
#define XHI_BUFFER_START 0
|
||||
|
||||
/**
|
||||
* buffer_icap_get_status: Get the contents of the status register.
|
||||
* @parameter base_address: is the base address of the device
|
||||
*
|
||||
* The status register contains the ICAP status and the done bit.
|
||||
*
|
||||
* D8 - cfgerr
|
||||
* D7 - dalign
|
||||
* D6 - rip
|
||||
* D5 - in_abort_l
|
||||
* D4 - Always 1
|
||||
* D3 - Always 1
|
||||
* D2 - Always 1
|
||||
* D1 - Always 1
|
||||
* D0 - Done bit
|
||||
**/
|
||||
static inline u32 buffer_icap_get_status(void __iomem *base_address)
|
||||
{
|
||||
return in_be32(base_address + XHI_STATUS_REG_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer_icap_get_bram: Reads data from the storage buffer bram.
|
||||
* @parameter base_address: contains the base address of the component.
|
||||
* @parameter offset: The word offset from which the data should be read.
|
||||
*
|
||||
* A bram is used as a configuration memory cache. One frame of data can
|
||||
* be stored in this "storage buffer".
|
||||
**/
|
||||
static inline u32 buffer_icap_get_bram(void __iomem *base_address,
|
||||
u32 offset)
|
||||
{
|
||||
return in_be32(base_address + (offset << 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer_icap_busy: Return true if the icap device is busy
|
||||
* @parameter base_address: is the base address of the device
|
||||
*
|
||||
* The queries the low order bit of the status register, which
|
||||
* indicates whether the current configuration or readback operation
|
||||
* has completed.
|
||||
**/
|
||||
static inline bool buffer_icap_busy(void __iomem *base_address)
|
||||
{
|
||||
return (buffer_icap_get_status(base_address) & 1) == XHI_NOT_FINISHED;
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer_icap_busy: Return true if the icap device is not busy
|
||||
* @parameter base_address: is the base address of the device
|
||||
*
|
||||
* The queries the low order bit of the status register, which
|
||||
* indicates whether the current configuration or readback operation
|
||||
* has completed.
|
||||
**/
|
||||
static inline bool buffer_icap_done(void __iomem *base_address)
|
||||
{
|
||||
return (buffer_icap_get_status(base_address) & 1) == XHI_FINISHED;
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer_icap_set_size: Set the size register.
|
||||
* @parameter base_address: is the base address of the device
|
||||
* @parameter data: The size in bytes.
|
||||
*
|
||||
* The size register holds the number of 8 bit bytes to transfer between
|
||||
* bram and the icap (or icap to bram).
|
||||
**/
|
||||
static inline void buffer_icap_set_size(void __iomem *base_address,
|
||||
u32 data)
|
||||
{
|
||||
out_be32(base_address + XHI_SIZE_REG_OFFSET, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer_icap_mSetoffsetReg: Set the bram offset register.
|
||||
* @parameter base_address: contains the base address of the device.
|
||||
* @parameter data: is the value to be written to the data register.
|
||||
*
|
||||
* The bram offset register holds the starting bram address to transfer
|
||||
* data from during configuration or write data to during readback.
|
||||
**/
|
||||
static inline void buffer_icap_set_offset(void __iomem *base_address,
|
||||
u32 data)
|
||||
{
|
||||
out_be32(base_address + XHI_BRAM_OFFSET_REG_OFFSET, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer_icap_set_rnc: Set the RNC (Readback not Configure) register.
|
||||
* @parameter base_address: contains the base address of the device.
|
||||
* @parameter data: is the value to be written to the data register.
|
||||
*
|
||||
* The RNC register determines the direction of the data transfer. It
|
||||
* controls whether a configuration or readback take place. Writing to
|
||||
* this register initiates the transfer. A value of 1 initiates a
|
||||
* readback while writing a value of 0 initiates a configuration.
|
||||
**/
|
||||
static inline void buffer_icap_set_rnc(void __iomem *base_address,
|
||||
u32 data)
|
||||
{
|
||||
out_be32(base_address + XHI_RNC_REG_OFFSET, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer_icap_set_bram: Write data to the storage buffer bram.
|
||||
* @parameter base_address: contains the base address of the component.
|
||||
* @parameter offset: The word offset at which the data should be written.
|
||||
* @parameter data: The value to be written to the bram offset.
|
||||
*
|
||||
* A bram is used as a configuration memory cache. One frame of data can
|
||||
* be stored in this "storage buffer".
|
||||
**/
|
||||
static inline void buffer_icap_set_bram(void __iomem *base_address,
|
||||
u32 offset, u32 data)
|
||||
{
|
||||
out_be32(base_address + (offset << 2), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer_icap_device_read: Transfer bytes from ICAP to the storage buffer.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
* @parameter offset: The storage buffer start address.
|
||||
* @parameter count: The number of words (32 bit) to read from the
|
||||
* device (ICAP).
|
||||
**/
|
||||
static int buffer_icap_device_read(struct hwicap_drvdata *drvdata,
|
||||
u32 offset, u32 count)
|
||||
{
|
||||
|
||||
s32 retries = 0;
|
||||
void __iomem *base_address = drvdata->base_address;
|
||||
|
||||
if (buffer_icap_busy(base_address))
|
||||
return -EBUSY;
|
||||
|
||||
if ((offset + count) > XHI_MAX_BUFFER_INTS)
|
||||
return -EINVAL;
|
||||
|
||||
/* setSize count*4 to get bytes. */
|
||||
buffer_icap_set_size(base_address, (count << 2));
|
||||
buffer_icap_set_offset(base_address, offset);
|
||||
buffer_icap_set_rnc(base_address, XHI_READBACK);
|
||||
|
||||
while (buffer_icap_busy(base_address)) {
|
||||
retries++;
|
||||
if (retries > XHI_MAX_RETRIES)
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* buffer_icap_device_write: Transfer bytes from ICAP to the storage buffer.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
* @parameter offset: The storage buffer start address.
|
||||
* @parameter count: The number of words (32 bit) to read from the
|
||||
* device (ICAP).
|
||||
**/
|
||||
static int buffer_icap_device_write(struct hwicap_drvdata *drvdata,
|
||||
u32 offset, u32 count)
|
||||
{
|
||||
|
||||
s32 retries = 0;
|
||||
void __iomem *base_address = drvdata->base_address;
|
||||
|
||||
if (buffer_icap_busy(base_address))
|
||||
return -EBUSY;
|
||||
|
||||
if ((offset + count) > XHI_MAX_BUFFER_INTS)
|
||||
return -EINVAL;
|
||||
|
||||
/* setSize count*4 to get bytes. */
|
||||
buffer_icap_set_size(base_address, count << 2);
|
||||
buffer_icap_set_offset(base_address, offset);
|
||||
buffer_icap_set_rnc(base_address, XHI_CONFIGURE);
|
||||
|
||||
while (buffer_icap_busy(base_address)) {
|
||||
retries++;
|
||||
if (retries > XHI_MAX_RETRIES)
|
||||
return -EBUSY;
|
||||
}
|
||||
return 0;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* buffer_icap_reset: Reset the logic of the icap device.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
*
|
||||
* Writing to the status register resets the ICAP logic in an internal
|
||||
* version of the core. For the version of the core published in EDK,
|
||||
* this is a noop.
|
||||
**/
|
||||
void buffer_icap_reset(struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
out_be32(drvdata->base_address + XHI_STATUS_REG_OFFSET, 0xFEFE);
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer_icap_set_configuration: Load a partial bitstream from system memory.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
* @parameter data: Kernel address of the partial bitstream.
|
||||
* @parameter size: the size of the partial bitstream in 32 bit words.
|
||||
**/
|
||||
int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
|
||||
u32 size)
|
||||
{
|
||||
int status;
|
||||
s32 buffer_count = 0;
|
||||
s32 num_writes = 0;
|
||||
bool dirty = 0;
|
||||
u32 i;
|
||||
void __iomem *base_address = drvdata->base_address;
|
||||
|
||||
/* Loop through all the data */
|
||||
for (i = 0, buffer_count = 0; i < size; i++) {
|
||||
|
||||
/* Copy data to bram */
|
||||
buffer_icap_set_bram(base_address, buffer_count, data[i]);
|
||||
dirty = 1;
|
||||
|
||||
if (buffer_count < XHI_MAX_BUFFER_INTS - 1) {
|
||||
buffer_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Write data to ICAP */
|
||||
status = buffer_icap_device_write(
|
||||
drvdata,
|
||||
XHI_BUFFER_START,
|
||||
XHI_MAX_BUFFER_INTS);
|
||||
if (status != 0) {
|
||||
/* abort. */
|
||||
buffer_icap_reset(drvdata);
|
||||
return status;
|
||||
}
|
||||
|
||||
buffer_count = 0;
|
||||
num_writes++;
|
||||
dirty = 0;
|
||||
}
|
||||
|
||||
/* Write unwritten data to ICAP */
|
||||
if (dirty) {
|
||||
/* Write data to ICAP */
|
||||
status = buffer_icap_device_write(drvdata, XHI_BUFFER_START,
|
||||
buffer_count);
|
||||
if (status != 0) {
|
||||
/* abort. */
|
||||
buffer_icap_reset(drvdata);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* buffer_icap_get_configuration: Read configuration data from the device.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
* @parameter data: Address of the data representing the partial bitstream
|
||||
* @parameter size: the size of the partial bitstream in 32 bit words.
|
||||
**/
|
||||
int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
|
||||
u32 size)
|
||||
{
|
||||
int status;
|
||||
s32 buffer_count = 0;
|
||||
s32 read_count = 0;
|
||||
u32 i;
|
||||
void __iomem *base_address = drvdata->base_address;
|
||||
|
||||
/* Loop through all the data */
|
||||
for (i = 0, buffer_count = XHI_MAX_BUFFER_INTS; i < size; i++) {
|
||||
if (buffer_count == XHI_MAX_BUFFER_INTS) {
|
||||
u32 words_remaining = size - i;
|
||||
u32 words_to_read =
|
||||
words_remaining <
|
||||
XHI_MAX_BUFFER_INTS ? words_remaining :
|
||||
XHI_MAX_BUFFER_INTS;
|
||||
|
||||
/* Read data from ICAP */
|
||||
status = buffer_icap_device_read(
|
||||
drvdata,
|
||||
XHI_BUFFER_START,
|
||||
words_to_read);
|
||||
if (status != 0) {
|
||||
/* abort. */
|
||||
buffer_icap_reset(drvdata);
|
||||
return status;
|
||||
}
|
||||
|
||||
buffer_count = 0;
|
||||
read_count++;
|
||||
}
|
||||
|
||||
/* Copy data from bram */
|
||||
data[i] = buffer_icap_get_bram(base_address, buffer_count);
|
||||
buffer_count++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
57
drivers/char/xilinx_hwicap/buffer_icap.h
Normal file
57
drivers/char/xilinx_hwicap/buffer_icap.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Author: Xilinx, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
|
||||
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
|
||||
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
|
||||
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
|
||||
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
|
||||
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
|
||||
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
|
||||
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
|
||||
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
|
||||
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Xilinx products are not intended for use in life support appliances,
|
||||
* devices, or systems. Use in such applications is expressly prohibited.
|
||||
*
|
||||
* (c) Copyright 2003-2008 Xilinx Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef XILINX_BUFFER_ICAP_H_ /* prevent circular inclusions */
|
||||
#define XILINX_BUFFER_ICAP_H_ /* by using protection macros */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include "xilinx_hwicap.h"
|
||||
|
||||
void buffer_icap_reset(struct hwicap_drvdata *drvdata);
|
||||
|
||||
/* Loads a partial bitstream from system memory. */
|
||||
int buffer_icap_set_configuration(struct hwicap_drvdata *drvdata, u32 *data,
|
||||
u32 Size);
|
||||
|
||||
/* Loads a partial bitstream from system memory. */
|
||||
int buffer_icap_get_configuration(struct hwicap_drvdata *drvdata, u32 *data,
|
||||
u32 Size);
|
||||
|
||||
#endif
|
381
drivers/char/xilinx_hwicap/fifo_icap.c
Normal file
381
drivers/char/xilinx_hwicap/fifo_icap.c
Normal file
|
@ -0,0 +1,381 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Author: Xilinx, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
|
||||
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
|
||||
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
|
||||
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
|
||||
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
|
||||
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
|
||||
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
|
||||
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
|
||||
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
|
||||
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Xilinx products are not intended for use in life support appliances,
|
||||
* devices, or systems. Use in such applications is expressly prohibited.
|
||||
*
|
||||
* (c) Copyright 2007-2008 Xilinx Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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 "fifo_icap.h"
|
||||
|
||||
/* Register offsets for the XHwIcap device. */
|
||||
#define XHI_GIER_OFFSET 0x1C /* Device Global Interrupt Enable Reg */
|
||||
#define XHI_IPISR_OFFSET 0x20 /* Interrupt Status Register */
|
||||
#define XHI_IPIER_OFFSET 0x28 /* Interrupt Enable Register */
|
||||
#define XHI_WF_OFFSET 0x100 /* Write FIFO */
|
||||
#define XHI_RF_OFFSET 0x104 /* Read FIFO */
|
||||
#define XHI_SZ_OFFSET 0x108 /* Size Register */
|
||||
#define XHI_CR_OFFSET 0x10C /* Control Register */
|
||||
#define XHI_SR_OFFSET 0x110 /* Status Register */
|
||||
#define XHI_WFV_OFFSET 0x114 /* Write FIFO Vacancy Register */
|
||||
#define XHI_RFO_OFFSET 0x118 /* Read FIFO Occupancy Register */
|
||||
|
||||
/* Device Global Interrupt Enable Register (GIER) bit definitions */
|
||||
|
||||
#define XHI_GIER_GIE_MASK 0x80000000 /* Global Interrupt enable Mask */
|
||||
|
||||
/**
|
||||
* HwIcap Device Interrupt Status/Enable Registers
|
||||
*
|
||||
* Interrupt Status Register (IPISR) : This register holds the
|
||||
* interrupt status flags for the device. These bits are toggle on
|
||||
* write.
|
||||
*
|
||||
* Interrupt Enable Register (IPIER) : This register is used to enable
|
||||
* interrupt sources for the device.
|
||||
* Writing a '1' to a bit enables the corresponding interrupt.
|
||||
* Writing a '0' to a bit disables the corresponding interrupt.
|
||||
*
|
||||
* IPISR/IPIER registers have the same bit definitions and are only defined
|
||||
* once.
|
||||
*/
|
||||
#define XHI_IPIXR_RFULL_MASK 0x00000008 /* Read FIFO Full */
|
||||
#define XHI_IPIXR_WEMPTY_MASK 0x00000004 /* Write FIFO Empty */
|
||||
#define XHI_IPIXR_RDP_MASK 0x00000002 /* Read FIFO half full */
|
||||
#define XHI_IPIXR_WRP_MASK 0x00000001 /* Write FIFO half full */
|
||||
#define XHI_IPIXR_ALL_MASK 0x0000000F /* Mask of all interrupts */
|
||||
|
||||
/* Control Register (CR) */
|
||||
#define XHI_CR_SW_RESET_MASK 0x00000008 /* SW Reset Mask */
|
||||
#define XHI_CR_FIFO_CLR_MASK 0x00000004 /* FIFO Clear Mask */
|
||||
#define XHI_CR_READ_MASK 0x00000002 /* Read from ICAP to FIFO */
|
||||
#define XHI_CR_WRITE_MASK 0x00000001 /* Write from FIFO to ICAP */
|
||||
|
||||
/* Status Register (SR) */
|
||||
#define XHI_SR_CFGERR_N_MASK 0x00000100 /* Config Error Mask */
|
||||
#define XHI_SR_DALIGN_MASK 0x00000080 /* Data Alignment Mask */
|
||||
#define XHI_SR_RIP_MASK 0x00000040 /* Read back Mask */
|
||||
#define XHI_SR_IN_ABORT_N_MASK 0x00000020 /* Select Map Abort Mask */
|
||||
#define XHI_SR_DONE_MASK 0x00000001 /* Done bit Mask */
|
||||
|
||||
|
||||
#define XHI_WFO_MAX_VACANCY 1024 /* Max Write FIFO Vacancy, in words */
|
||||
#define XHI_RFO_MAX_OCCUPANCY 256 /* Max Read FIFO Occupancy, in words */
|
||||
/* The maximum amount we can request from fifo_icap_get_configuration
|
||||
at once, in bytes. */
|
||||
#define XHI_MAX_READ_TRANSACTION_WORDS 0xFFF
|
||||
|
||||
|
||||
/**
|
||||
* fifo_icap_fifo_write: Write data to the write FIFO.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
* @parameter data: the 32-bit value to be written to the FIFO.
|
||||
*
|
||||
* This function will silently fail if the fifo is full.
|
||||
**/
|
||||
static inline void fifo_icap_fifo_write(struct hwicap_drvdata *drvdata,
|
||||
u32 data)
|
||||
{
|
||||
dev_dbg(drvdata->dev, "fifo_write: %x\n", data);
|
||||
out_be32(drvdata->base_address + XHI_WF_OFFSET, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo_icap_fifo_read: Read data from the Read FIFO.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
*
|
||||
* This function will silently fail if the fifo is empty.
|
||||
**/
|
||||
static inline u32 fifo_icap_fifo_read(struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
u32 data = in_be32(drvdata->base_address + XHI_RF_OFFSET);
|
||||
dev_dbg(drvdata->dev, "fifo_read: %x\n", data);
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo_icap_set_read_size: Set the the size register.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
* @parameter data: the size of the following read transaction, in words.
|
||||
**/
|
||||
static inline void fifo_icap_set_read_size(struct hwicap_drvdata *drvdata,
|
||||
u32 data)
|
||||
{
|
||||
out_be32(drvdata->base_address + XHI_SZ_OFFSET, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo_icap_start_config: Initiate a configuration (write) to the device.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
**/
|
||||
static inline void fifo_icap_start_config(struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_WRITE_MASK);
|
||||
dev_dbg(drvdata->dev, "configuration started\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo_icap_start_readback: Initiate a readback from the device.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
**/
|
||||
static inline void fifo_icap_start_readback(struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
out_be32(drvdata->base_address + XHI_CR_OFFSET, XHI_CR_READ_MASK);
|
||||
dev_dbg(drvdata->dev, "readback started\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo_icap_busy: Return true if the ICAP is still processing a transaction.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
**/
|
||||
static inline u32 fifo_icap_busy(struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
u32 status = in_be32(drvdata->base_address + XHI_SR_OFFSET);
|
||||
dev_dbg(drvdata->dev, "Getting status = %x\n", status);
|
||||
return (status & XHI_SR_DONE_MASK) ? 0 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo_icap_write_fifo_vacancy: Query the write fifo available space.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
*
|
||||
* Return the number of words that can be safely pushed into the write fifo.
|
||||
**/
|
||||
static inline u32 fifo_icap_write_fifo_vacancy(
|
||||
struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
return in_be32(drvdata->base_address + XHI_WFV_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo_icap_read_fifo_occupancy: Query the read fifo available data.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
*
|
||||
* Return the number of words that can be safely read from the read fifo.
|
||||
**/
|
||||
static inline u32 fifo_icap_read_fifo_occupancy(
|
||||
struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
return in_be32(drvdata->base_address + XHI_RFO_OFFSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo_icap_set_configuration: Send configuration data to the ICAP.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
* @parameter frame_buffer: a pointer to the data to be written to the
|
||||
* ICAP device.
|
||||
* @parameter num_words: the number of words (32 bit) to write to the ICAP
|
||||
* device.
|
||||
|
||||
* This function writes the given user data to the Write FIFO in
|
||||
* polled mode and starts the transfer of the data to
|
||||
* the ICAP device.
|
||||
**/
|
||||
int fifo_icap_set_configuration(struct hwicap_drvdata *drvdata,
|
||||
u32 *frame_buffer, u32 num_words)
|
||||
{
|
||||
|
||||
u32 write_fifo_vacancy = 0;
|
||||
u32 retries = 0;
|
||||
u32 remaining_words;
|
||||
|
||||
dev_dbg(drvdata->dev, "fifo_set_configuration\n");
|
||||
|
||||
/*
|
||||
* Check if the ICAP device is Busy with the last Read/Write
|
||||
*/
|
||||
if (fifo_icap_busy(drvdata))
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* Set up the buffer pointer and the words to be transferred.
|
||||
*/
|
||||
remaining_words = num_words;
|
||||
|
||||
while (remaining_words > 0) {
|
||||
/*
|
||||
* Wait until we have some data in the fifo.
|
||||
*/
|
||||
while (write_fifo_vacancy == 0) {
|
||||
write_fifo_vacancy =
|
||||
fifo_icap_write_fifo_vacancy(drvdata);
|
||||
retries++;
|
||||
if (retries > XHI_MAX_RETRIES)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write data into the Write FIFO.
|
||||
*/
|
||||
while ((write_fifo_vacancy != 0) &&
|
||||
(remaining_words > 0)) {
|
||||
fifo_icap_fifo_write(drvdata, *frame_buffer);
|
||||
|
||||
remaining_words--;
|
||||
write_fifo_vacancy--;
|
||||
frame_buffer++;
|
||||
}
|
||||
/* Start pushing whatever is in the FIFO into the ICAP. */
|
||||
fifo_icap_start_config(drvdata);
|
||||
}
|
||||
|
||||
/* Wait until the write has finished. */
|
||||
while (fifo_icap_busy(drvdata)) {
|
||||
retries++;
|
||||
if (retries > XHI_MAX_RETRIES)
|
||||
break;
|
||||
}
|
||||
|
||||
dev_dbg(drvdata->dev, "done fifo_set_configuration\n");
|
||||
|
||||
/*
|
||||
* If the requested number of words have not been read from
|
||||
* the device then indicate failure.
|
||||
*/
|
||||
if (remaining_words != 0)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo_icap_get_configuration: Read configuration data from the device.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
* @parameter data: Address of the data representing the partial bitstream
|
||||
* @parameter size: the size of the partial bitstream in 32 bit words.
|
||||
*
|
||||
* This function reads the specified number of words from the ICAP device in
|
||||
* the polled mode.
|
||||
*/
|
||||
int fifo_icap_get_configuration(struct hwicap_drvdata *drvdata,
|
||||
u32 *frame_buffer, u32 num_words)
|
||||
{
|
||||
|
||||
u32 read_fifo_occupancy = 0;
|
||||
u32 retries = 0;
|
||||
u32 *data = frame_buffer;
|
||||
u32 remaining_words;
|
||||
u32 words_to_read;
|
||||
|
||||
dev_dbg(drvdata->dev, "fifo_get_configuration\n");
|
||||
|
||||
/*
|
||||
* Check if the ICAP device is Busy with the last Write/Read
|
||||
*/
|
||||
if (fifo_icap_busy(drvdata))
|
||||
return -EBUSY;
|
||||
|
||||
remaining_words = num_words;
|
||||
|
||||
while (remaining_words > 0) {
|
||||
words_to_read = remaining_words;
|
||||
/* The hardware has a limit on the number of words
|
||||
that can be read at one time. */
|
||||
if (words_to_read > XHI_MAX_READ_TRANSACTION_WORDS)
|
||||
words_to_read = XHI_MAX_READ_TRANSACTION_WORDS;
|
||||
|
||||
remaining_words -= words_to_read;
|
||||
|
||||
fifo_icap_set_read_size(drvdata, words_to_read);
|
||||
fifo_icap_start_readback(drvdata);
|
||||
|
||||
while (words_to_read > 0) {
|
||||
/* Wait until we have some data in the fifo. */
|
||||
while (read_fifo_occupancy == 0) {
|
||||
read_fifo_occupancy =
|
||||
fifo_icap_read_fifo_occupancy(drvdata);
|
||||
retries++;
|
||||
if (retries > XHI_MAX_RETRIES)
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (read_fifo_occupancy > words_to_read)
|
||||
read_fifo_occupancy = words_to_read;
|
||||
|
||||
words_to_read -= read_fifo_occupancy;
|
||||
|
||||
/* Read the data from the Read FIFO. */
|
||||
while (read_fifo_occupancy != 0) {
|
||||
*data++ = fifo_icap_fifo_read(drvdata);
|
||||
read_fifo_occupancy--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dev_dbg(drvdata->dev, "done fifo_get_configuration\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer_icap_reset: Reset the logic of the icap device.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
*
|
||||
* This function forces the software reset of the complete HWICAP device.
|
||||
* All the registers will return to the default value and the FIFO is also
|
||||
* flushed as a part of this software reset.
|
||||
*/
|
||||
void fifo_icap_reset(struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
u32 reg_data;
|
||||
/*
|
||||
* Reset the device by setting/clearing the RESET bit in the
|
||||
* Control Register.
|
||||
*/
|
||||
reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);
|
||||
|
||||
out_be32(drvdata->base_address + XHI_CR_OFFSET,
|
||||
reg_data | XHI_CR_SW_RESET_MASK);
|
||||
|
||||
out_be32(drvdata->base_address + XHI_CR_OFFSET,
|
||||
reg_data & (~XHI_CR_SW_RESET_MASK));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* fifo_icap_flush_fifo: This function flushes the FIFOs in the device.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
*/
|
||||
void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
u32 reg_data;
|
||||
/*
|
||||
* Flush the FIFO by setting/clearing the FIFO Clear bit in the
|
||||
* Control Register.
|
||||
*/
|
||||
reg_data = in_be32(drvdata->base_address + XHI_CR_OFFSET);
|
||||
|
||||
out_be32(drvdata->base_address + XHI_CR_OFFSET,
|
||||
reg_data | XHI_CR_FIFO_CLR_MASK);
|
||||
|
||||
out_be32(drvdata->base_address + XHI_CR_OFFSET,
|
||||
reg_data & (~XHI_CR_FIFO_CLR_MASK));
|
||||
}
|
||||
|
62
drivers/char/xilinx_hwicap/fifo_icap.h
Normal file
62
drivers/char/xilinx_hwicap/fifo_icap.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Author: Xilinx, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
|
||||
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
|
||||
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
|
||||
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
|
||||
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
|
||||
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
|
||||
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
|
||||
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
|
||||
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
|
||||
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Xilinx products are not intended for use in life support appliances,
|
||||
* devices, or systems. Use in such applications is expressly prohibited.
|
||||
*
|
||||
* (c) Copyright 2007-2008 Xilinx Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef XILINX_FIFO_ICAP_H_ /* prevent circular inclusions */
|
||||
#define XILINX_FIFO_ICAP_H_ /* by using protection macros */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include "xilinx_hwicap.h"
|
||||
|
||||
/* Reads integers from the device into the storage buffer. */
|
||||
int fifo_icap_get_configuration(
|
||||
struct hwicap_drvdata *drvdata,
|
||||
u32 *FrameBuffer,
|
||||
u32 NumWords);
|
||||
|
||||
/* Writes integers to the device from the storage buffer. */
|
||||
int fifo_icap_set_configuration(
|
||||
struct hwicap_drvdata *drvdata,
|
||||
u32 *FrameBuffer,
|
||||
u32 NumWords);
|
||||
|
||||
void fifo_icap_reset(struct hwicap_drvdata *drvdata);
|
||||
void fifo_icap_flush_fifo(struct hwicap_drvdata *drvdata);
|
||||
|
||||
#endif
|
904
drivers/char/xilinx_hwicap/xilinx_hwicap.c
Normal file
904
drivers/char/xilinx_hwicap/xilinx_hwicap.c
Normal file
|
@ -0,0 +1,904 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Author: Xilinx, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
|
||||
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
|
||||
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
|
||||
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
|
||||
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
|
||||
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
|
||||
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
|
||||
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
|
||||
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
|
||||
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Xilinx products are not intended for use in life support appliances,
|
||||
* devices, or systems. Use in such applications is expressly prohibited.
|
||||
*
|
||||
* (c) Copyright 2002 Xilinx Inc., Systems Engineering Group
|
||||
* (c) Copyright 2004 Xilinx Inc., Systems Engineering Group
|
||||
* (c) Copyright 2007-2008 Xilinx Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* This is the code behind /dev/xilinx_icap -- it allows a user-space
|
||||
* application to use the Xilinx ICAP subsystem.
|
||||
*
|
||||
* The following operations are possible:
|
||||
*
|
||||
* open open the port and initialize for access.
|
||||
* release release port
|
||||
* write Write a bitstream to the configuration processor.
|
||||
* read Read a data stream from the configuration processor.
|
||||
*
|
||||
* After being opened, the port is initialized and accessed to avoid a
|
||||
* corrupted first read which may occur with some hardware. The port
|
||||
* is left in a desynched state, requiring that a synch sequence be
|
||||
* transmitted before any valid configuration data. A user will have
|
||||
* exclusive access to the device while it remains open, and the state
|
||||
* of the ICAP cannot be guaranteed after the device is closed. Note
|
||||
* that a complete reset of the core and the state of the ICAP cannot
|
||||
* be performed on many versions of the cores, hence users of this
|
||||
* device should avoid making inconsistent accesses to the device. In
|
||||
* particular, accessing the read interface, without first generating
|
||||
* a write containing a readback packet can leave the ICAP in an
|
||||
* inaccessible state.
|
||||
*
|
||||
* Note that in order to use the read interface, it is first necessary
|
||||
* to write a request packet to the write interface. i.e., it is not
|
||||
* possible to simply readback the bitstream (or any configuration
|
||||
* bits) from a device without specifically requesting them first.
|
||||
* The code to craft such packets is intended to be part of the
|
||||
* user-space application code that uses this device. The simplest
|
||||
* way to use this interface is simply:
|
||||
*
|
||||
* cp foo.bit /dev/xilinx_icap
|
||||
*
|
||||
* Note that unless foo.bit is an appropriately constructed partial
|
||||
* bitstream, this has a high likelyhood of overwriting the design
|
||||
* currently programmed in the FPGA.
|
||||
*/
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <asm/semaphore.h>
|
||||
#include <linux/sysctl.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/* For open firmware. */
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#endif
|
||||
|
||||
#include "xilinx_hwicap.h"
|
||||
#include "buffer_icap.h"
|
||||
#include "fifo_icap.h"
|
||||
|
||||
#define DRIVER_NAME "xilinx_icap"
|
||||
|
||||
#define HWICAP_REGS (0x10000)
|
||||
|
||||
/* dynamically allocate device number */
|
||||
static int xhwicap_major;
|
||||
static int xhwicap_minor;
|
||||
#define HWICAP_DEVICES 1
|
||||
|
||||
module_param(xhwicap_major, int, S_IRUGO);
|
||||
module_param(xhwicap_minor, int, S_IRUGO);
|
||||
|
||||
/* An array, which is set to true when the device is registered. */
|
||||
static bool probed_devices[HWICAP_DEVICES];
|
||||
|
||||
static struct class *icap_class;
|
||||
|
||||
#define UNIMPLEMENTED 0xFFFF
|
||||
|
||||
static const struct config_registers v2_config_registers = {
|
||||
.CRC = 0,
|
||||
.FAR = 1,
|
||||
.FDRI = 2,
|
||||
.FDRO = 3,
|
||||
.CMD = 4,
|
||||
.CTL = 5,
|
||||
.MASK = 6,
|
||||
.STAT = 7,
|
||||
.LOUT = 8,
|
||||
.COR = 9,
|
||||
.MFWR = 10,
|
||||
.FLR = 11,
|
||||
.KEY = 12,
|
||||
.CBC = 13,
|
||||
.IDCODE = 14,
|
||||
.AXSS = UNIMPLEMENTED,
|
||||
.C0R_1 = UNIMPLEMENTED,
|
||||
.CSOB = UNIMPLEMENTED,
|
||||
.WBSTAR = UNIMPLEMENTED,
|
||||
.TIMER = UNIMPLEMENTED,
|
||||
.BOOTSTS = UNIMPLEMENTED,
|
||||
.CTL_1 = UNIMPLEMENTED,
|
||||
};
|
||||
|
||||
static const struct config_registers v4_config_registers = {
|
||||
.CRC = 0,
|
||||
.FAR = 1,
|
||||
.FDRI = 2,
|
||||
.FDRO = 3,
|
||||
.CMD = 4,
|
||||
.CTL = 5,
|
||||
.MASK = 6,
|
||||
.STAT = 7,
|
||||
.LOUT = 8,
|
||||
.COR = 9,
|
||||
.MFWR = 10,
|
||||
.FLR = UNIMPLEMENTED,
|
||||
.KEY = UNIMPLEMENTED,
|
||||
.CBC = 11,
|
||||
.IDCODE = 12,
|
||||
.AXSS = 13,
|
||||
.C0R_1 = UNIMPLEMENTED,
|
||||
.CSOB = UNIMPLEMENTED,
|
||||
.WBSTAR = UNIMPLEMENTED,
|
||||
.TIMER = UNIMPLEMENTED,
|
||||
.BOOTSTS = UNIMPLEMENTED,
|
||||
.CTL_1 = UNIMPLEMENTED,
|
||||
};
|
||||
static const struct config_registers v5_config_registers = {
|
||||
.CRC = 0,
|
||||
.FAR = 1,
|
||||
.FDRI = 2,
|
||||
.FDRO = 3,
|
||||
.CMD = 4,
|
||||
.CTL = 5,
|
||||
.MASK = 6,
|
||||
.STAT = 7,
|
||||
.LOUT = 8,
|
||||
.COR = 9,
|
||||
.MFWR = 10,
|
||||
.FLR = UNIMPLEMENTED,
|
||||
.KEY = UNIMPLEMENTED,
|
||||
.CBC = 11,
|
||||
.IDCODE = 12,
|
||||
.AXSS = 13,
|
||||
.C0R_1 = 14,
|
||||
.CSOB = 15,
|
||||
.WBSTAR = 16,
|
||||
.TIMER = 17,
|
||||
.BOOTSTS = 18,
|
||||
.CTL_1 = 19,
|
||||
};
|
||||
|
||||
/**
|
||||
* hwicap_command_desync: Send a DESYNC command to the ICAP port.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
*
|
||||
* This command desynchronizes the ICAP After this command, a
|
||||
* bitstream containing a NULL packet, followed by a SYNCH packet is
|
||||
* required before the ICAP will recognize commands.
|
||||
*/
|
||||
int hwicap_command_desync(struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
u32 buffer[4];
|
||||
u32 index = 0;
|
||||
|
||||
/*
|
||||
* Create the data to be written to the ICAP.
|
||||
*/
|
||||
buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
|
||||
buffer[index++] = XHI_CMD_DESYNCH;
|
||||
buffer[index++] = XHI_NOOP_PACKET;
|
||||
buffer[index++] = XHI_NOOP_PACKET;
|
||||
|
||||
/*
|
||||
* Write the data to the FIFO and intiate the transfer of data present
|
||||
* in the FIFO to the ICAP device.
|
||||
*/
|
||||
return drvdata->config->set_configuration(drvdata,
|
||||
&buffer[0], index);
|
||||
}
|
||||
|
||||
/**
|
||||
* hwicap_command_capture: Send a CAPTURE command to the ICAP port.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
*
|
||||
* This command captures all of the flip flop states so they will be
|
||||
* available during readback. One can use this command instead of
|
||||
* enabling the CAPTURE block in the design.
|
||||
*/
|
||||
int hwicap_command_capture(struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
u32 buffer[7];
|
||||
u32 index = 0;
|
||||
|
||||
/*
|
||||
* Create the data to be written to the ICAP.
|
||||
*/
|
||||
buffer[index++] = XHI_DUMMY_PACKET;
|
||||
buffer[index++] = XHI_SYNC_PACKET;
|
||||
buffer[index++] = XHI_NOOP_PACKET;
|
||||
buffer[index++] = hwicap_type_1_write(drvdata->config_regs->CMD) | 1;
|
||||
buffer[index++] = XHI_CMD_GCAPTURE;
|
||||
buffer[index++] = XHI_DUMMY_PACKET;
|
||||
buffer[index++] = XHI_DUMMY_PACKET;
|
||||
|
||||
/*
|
||||
* Write the data to the FIFO and intiate the transfer of data
|
||||
* present in the FIFO to the ICAP device.
|
||||
*/
|
||||
return drvdata->config->set_configuration(drvdata,
|
||||
&buffer[0], index);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* hwicap_get_configuration_register: Query a configuration register.
|
||||
* @parameter drvdata: a pointer to the drvdata.
|
||||
* @parameter reg: a constant which represents the configuration
|
||||
* register value to be returned.
|
||||
* Examples: XHI_IDCODE, XHI_FLR.
|
||||
* @parameter RegData: returns the value of the register.
|
||||
*
|
||||
* Sends a query packet to the ICAP and then receives the response.
|
||||
* The icap is left in Synched state.
|
||||
*/
|
||||
int hwicap_get_configuration_register(struct hwicap_drvdata *drvdata,
|
||||
u32 reg, u32 *RegData)
|
||||
{
|
||||
int status;
|
||||
u32 buffer[6];
|
||||
u32 index = 0;
|
||||
|
||||
/*
|
||||
* Create the data to be written to the ICAP.
|
||||
*/
|
||||
buffer[index++] = XHI_DUMMY_PACKET;
|
||||
buffer[index++] = XHI_SYNC_PACKET;
|
||||
buffer[index++] = XHI_NOOP_PACKET;
|
||||
buffer[index++] = hwicap_type_1_read(reg) | 1;
|
||||
buffer[index++] = XHI_NOOP_PACKET;
|
||||
buffer[index++] = XHI_NOOP_PACKET;
|
||||
|
||||
/*
|
||||
* Write the data to the FIFO and intiate the transfer of data present
|
||||
* in the FIFO to the ICAP device.
|
||||
*/
|
||||
status = drvdata->config->set_configuration(drvdata,
|
||||
&buffer[0], index);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/*
|
||||
* Read the configuration register
|
||||
*/
|
||||
status = drvdata->config->get_configuration(drvdata, RegData, 1);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hwicap_initialize_hwicap(struct hwicap_drvdata *drvdata)
|
||||
{
|
||||
int status;
|
||||
u32 idcode;
|
||||
|
||||
dev_dbg(drvdata->dev, "initializing\n");
|
||||
|
||||
/* Abort any current transaction, to make sure we have the
|
||||
* ICAP in a good state. */
|
||||
dev_dbg(drvdata->dev, "Reset...\n");
|
||||
drvdata->config->reset(drvdata);
|
||||
|
||||
dev_dbg(drvdata->dev, "Desync...\n");
|
||||
status = hwicap_command_desync(drvdata);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Attempt to read the IDCODE from ICAP. This
|
||||
* may not be returned correctly, due to the design of the
|
||||
* hardware.
|
||||
*/
|
||||
dev_dbg(drvdata->dev, "Reading IDCODE...\n");
|
||||
status = hwicap_get_configuration_register(
|
||||
drvdata, drvdata->config_regs->IDCODE, &idcode);
|
||||
dev_dbg(drvdata->dev, "IDCODE = %x\n", idcode);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
dev_dbg(drvdata->dev, "Desync...\n");
|
||||
status = hwicap_command_desync(drvdata);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
hwicap_read(struct file *file, char *buf, size_t count, loff_t *ppos)
|
||||
{
|
||||
struct hwicap_drvdata *drvdata = file->private_data;
|
||||
ssize_t bytes_to_read = 0;
|
||||
u32 *kbuf;
|
||||
u32 words;
|
||||
u32 bytes_remaining;
|
||||
int status;
|
||||
|
||||
if (down_interruptible(&drvdata->sem))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (drvdata->read_buffer_in_use) {
|
||||
/* If there are leftover bytes in the buffer, just */
|
||||
/* return them and don't try to read more from the */
|
||||
/* ICAP device. */
|
||||
bytes_to_read =
|
||||
(count < drvdata->read_buffer_in_use) ? count :
|
||||
drvdata->read_buffer_in_use;
|
||||
|
||||
/* Return the data currently in the read buffer. */
|
||||
if (copy_to_user(buf, drvdata->read_buffer, bytes_to_read)) {
|
||||
status = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
drvdata->read_buffer_in_use -= bytes_to_read;
|
||||
memcpy(drvdata->read_buffer + bytes_to_read,
|
||||
drvdata->read_buffer, 4 - bytes_to_read);
|
||||
} else {
|
||||
/* Get new data from the ICAP, and return was was requested. */
|
||||
kbuf = (u32 *) get_zeroed_page(GFP_KERNEL);
|
||||
if (!kbuf) {
|
||||
status = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* The ICAP device is only able to read complete */
|
||||
/* words. If a number of bytes that do not correspond */
|
||||
/* to complete words is requested, then we read enough */
|
||||
/* words to get the required number of bytes, and then */
|
||||
/* save the remaining bytes for the next read. */
|
||||
|
||||
/* Determine the number of words to read, rounding up */
|
||||
/* if necessary. */
|
||||
words = ((count + 3) >> 2);
|
||||
bytes_to_read = words << 2;
|
||||
|
||||
if (bytes_to_read > PAGE_SIZE)
|
||||
bytes_to_read = PAGE_SIZE;
|
||||
|
||||
/* Ensure we only read a complete number of words. */
|
||||
bytes_remaining = bytes_to_read & 3;
|
||||
bytes_to_read &= ~3;
|
||||
words = bytes_to_read >> 2;
|
||||
|
||||
status = drvdata->config->get_configuration(drvdata,
|
||||
kbuf, words);
|
||||
|
||||
/* If we didn't read correctly, then bail out. */
|
||||
if (status) {
|
||||
free_page((unsigned long)kbuf);
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* If we fail to return the data to the user, then bail out. */
|
||||
if (copy_to_user(buf, kbuf, bytes_to_read)) {
|
||||
free_page((unsigned long)kbuf);
|
||||
status = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
memcpy(kbuf, drvdata->read_buffer, bytes_remaining);
|
||||
drvdata->read_buffer_in_use = bytes_remaining;
|
||||
free_page((unsigned long)kbuf);
|
||||
}
|
||||
status = bytes_to_read;
|
||||
error:
|
||||
up(&drvdata->sem);
|
||||
return status;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
hwicap_write(struct file *file, const char *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct hwicap_drvdata *drvdata = file->private_data;
|
||||
ssize_t written = 0;
|
||||
ssize_t left = count;
|
||||
u32 *kbuf;
|
||||
ssize_t len;
|
||||
ssize_t status;
|
||||
|
||||
if (down_interruptible(&drvdata->sem))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
left += drvdata->write_buffer_in_use;
|
||||
|
||||
/* Only write multiples of 4 bytes. */
|
||||
if (left < 4) {
|
||||
status = 0;
|
||||
goto error;
|
||||
}
|
||||
|
||||
kbuf = (u32 *) __get_free_page(GFP_KERNEL);
|
||||
if (!kbuf) {
|
||||
status = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
while (left > 3) {
|
||||
/* only write multiples of 4 bytes, so there might */
|
||||
/* be as many as 3 bytes left (at the end). */
|
||||
len = left;
|
||||
|
||||
if (len > PAGE_SIZE)
|
||||
len = PAGE_SIZE;
|
||||
len &= ~3;
|
||||
|
||||
if (drvdata->write_buffer_in_use) {
|
||||
memcpy(kbuf, drvdata->write_buffer,
|
||||
drvdata->write_buffer_in_use);
|
||||
if (copy_from_user(
|
||||
(((char *)kbuf) + (drvdata->write_buffer_in_use)),
|
||||
buf + written,
|
||||
len - (drvdata->write_buffer_in_use))) {
|
||||
free_page((unsigned long)kbuf);
|
||||
status = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
if (copy_from_user(kbuf, buf + written, len)) {
|
||||
free_page((unsigned long)kbuf);
|
||||
status = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
status = drvdata->config->set_configuration(drvdata,
|
||||
kbuf, len >> 2);
|
||||
|
||||
if (status) {
|
||||
free_page((unsigned long)kbuf);
|
||||
status = -EFAULT;
|
||||
goto error;
|
||||
}
|
||||
if (drvdata->write_buffer_in_use) {
|
||||
len -= drvdata->write_buffer_in_use;
|
||||
left -= drvdata->write_buffer_in_use;
|
||||
drvdata->write_buffer_in_use = 0;
|
||||
}
|
||||
written += len;
|
||||
left -= len;
|
||||
}
|
||||
if ((left > 0) && (left < 4)) {
|
||||
if (!copy_from_user(drvdata->write_buffer,
|
||||
buf + written, left)) {
|
||||
drvdata->write_buffer_in_use = left;
|
||||
written += left;
|
||||
left = 0;
|
||||
}
|
||||
}
|
||||
|
||||
free_page((unsigned long)kbuf);
|
||||
status = written;
|
||||
error:
|
||||
up(&drvdata->sem);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int hwicap_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct hwicap_drvdata *drvdata;
|
||||
int status;
|
||||
|
||||
drvdata = container_of(inode->i_cdev, struct hwicap_drvdata, cdev);
|
||||
|
||||
if (down_interruptible(&drvdata->sem))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (drvdata->is_open) {
|
||||
status = -EBUSY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
status = hwicap_initialize_hwicap(drvdata);
|
||||
if (status) {
|
||||
dev_err(drvdata->dev, "Failed to open file");
|
||||
goto error;
|
||||
}
|
||||
|
||||
file->private_data = drvdata;
|
||||
drvdata->write_buffer_in_use = 0;
|
||||
drvdata->read_buffer_in_use = 0;
|
||||
drvdata->is_open = 1;
|
||||
|
||||
error:
|
||||
up(&drvdata->sem);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int hwicap_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct hwicap_drvdata *drvdata = file->private_data;
|
||||
int i;
|
||||
int status = 0;
|
||||
|
||||
if (down_interruptible(&drvdata->sem))
|
||||
return -ERESTARTSYS;
|
||||
|
||||
if (drvdata->write_buffer_in_use) {
|
||||
/* Flush write buffer. */
|
||||
for (i = drvdata->write_buffer_in_use; i < 4; i++)
|
||||
drvdata->write_buffer[i] = 0;
|
||||
|
||||
status = drvdata->config->set_configuration(drvdata,
|
||||
(u32 *) drvdata->write_buffer, 1);
|
||||
if (status)
|
||||
goto error;
|
||||
}
|
||||
|
||||
status = hwicap_command_desync(drvdata);
|
||||
if (status)
|
||||
goto error;
|
||||
|
||||
error:
|
||||
drvdata->is_open = 0;
|
||||
up(&drvdata->sem);
|
||||
return status;
|
||||
}
|
||||
|
||||
static struct file_operations hwicap_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.write = hwicap_write,
|
||||
.read = hwicap_read,
|
||||
.open = hwicap_open,
|
||||
.release = hwicap_release,
|
||||
};
|
||||
|
||||
static int __devinit hwicap_setup(struct device *dev, int id,
|
||||
const struct resource *regs_res,
|
||||
const struct hwicap_driver_config *config,
|
||||
const struct config_registers *config_regs)
|
||||
{
|
||||
dev_t devt;
|
||||
struct hwicap_drvdata *drvdata = NULL;
|
||||
int retval = 0;
|
||||
|
||||
dev_info(dev, "Xilinx icap port driver\n");
|
||||
|
||||
if (id < 0) {
|
||||
for (id = 0; id < HWICAP_DEVICES; id++)
|
||||
if (!probed_devices[id])
|
||||
break;
|
||||
}
|
||||
if (id < 0 || id >= HWICAP_DEVICES) {
|
||||
dev_err(dev, "%s%i too large\n", DRIVER_NAME, id);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (probed_devices[id]) {
|
||||
dev_err(dev, "cannot assign to %s%i; it is already in use\n",
|
||||
DRIVER_NAME, id);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
probed_devices[id] = 1;
|
||||
|
||||
devt = MKDEV(xhwicap_major, xhwicap_minor + id);
|
||||
|
||||
drvdata = kmalloc(sizeof(struct hwicap_drvdata), GFP_KERNEL);
|
||||
if (!drvdata) {
|
||||
dev_err(dev, "Couldn't allocate device private record\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset((void *)drvdata, 0, sizeof(struct hwicap_drvdata));
|
||||
dev_set_drvdata(dev, (void *)drvdata);
|
||||
|
||||
if (!regs_res) {
|
||||
dev_err(dev, "Couldn't get registers resource\n");
|
||||
retval = -EFAULT;
|
||||
goto failed1;
|
||||
}
|
||||
|
||||
drvdata->mem_start = regs_res->start;
|
||||
drvdata->mem_end = regs_res->end;
|
||||
drvdata->mem_size = regs_res->end - regs_res->start + 1;
|
||||
|
||||
if (!request_mem_region(drvdata->mem_start,
|
||||
drvdata->mem_size, DRIVER_NAME)) {
|
||||
dev_err(dev, "Couldn't lock memory region at %p\n",
|
||||
(void *)regs_res->start);
|
||||
retval = -EBUSY;
|
||||
goto failed1;
|
||||
}
|
||||
|
||||
drvdata->devt = devt;
|
||||
drvdata->dev = dev;
|
||||
drvdata->base_address = ioremap(drvdata->mem_start, drvdata->mem_size);
|
||||
if (!drvdata->base_address) {
|
||||
dev_err(dev, "ioremap() failed\n");
|
||||
goto failed2;
|
||||
}
|
||||
|
||||
drvdata->config = config;
|
||||
drvdata->config_regs = config_regs;
|
||||
|
||||
init_MUTEX(&drvdata->sem);
|
||||
drvdata->is_open = 0;
|
||||
|
||||
dev_info(dev, "ioremap %lx to %p with size %x\n",
|
||||
(unsigned long int)drvdata->mem_start,
|
||||
drvdata->base_address, drvdata->mem_size);
|
||||
|
||||
cdev_init(&drvdata->cdev, &hwicap_fops);
|
||||
drvdata->cdev.owner = THIS_MODULE;
|
||||
retval = cdev_add(&drvdata->cdev, devt, 1);
|
||||
if (retval) {
|
||||
dev_err(dev, "cdev_add() failed\n");
|
||||
goto failed3;
|
||||
}
|
||||
/* devfs_mk_cdev(devt, S_IFCHR|S_IRUGO|S_IWUGO, DRIVER_NAME); */
|
||||
class_device_create(icap_class, NULL, devt, NULL, DRIVER_NAME);
|
||||
return 0; /* success */
|
||||
|
||||
failed3:
|
||||
iounmap(drvdata->base_address);
|
||||
|
||||
failed2:
|
||||
release_mem_region(regs_res->start, drvdata->mem_size);
|
||||
|
||||
failed1:
|
||||
kfree(drvdata);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static struct hwicap_driver_config buffer_icap_config = {
|
||||
.get_configuration = buffer_icap_get_configuration,
|
||||
.set_configuration = buffer_icap_set_configuration,
|
||||
.reset = buffer_icap_reset,
|
||||
};
|
||||
|
||||
static struct hwicap_driver_config fifo_icap_config = {
|
||||
.get_configuration = fifo_icap_get_configuration,
|
||||
.set_configuration = fifo_icap_set_configuration,
|
||||
.reset = fifo_icap_reset,
|
||||
};
|
||||
|
||||
static int __devexit hwicap_remove(struct device *dev)
|
||||
{
|
||||
struct hwicap_drvdata *drvdata;
|
||||
|
||||
drvdata = (struct hwicap_drvdata *)dev_get_drvdata(dev);
|
||||
|
||||
if (!drvdata)
|
||||
return 0;
|
||||
|
||||
class_device_destroy(icap_class, drvdata->devt);
|
||||
cdev_del(&drvdata->cdev);
|
||||
iounmap(drvdata->base_address);
|
||||
release_mem_region(drvdata->mem_start, drvdata->mem_size);
|
||||
kfree(drvdata);
|
||||
dev_set_drvdata(dev, NULL);
|
||||
probed_devices[MINOR(dev->devt)-xhwicap_minor] = 0;
|
||||
|
||||
return 0; /* success */
|
||||
}
|
||||
|
||||
static int __devinit hwicap_drv_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
const struct config_registers *regs;
|
||||
const char *family;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
/* It's most likely that we're using V4, if the family is not
|
||||
specified */
|
||||
regs = &v4_config_registers;
|
||||
family = pdev->dev.platform_data;
|
||||
|
||||
if (family) {
|
||||
if (!strcmp(family, "virtex2p")) {
|
||||
regs = &v2_config_registers;
|
||||
} else if (!strcmp(family, "virtex4")) {
|
||||
regs = &v4_config_registers;
|
||||
} else if (!strcmp(family, "virtex5")) {
|
||||
regs = &v5_config_registers;
|
||||
}
|
||||
}
|
||||
|
||||
return hwicap_setup(&pdev->dev, pdev->id, res,
|
||||
&buffer_icap_config, regs);
|
||||
}
|
||||
|
||||
static int __devexit hwicap_drv_remove(struct platform_device *pdev)
|
||||
{
|
||||
return hwicap_remove(&pdev->dev);
|
||||
}
|
||||
|
||||
static struct platform_driver hwicap_platform_driver = {
|
||||
.probe = hwicap_drv_probe,
|
||||
.remove = hwicap_drv_remove,
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
/* ---------------------------------------------------------------------
|
||||
* OF bus binding
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static int __devinit
|
||||
hwicap_of_probe(struct of_device *op, const struct of_device_id *match)
|
||||
{
|
||||
struct resource res;
|
||||
const unsigned int *id;
|
||||
const char *family;
|
||||
int rc;
|
||||
const struct hwicap_driver_config *config = match->data;
|
||||
const struct config_registers *regs;
|
||||
|
||||
dev_dbg(&op->dev, "hwicap_of_probe(%p, %p)\n", op, match);
|
||||
|
||||
rc = of_address_to_resource(op->node, 0, &res);
|
||||
if (rc) {
|
||||
dev_err(&op->dev, "invalid address\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
id = of_get_property(op->node, "port-number", NULL);
|
||||
|
||||
/* It's most likely that we're using V4, if the family is not
|
||||
specified */
|
||||
regs = &v4_config_registers;
|
||||
family = of_get_property(op->node, "xlnx,family", NULL);
|
||||
|
||||
if (family) {
|
||||
if (!strcmp(family, "virtex2p")) {
|
||||
regs = &v2_config_registers;
|
||||
} else if (!strcmp(family, "virtex4")) {
|
||||
regs = &v4_config_registers;
|
||||
} else if (!strcmp(family, "virtex5")) {
|
||||
regs = &v5_config_registers;
|
||||
}
|
||||
}
|
||||
return hwicap_setup(&op->dev, id ? *id : -1, &res, config,
|
||||
regs);
|
||||
}
|
||||
|
||||
static int __devexit hwicap_of_remove(struct of_device *op)
|
||||
{
|
||||
return hwicap_remove(&op->dev);
|
||||
}
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static const struct of_device_id __devinit hwicap_of_match[] = {
|
||||
{ .compatible = "xlnx,opb-hwicap-1.00.b", .data = &buffer_icap_config},
|
||||
{ .compatible = "xlnx,xps-hwicap-1.00.a", .data = &fifo_icap_config},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, hwicap_of_match);
|
||||
|
||||
static struct of_platform_driver hwicap_of_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = DRIVER_NAME,
|
||||
.match_table = hwicap_of_match,
|
||||
.probe = hwicap_of_probe,
|
||||
.remove = __devexit_p(hwicap_of_remove),
|
||||
.driver = {
|
||||
.name = DRIVER_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
/* Registration helpers to keep the number of #ifdefs to a minimum */
|
||||
static inline int __devinit hwicap_of_register(void)
|
||||
{
|
||||
pr_debug("hwicap: calling of_register_platform_driver()\n");
|
||||
return of_register_platform_driver(&hwicap_of_driver);
|
||||
}
|
||||
|
||||
static inline void __devexit hwicap_of_unregister(void)
|
||||
{
|
||||
of_unregister_platform_driver(&hwicap_of_driver);
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
/* CONFIG_OF not enabled; do nothing helpers */
|
||||
static inline int __devinit hwicap_of_register(void) { return 0; }
|
||||
static inline void __devexit hwicap_of_unregister(void) { }
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int __devinit hwicap_module_init(void)
|
||||
{
|
||||
dev_t devt;
|
||||
int retval;
|
||||
|
||||
icap_class = class_create(THIS_MODULE, "xilinx_config");
|
||||
|
||||
if (xhwicap_major) {
|
||||
devt = MKDEV(xhwicap_major, xhwicap_minor);
|
||||
retval = register_chrdev_region(
|
||||
devt,
|
||||
HWICAP_DEVICES,
|
||||
DRIVER_NAME);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
} else {
|
||||
retval = alloc_chrdev_region(&devt,
|
||||
xhwicap_minor,
|
||||
HWICAP_DEVICES,
|
||||
DRIVER_NAME);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
xhwicap_major = MAJOR(devt);
|
||||
}
|
||||
|
||||
retval = platform_driver_register(&hwicap_platform_driver);
|
||||
|
||||
if (retval)
|
||||
goto failed1;
|
||||
|
||||
retval = hwicap_of_register();
|
||||
|
||||
if (retval)
|
||||
goto failed2;
|
||||
|
||||
return retval;
|
||||
|
||||
failed2:
|
||||
platform_driver_unregister(&hwicap_platform_driver);
|
||||
|
||||
failed1:
|
||||
unregister_chrdev_region(devt, HWICAP_DEVICES);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void __devexit hwicap_module_cleanup(void)
|
||||
{
|
||||
dev_t devt = MKDEV(xhwicap_major, xhwicap_minor);
|
||||
|
||||
class_destroy(icap_class);
|
||||
|
||||
platform_driver_unregister(&hwicap_platform_driver);
|
||||
|
||||
hwicap_of_unregister();
|
||||
|
||||
unregister_chrdev_region(devt, HWICAP_DEVICES);
|
||||
}
|
||||
|
||||
module_init(hwicap_module_init);
|
||||
module_exit(hwicap_module_cleanup);
|
||||
|
||||
MODULE_AUTHOR("Xilinx, Inc; Xilinx Research Labs Group");
|
||||
MODULE_DESCRIPTION("Xilinx ICAP Port Driver");
|
||||
MODULE_LICENSE("GPL");
|
193
drivers/char/xilinx_hwicap/xilinx_hwicap.h
Normal file
193
drivers/char/xilinx_hwicap/xilinx_hwicap.h
Normal file
|
@ -0,0 +1,193 @@
|
|||
/*****************************************************************************
|
||||
*
|
||||
* Author: Xilinx, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* XILINX IS PROVIDING THIS DESIGN, CODE, OR INFORMATION "AS IS"
|
||||
* AS A COURTESY TO YOU, SOLELY FOR USE IN DEVELOPING PROGRAMS AND
|
||||
* SOLUTIONS FOR XILINX DEVICES. BY PROVIDING THIS DESIGN, CODE,
|
||||
* OR INFORMATION AS ONE POSSIBLE IMPLEMENTATION OF THIS FEATURE,
|
||||
* APPLICATION OR STANDARD, XILINX IS MAKING NO REPRESENTATION
|
||||
* THAT THIS IMPLEMENTATION IS FREE FROM ANY CLAIMS OF INFRINGEMENT,
|
||||
* AND YOU ARE RESPONSIBLE FOR OBTAINING ANY RIGHTS YOU MAY REQUIRE
|
||||
* FOR YOUR IMPLEMENTATION. XILINX EXPRESSLY DISCLAIMS ANY
|
||||
* WARRANTY WHATSOEVER WITH RESPECT TO THE ADEQUACY OF THE
|
||||
* IMPLEMENTATION, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OR
|
||||
* REPRESENTATIONS THAT THIS IMPLEMENTATION IS FREE FROM CLAIMS OF
|
||||
* INFRINGEMENT, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* Xilinx products are not intended for use in life support appliances,
|
||||
* devices, or systems. Use in such applications is expressly prohibited.
|
||||
*
|
||||
* (c) Copyright 2003-2007 Xilinx Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef XILINX_HWICAP_H_ /* prevent circular inclusions */
|
||||
#define XILINX_HWICAP_H_ /* by using protection macros */
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
|
||||
struct hwicap_drvdata {
|
||||
u32 write_buffer_in_use; /* Always in [0,3] */
|
||||
u8 write_buffer[4];
|
||||
u32 read_buffer_in_use; /* Always in [0,3] */
|
||||
u8 read_buffer[4];
|
||||
u32 mem_start; /* phys. address of the control registers */
|
||||
u32 mem_end; /* phys. address of the control registers */
|
||||
u32 mem_size;
|
||||
void __iomem *base_address;/* virt. address of the control registers */
|
||||
|
||||
struct device *dev;
|
||||
struct cdev cdev; /* Char device structure */
|
||||
dev_t devt;
|
||||
|
||||
const struct hwicap_driver_config *config;
|
||||
const struct config_registers *config_regs;
|
||||
void *private_data;
|
||||
bool is_open;
|
||||
struct semaphore sem;
|
||||
};
|
||||
|
||||
struct hwicap_driver_config {
|
||||
int (*get_configuration)(struct hwicap_drvdata *drvdata, u32 *data,
|
||||
u32 size);
|
||||
int (*set_configuration)(struct hwicap_drvdata *drvdata, u32 *data,
|
||||
u32 size);
|
||||
void (*reset)(struct hwicap_drvdata *drvdata);
|
||||
};
|
||||
|
||||
/* Number of times to poll the done regsiter */
|
||||
#define XHI_MAX_RETRIES 10
|
||||
|
||||
/************ Constant Definitions *************/
|
||||
|
||||
#define XHI_PAD_FRAMES 0x1
|
||||
|
||||
/* Mask for calculating configuration packet headers */
|
||||
#define XHI_WORD_COUNT_MASK_TYPE_1 0x7FFUL
|
||||
#define XHI_WORD_COUNT_MASK_TYPE_2 0x1FFFFFUL
|
||||
#define XHI_TYPE_MASK 0x7
|
||||
#define XHI_REGISTER_MASK 0xF
|
||||
#define XHI_OP_MASK 0x3
|
||||
|
||||
#define XHI_TYPE_SHIFT 29
|
||||
#define XHI_REGISTER_SHIFT 13
|
||||
#define XHI_OP_SHIFT 27
|
||||
|
||||
#define XHI_TYPE_1 1
|
||||
#define XHI_TYPE_2 2
|
||||
#define XHI_OP_WRITE 2
|
||||
#define XHI_OP_READ 1
|
||||
|
||||
/* Address Block Types */
|
||||
#define XHI_FAR_CLB_BLOCK 0
|
||||
#define XHI_FAR_BRAM_BLOCK 1
|
||||
#define XHI_FAR_BRAM_INT_BLOCK 2
|
||||
|
||||
struct config_registers {
|
||||
u32 CRC;
|
||||
u32 FAR;
|
||||
u32 FDRI;
|
||||
u32 FDRO;
|
||||
u32 CMD;
|
||||
u32 CTL;
|
||||
u32 MASK;
|
||||
u32 STAT;
|
||||
u32 LOUT;
|
||||
u32 COR;
|
||||
u32 MFWR;
|
||||
u32 FLR;
|
||||
u32 KEY;
|
||||
u32 CBC;
|
||||
u32 IDCODE;
|
||||
u32 AXSS;
|
||||
u32 C0R_1;
|
||||
u32 CSOB;
|
||||
u32 WBSTAR;
|
||||
u32 TIMER;
|
||||
u32 BOOTSTS;
|
||||
u32 CTL_1;
|
||||
};
|
||||
|
||||
/* Configuration Commands */
|
||||
#define XHI_CMD_NULL 0
|
||||
#define XHI_CMD_WCFG 1
|
||||
#define XHI_CMD_MFW 2
|
||||
#define XHI_CMD_DGHIGH 3
|
||||
#define XHI_CMD_RCFG 4
|
||||
#define XHI_CMD_START 5
|
||||
#define XHI_CMD_RCAP 6
|
||||
#define XHI_CMD_RCRC 7
|
||||
#define XHI_CMD_AGHIGH 8
|
||||
#define XHI_CMD_SWITCH 9
|
||||
#define XHI_CMD_GRESTORE 10
|
||||
#define XHI_CMD_SHUTDOWN 11
|
||||
#define XHI_CMD_GCAPTURE 12
|
||||
#define XHI_CMD_DESYNCH 13
|
||||
#define XHI_CMD_IPROG 15 /* Only in Virtex5 */
|
||||
#define XHI_CMD_CRCC 16 /* Only in Virtex5 */
|
||||
#define XHI_CMD_LTIMER 17 /* Only in Virtex5 */
|
||||
|
||||
/* Packet constants */
|
||||
#define XHI_SYNC_PACKET 0xAA995566UL
|
||||
#define XHI_DUMMY_PACKET 0xFFFFFFFFUL
|
||||
#define XHI_NOOP_PACKET (XHI_TYPE_1 << XHI_TYPE_SHIFT)
|
||||
#define XHI_TYPE_2_READ ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \
|
||||
(XHI_OP_READ << XHI_OP_SHIFT))
|
||||
|
||||
#define XHI_TYPE_2_WRITE ((XHI_TYPE_2 << XHI_TYPE_SHIFT) | \
|
||||
(XHI_OP_WRITE << XHI_OP_SHIFT))
|
||||
|
||||
#define XHI_TYPE2_CNT_MASK 0x07FFFFFF
|
||||
|
||||
#define XHI_TYPE_1_PACKET_MAX_WORDS 2047UL
|
||||
#define XHI_TYPE_1_HEADER_BYTES 4
|
||||
#define XHI_TYPE_2_HEADER_BYTES 8
|
||||
|
||||
/* Constant to use for CRC check when CRC has been disabled */
|
||||
#define XHI_DISABLED_AUTO_CRC 0x0000DEFCUL
|
||||
|
||||
/**
|
||||
* hwicap_type_1_read: Generates a Type 1 read packet header.
|
||||
* @parameter: Register is the address of the register to be read back.
|
||||
*
|
||||
* Generates a Type 1 read packet header, which is used to indirectly
|
||||
* read registers in the configuration logic. This packet must then
|
||||
* be sent through the icap device, and a return packet received with
|
||||
* the information.
|
||||
**/
|
||||
static inline u32 hwicap_type_1_read(u32 Register)
|
||||
{
|
||||
return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
|
||||
(Register << XHI_REGISTER_SHIFT) |
|
||||
(XHI_OP_READ << XHI_OP_SHIFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* hwicap_type_1_write: Generates a Type 1 write packet header
|
||||
* @parameter: Register is the address of the register to be read back.
|
||||
**/
|
||||
static inline u32 hwicap_type_1_write(u32 Register)
|
||||
{
|
||||
return (XHI_TYPE_1 << XHI_TYPE_SHIFT) |
|
||||
(Register << XHI_REGISTER_SHIFT) |
|
||||
(XHI_OP_WRITE << XHI_OP_SHIFT);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1737,10 +1737,8 @@ config SC92031
|
|||
|
||||
config CPMAC
|
||||
tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
|
||||
depends on NET_ETHERNET && EXPERIMENTAL && AR7
|
||||
depends on NET_ETHERNET && EXPERIMENTAL && AR7 && BROKEN
|
||||
select PHYLIB
|
||||
select FIXED_PHY
|
||||
select FIXED_MII_100_FDX
|
||||
help
|
||||
TI AR7 CPMAC Ethernet support
|
||||
|
||||
|
|
|
@ -845,15 +845,6 @@ static void cpmac_adjust_link(struct net_device *dev)
|
|||
spin_unlock(&priv->lock);
|
||||
}
|
||||
|
||||
static int cpmac_link_update(struct net_device *dev,
|
||||
struct fixed_phy_status *status)
|
||||
{
|
||||
status->link = 1;
|
||||
status->speed = 100;
|
||||
status->duplex = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cpmac_open(struct net_device *dev)
|
||||
{
|
||||
int i, size, res;
|
||||
|
@ -996,11 +987,11 @@ static int external_switch;
|
|||
static int __devinit cpmac_probe(struct platform_device *pdev)
|
||||
{
|
||||
int rc, phy_id, i;
|
||||
int mdio_bus_id = cpmac_mii.id;
|
||||
struct resource *mem;
|
||||
struct cpmac_priv *priv;
|
||||
struct net_device *dev;
|
||||
struct plat_cpmac_data *pdata;
|
||||
struct fixed_info *fixed_phy;
|
||||
DECLARE_MAC_BUF(mac);
|
||||
|
||||
pdata = pdev->dev.platform_data;
|
||||
|
@ -1014,9 +1005,23 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
if (phy_id == PHY_MAX_ADDR) {
|
||||
if (external_switch || dumb_switch)
|
||||
if (external_switch || dumb_switch) {
|
||||
struct fixed_phy_status status = {};
|
||||
|
||||
mdio_bus_id = 0;
|
||||
|
||||
/*
|
||||
* FIXME: this should be in the platform code!
|
||||
* Since there is not platform code at all (that is,
|
||||
* no mainline users of that driver), place it here
|
||||
* for now.
|
||||
*/
|
||||
phy_id = 0;
|
||||
else {
|
||||
status.link = 1;
|
||||
status.duplex = 1;
|
||||
status.speed = 100;
|
||||
fixed_phy_add(PHY_POLL, phy_id, &status);
|
||||
} else {
|
||||
printk(KERN_ERR "cpmac: no PHY present\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -1060,32 +1065,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
|
|||
priv->msg_enable = netif_msg_init(debug_level, 0xff);
|
||||
memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
|
||||
|
||||
if (phy_id == 31) {
|
||||
snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, cpmac_mii.id,
|
||||
phy_id);
|
||||
} else {
|
||||
/* Let's try to get a free fixed phy... */
|
||||
for (i = 0; i < MAX_PHY_AMNT; i++) {
|
||||
fixed_phy = fixed_mdio_get_phydev(i);
|
||||
if (!fixed_phy)
|
||||
continue;
|
||||
if (!fixed_phy->phydev->attached_dev) {
|
||||
strncpy(priv->phy_name,
|
||||
fixed_phy->phydev->dev.bus_id,
|
||||
BUS_ID_SIZE);
|
||||
fixed_mdio_set_link_update(fixed_phy->phydev,
|
||||
&cpmac_link_update);
|
||||
goto phy_found;
|
||||
}
|
||||
}
|
||||
if (netif_msg_drv(priv))
|
||||
printk(KERN_ERR "%s: Could not find fixed PHY\n",
|
||||
dev->name);
|
||||
rc = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
snprintf(priv->phy_name, BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id);
|
||||
|
||||
phy_found:
|
||||
priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0,
|
||||
PHY_INTERFACE_MODE_MII);
|
||||
if (IS_ERR(priv->phy)) {
|
||||
|
|
|
@ -137,6 +137,31 @@ struct device_node *of_get_parent(const struct device_node *node)
|
|||
}
|
||||
EXPORT_SYMBOL(of_get_parent);
|
||||
|
||||
/**
|
||||
* of_get_next_parent - Iterate to a node's parent
|
||||
* @node: Node to get parent of
|
||||
*
|
||||
* This is like of_get_parent() except that it drops the
|
||||
* refcount on the passed node, making it suitable for iterating
|
||||
* through a node's parents.
|
||||
*
|
||||
* Returns a node pointer with refcount incremented, use
|
||||
* of_node_put() on it when done.
|
||||
*/
|
||||
struct device_node *of_get_next_parent(struct device_node *node)
|
||||
{
|
||||
struct device_node *parent;
|
||||
|
||||
if (!node)
|
||||
return NULL;
|
||||
|
||||
read_lock(&devtree_lock);
|
||||
parent = of_node_get(node->parent);
|
||||
of_node_put(node);
|
||||
read_unlock(&devtree_lock);
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_get_next_child - Iterate a node childs
|
||||
* @node: parent node
|
||||
|
|
|
@ -85,6 +85,15 @@ static int of_platform_device_resume(struct device * dev)
|
|||
return error;
|
||||
}
|
||||
|
||||
static void of_platform_device_shutdown(struct device *dev)
|
||||
{
|
||||
struct of_device *of_dev = to_of_device(dev);
|
||||
struct of_platform_driver *drv = to_of_platform_driver(dev->driver);
|
||||
|
||||
if (dev->driver && drv->shutdown)
|
||||
drv->shutdown(of_dev);
|
||||
}
|
||||
|
||||
int of_bus_type_init(struct bus_type *bus, const char *name)
|
||||
{
|
||||
bus->name = name;
|
||||
|
@ -93,6 +102,7 @@ int of_bus_type_init(struct bus_type *bus, const char *name)
|
|||
bus->remove = of_platform_device_remove;
|
||||
bus->suspend = of_platform_device_suspend;
|
||||
bus->resume = of_platform_device_resume;
|
||||
bus->shutdown = of_platform_device_shutdown;
|
||||
return bus_register(bus);
|
||||
}
|
||||
|
||||
|
|
|
@ -1142,17 +1142,17 @@ config SERIAL_SGI_L1_CONSOLE
|
|||
say Y. Otherwise, say N.
|
||||
|
||||
config SERIAL_MPC52xx
|
||||
tristate "Freescale MPC52xx family PSC serial support"
|
||||
depends on PPC_MPC52xx
|
||||
tristate "Freescale MPC52xx/MPC512x family PSC serial support"
|
||||
depends on PPC_MPC52xx || PPC_MPC512x
|
||||
select SERIAL_CORE
|
||||
help
|
||||
This drivers support the MPC52xx PSC serial ports. If you would
|
||||
like to use them, you must answer Y or M to this option. Not that
|
||||
This driver supports MPC52xx and MPC512x PSC serial ports. If you would
|
||||
like to use them, you must answer Y or M to this option. Note that
|
||||
for use as console, it must be included in kernel and not as a
|
||||
module.
|
||||
|
||||
config SERIAL_MPC52xx_CONSOLE
|
||||
bool "Console on a Freescale MPC52xx family PSC serial port"
|
||||
bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port"
|
||||
depends on SERIAL_MPC52xx=y
|
||||
select SERIAL_CORE_CONSOLE
|
||||
help
|
||||
|
@ -1160,7 +1160,7 @@ config SERIAL_MPC52xx_CONSOLE
|
|||
of the Freescale MPC52xx family as a console.
|
||||
|
||||
config SERIAL_MPC52xx_CONSOLE_BAUD
|
||||
int "Freescale MPC52xx family PSC serial port baud"
|
||||
int "Freescale MPC52xx/MPC512x family PSC serial port baud"
|
||||
depends on SERIAL_MPC52xx_CONSOLE=y
|
||||
default "9600"
|
||||
help
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
* Some of the code has been inspired/copied from the 2.4 code written
|
||||
* by Dale Farnsworth <dfarnsworth@mvista.com>.
|
||||
*
|
||||
* Copyright (C) 2008 Freescale Semiconductor Inc.
|
||||
* John Rigby <jrigby@gmail.com>
|
||||
* Added support for MPC5121
|
||||
* Copyright (C) 2006 Secret Lab Technologies Ltd.
|
||||
* Grant Likely <grant.likely@secretlab.ca>
|
||||
* Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
|
||||
|
@ -67,7 +70,6 @@
|
|||
#include <linux/serial.h>
|
||||
#include <linux/sysrq.h>
|
||||
#include <linux/console.h>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
|
@ -79,6 +81,7 @@
|
|||
#endif
|
||||
|
||||
#include <asm/mpc52xx.h>
|
||||
#include <asm/mpc512x.h>
|
||||
#include <asm/mpc52xx_psc.h>
|
||||
|
||||
#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
||||
|
@ -111,8 +114,8 @@ static struct device_node *mpc52xx_uart_nodes[MPC52xx_PSC_MAXNUM];
|
|||
static void mpc52xx_uart_of_enumerate(void);
|
||||
#endif
|
||||
|
||||
|
||||
#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
|
||||
#define FIFO(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
|
||||
|
||||
|
||||
/* Forward declaration of the interruption handling routine */
|
||||
|
@ -128,15 +131,301 @@ static irqreturn_t mpc52xx_uart_int(int irq, void *dev_id);
|
|||
#define uart_console(port) (0)
|
||||
#endif
|
||||
|
||||
/* ======================================================================== */
|
||||
/* PSC fifo operations for isolating differences between 52xx and 512x */
|
||||
/* ======================================================================== */
|
||||
|
||||
struct psc_ops {
|
||||
void (*fifo_init)(struct uart_port *port);
|
||||
int (*raw_rx_rdy)(struct uart_port *port);
|
||||
int (*raw_tx_rdy)(struct uart_port *port);
|
||||
int (*rx_rdy)(struct uart_port *port);
|
||||
int (*tx_rdy)(struct uart_port *port);
|
||||
int (*tx_empty)(struct uart_port *port);
|
||||
void (*stop_rx)(struct uart_port *port);
|
||||
void (*start_tx)(struct uart_port *port);
|
||||
void (*stop_tx)(struct uart_port *port);
|
||||
void (*rx_clr_irq)(struct uart_port *port);
|
||||
void (*tx_clr_irq)(struct uart_port *port);
|
||||
void (*write_char)(struct uart_port *port, unsigned char c);
|
||||
unsigned char (*read_char)(struct uart_port *port);
|
||||
void (*cw_disable_ints)(struct uart_port *port);
|
||||
void (*cw_restore_ints)(struct uart_port *port);
|
||||
unsigned long (*getuartclk)(void *p);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PPC_MPC52xx
|
||||
#define FIFO_52xx(port) ((struct mpc52xx_psc_fifo __iomem *)(PSC(port)+1))
|
||||
static void mpc52xx_psc_fifo_init(struct uart_port *port)
|
||||
{
|
||||
struct mpc52xx_psc __iomem *psc = PSC(port);
|
||||
struct mpc52xx_psc_fifo __iomem *fifo = FIFO_52xx(port);
|
||||
|
||||
/* /32 prescaler */
|
||||
out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00);
|
||||
|
||||
out_8(&fifo->rfcntl, 0x00);
|
||||
out_be16(&fifo->rfalarm, 0x1ff);
|
||||
out_8(&fifo->tfcntl, 0x07);
|
||||
out_be16(&fifo->tfalarm, 0x80);
|
||||
|
||||
port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
|
||||
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
|
||||
}
|
||||
|
||||
static int mpc52xx_psc_raw_rx_rdy(struct uart_port *port)
|
||||
{
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_status)
|
||||
& MPC52xx_PSC_SR_RXRDY;
|
||||
}
|
||||
|
||||
static int mpc52xx_psc_raw_tx_rdy(struct uart_port *port)
|
||||
{
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_status)
|
||||
& MPC52xx_PSC_SR_TXRDY;
|
||||
}
|
||||
|
||||
|
||||
static int mpc52xx_psc_rx_rdy(struct uart_port *port)
|
||||
{
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_isr)
|
||||
& port->read_status_mask
|
||||
& MPC52xx_PSC_IMR_RXRDY;
|
||||
}
|
||||
|
||||
static int mpc52xx_psc_tx_rdy(struct uart_port *port)
|
||||
{
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_isr)
|
||||
& port->read_status_mask
|
||||
& MPC52xx_PSC_IMR_TXRDY;
|
||||
}
|
||||
|
||||
static int mpc52xx_psc_tx_empty(struct uart_port *port)
|
||||
{
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_status)
|
||||
& MPC52xx_PSC_SR_TXEMP;
|
||||
}
|
||||
|
||||
static void mpc52xx_psc_start_tx(struct uart_port *port)
|
||||
{
|
||||
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
|
||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
||||
}
|
||||
|
||||
static void mpc52xx_psc_stop_tx(struct uart_port *port)
|
||||
{
|
||||
port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
|
||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
||||
}
|
||||
|
||||
static void mpc52xx_psc_stop_rx(struct uart_port *port)
|
||||
{
|
||||
port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
|
||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
||||
}
|
||||
|
||||
static void mpc52xx_psc_rx_clr_irq(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
static void mpc52xx_psc_tx_clr_irq(struct uart_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
static void mpc52xx_psc_write_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
out_8(&PSC(port)->mpc52xx_psc_buffer_8, c);
|
||||
}
|
||||
|
||||
static unsigned char mpc52xx_psc_read_char(struct uart_port *port)
|
||||
{
|
||||
return in_8(&PSC(port)->mpc52xx_psc_buffer_8);
|
||||
}
|
||||
|
||||
static void mpc52xx_psc_cw_disable_ints(struct uart_port *port)
|
||||
{
|
||||
out_be16(&PSC(port)->mpc52xx_psc_imr, 0);
|
||||
}
|
||||
|
||||
static void mpc52xx_psc_cw_restore_ints(struct uart_port *port)
|
||||
{
|
||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
||||
}
|
||||
|
||||
/* Search for bus-frequency property in this node or a parent */
|
||||
static unsigned long mpc52xx_getuartclk(void *p)
|
||||
{
|
||||
#if defined(CONFIG_PPC_MERGE)
|
||||
static struct of_device_id mpc52xx_uart_of_match[] = {
|
||||
{ .type = "serial", .compatible = "fsl,mpc5200-psc-uart", },
|
||||
{ .type = "serial", .compatible = "mpc5200-psc-uart", }, /* lite5200 */
|
||||
{ .type = "serial", .compatible = "mpc5200-serial", }, /* efika */
|
||||
{},
|
||||
/*
|
||||
* 5200 UARTs have a / 32 prescaler
|
||||
* but the generic serial code assumes 16
|
||||
* so return ipb freq / 2
|
||||
*/
|
||||
return mpc52xx_find_ipb_freq(p) / 2;
|
||||
#else
|
||||
pr_debug("unexpected call to mpc52xx_getuartclk with arch/ppc\n");
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static struct psc_ops mpc52xx_psc_ops = {
|
||||
.fifo_init = mpc52xx_psc_fifo_init,
|
||||
.raw_rx_rdy = mpc52xx_psc_raw_rx_rdy,
|
||||
.raw_tx_rdy = mpc52xx_psc_raw_tx_rdy,
|
||||
.rx_rdy = mpc52xx_psc_rx_rdy,
|
||||
.tx_rdy = mpc52xx_psc_tx_rdy,
|
||||
.tx_empty = mpc52xx_psc_tx_empty,
|
||||
.stop_rx = mpc52xx_psc_stop_rx,
|
||||
.start_tx = mpc52xx_psc_start_tx,
|
||||
.stop_tx = mpc52xx_psc_stop_tx,
|
||||
.rx_clr_irq = mpc52xx_psc_rx_clr_irq,
|
||||
.tx_clr_irq = mpc52xx_psc_tx_clr_irq,
|
||||
.write_char = mpc52xx_psc_write_char,
|
||||
.read_char = mpc52xx_psc_read_char,
|
||||
.cw_disable_ints = mpc52xx_psc_cw_disable_ints,
|
||||
.cw_restore_ints = mpc52xx_psc_cw_restore_ints,
|
||||
.getuartclk = mpc52xx_getuartclk,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_MPC52xx */
|
||||
|
||||
#ifdef CONFIG_PPC_MPC512x
|
||||
#define FIFO_512x(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
|
||||
static void mpc512x_psc_fifo_init(struct uart_port *port)
|
||||
{
|
||||
out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
|
||||
out_be32(&FIFO_512x(port)->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
|
||||
out_be32(&FIFO_512x(port)->txalarm, 1);
|
||||
out_be32(&FIFO_512x(port)->tximr, 0);
|
||||
|
||||
out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
|
||||
out_be32(&FIFO_512x(port)->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
|
||||
out_be32(&FIFO_512x(port)->rxalarm, 1);
|
||||
out_be32(&FIFO_512x(port)->rximr, 0);
|
||||
|
||||
out_be32(&FIFO_512x(port)->tximr, MPC512x_PSC_FIFO_ALARM);
|
||||
out_be32(&FIFO_512x(port)->rximr, MPC512x_PSC_FIFO_ALARM);
|
||||
}
|
||||
|
||||
static int mpc512x_psc_raw_rx_rdy(struct uart_port *port)
|
||||
{
|
||||
return !(in_be32(&FIFO_512x(port)->rxsr) & MPC512x_PSC_FIFO_EMPTY);
|
||||
}
|
||||
|
||||
static int mpc512x_psc_raw_tx_rdy(struct uart_port *port)
|
||||
{
|
||||
return !(in_be32(&FIFO_512x(port)->txsr) & MPC512x_PSC_FIFO_FULL);
|
||||
}
|
||||
|
||||
static int mpc512x_psc_rx_rdy(struct uart_port *port)
|
||||
{
|
||||
return in_be32(&FIFO_512x(port)->rxsr)
|
||||
& in_be32(&FIFO_512x(port)->rximr)
|
||||
& MPC512x_PSC_FIFO_ALARM;
|
||||
}
|
||||
|
||||
static int mpc512x_psc_tx_rdy(struct uart_port *port)
|
||||
{
|
||||
return in_be32(&FIFO_512x(port)->txsr)
|
||||
& in_be32(&FIFO_512x(port)->tximr)
|
||||
& MPC512x_PSC_FIFO_ALARM;
|
||||
}
|
||||
|
||||
static int mpc512x_psc_tx_empty(struct uart_port *port)
|
||||
{
|
||||
return in_be32(&FIFO_512x(port)->txsr)
|
||||
& MPC512x_PSC_FIFO_EMPTY;
|
||||
}
|
||||
|
||||
static void mpc512x_psc_stop_rx(struct uart_port *port)
|
||||
{
|
||||
unsigned long rx_fifo_imr;
|
||||
|
||||
rx_fifo_imr = in_be32(&FIFO_512x(port)->rximr);
|
||||
rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
|
||||
out_be32(&FIFO_512x(port)->rximr, rx_fifo_imr);
|
||||
}
|
||||
|
||||
static void mpc512x_psc_start_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned long tx_fifo_imr;
|
||||
|
||||
tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
|
||||
tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
|
||||
out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
|
||||
}
|
||||
|
||||
static void mpc512x_psc_stop_tx(struct uart_port *port)
|
||||
{
|
||||
unsigned long tx_fifo_imr;
|
||||
|
||||
tx_fifo_imr = in_be32(&FIFO_512x(port)->tximr);
|
||||
tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
|
||||
out_be32(&FIFO_512x(port)->tximr, tx_fifo_imr);
|
||||
}
|
||||
|
||||
static void mpc512x_psc_rx_clr_irq(struct uart_port *port)
|
||||
{
|
||||
out_be32(&FIFO_512x(port)->rxisr, in_be32(&FIFO_512x(port)->rxisr));
|
||||
}
|
||||
|
||||
static void mpc512x_psc_tx_clr_irq(struct uart_port *port)
|
||||
{
|
||||
out_be32(&FIFO_512x(port)->txisr, in_be32(&FIFO_512x(port)->txisr));
|
||||
}
|
||||
|
||||
static void mpc512x_psc_write_char(struct uart_port *port, unsigned char c)
|
||||
{
|
||||
out_8(&FIFO_512x(port)->txdata_8, c);
|
||||
}
|
||||
|
||||
static unsigned char mpc512x_psc_read_char(struct uart_port *port)
|
||||
{
|
||||
return in_8(&FIFO_512x(port)->rxdata_8);
|
||||
}
|
||||
|
||||
static void mpc512x_psc_cw_disable_ints(struct uart_port *port)
|
||||
{
|
||||
port->read_status_mask =
|
||||
in_be32(&FIFO_512x(port)->tximr) << 16 |
|
||||
in_be32(&FIFO_512x(port)->rximr);
|
||||
out_be32(&FIFO_512x(port)->tximr, 0);
|
||||
out_be32(&FIFO_512x(port)->rximr, 0);
|
||||
}
|
||||
|
||||
static void mpc512x_psc_cw_restore_ints(struct uart_port *port)
|
||||
{
|
||||
out_be32(&FIFO_512x(port)->tximr,
|
||||
(port->read_status_mask >> 16) & 0x7f);
|
||||
out_be32(&FIFO_512x(port)->rximr, port->read_status_mask & 0x7f);
|
||||
}
|
||||
|
||||
static unsigned long mpc512x_getuartclk(void *p)
|
||||
{
|
||||
return mpc512x_find_ips_freq(p);
|
||||
}
|
||||
|
||||
static struct psc_ops mpc512x_psc_ops = {
|
||||
.fifo_init = mpc512x_psc_fifo_init,
|
||||
.raw_rx_rdy = mpc512x_psc_raw_rx_rdy,
|
||||
.raw_tx_rdy = mpc512x_psc_raw_tx_rdy,
|
||||
.rx_rdy = mpc512x_psc_rx_rdy,
|
||||
.tx_rdy = mpc512x_psc_tx_rdy,
|
||||
.tx_empty = mpc512x_psc_tx_empty,
|
||||
.stop_rx = mpc512x_psc_stop_rx,
|
||||
.start_tx = mpc512x_psc_start_tx,
|
||||
.stop_tx = mpc512x_psc_stop_tx,
|
||||
.rx_clr_irq = mpc512x_psc_rx_clr_irq,
|
||||
.tx_clr_irq = mpc512x_psc_tx_clr_irq,
|
||||
.write_char = mpc512x_psc_write_char,
|
||||
.read_char = mpc512x_psc_read_char,
|
||||
.cw_disable_ints = mpc512x_psc_cw_disable_ints,
|
||||
.cw_restore_ints = mpc512x_psc_cw_restore_ints,
|
||||
.getuartclk = mpc512x_getuartclk,
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct psc_ops *psc_ops;
|
||||
|
||||
/* ======================================================================== */
|
||||
/* UART operations */
|
||||
|
@ -145,8 +434,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
|
|||
static unsigned int
|
||||
mpc52xx_uart_tx_empty(struct uart_port *port)
|
||||
{
|
||||
int status = in_be16(&PSC(port)->mpc52xx_psc_status);
|
||||
return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
|
||||
return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -166,16 +454,14 @@ static void
|
|||
mpc52xx_uart_stop_tx(struct uart_port *port)
|
||||
{
|
||||
/* port->lock taken by caller */
|
||||
port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
|
||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
||||
psc_ops->stop_tx(port);
|
||||
}
|
||||
|
||||
static void
|
||||
mpc52xx_uart_start_tx(struct uart_port *port)
|
||||
{
|
||||
/* port->lock taken by caller */
|
||||
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
|
||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
||||
psc_ops->start_tx(port);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -188,8 +474,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
|
|||
if (ch) {
|
||||
/* Make sure tx interrupts are on */
|
||||
/* Truly necessary ??? They should be anyway */
|
||||
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
|
||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
||||
psc_ops->start_tx(port);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
|
@ -199,8 +484,7 @@ static void
|
|||
mpc52xx_uart_stop_rx(struct uart_port *port)
|
||||
{
|
||||
/* port->lock taken by caller */
|
||||
port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
|
||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
||||
psc_ops->stop_rx(port);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -227,12 +511,12 @@ static int
|
|||
mpc52xx_uart_startup(struct uart_port *port)
|
||||
{
|
||||
struct mpc52xx_psc __iomem *psc = PSC(port);
|
||||
struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port);
|
||||
int ret;
|
||||
|
||||
/* Request IRQ */
|
||||
ret = request_irq(port->irq, mpc52xx_uart_int,
|
||||
IRQF_DISABLED | IRQF_SAMPLE_RANDOM, "mpc52xx_psc_uart", port);
|
||||
IRQF_DISABLED | IRQF_SAMPLE_RANDOM | IRQF_SHARED,
|
||||
"mpc52xx_psc_uart", port);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -242,15 +526,7 @@ mpc52xx_uart_startup(struct uart_port *port)
|
|||
|
||||
out_be32(&psc->sicr, 0); /* UART mode DCD ignored */
|
||||
|
||||
out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
|
||||
|
||||
out_8(&fifo->rfcntl, 0x00);
|
||||
out_be16(&fifo->rfalarm, 0x1ff);
|
||||
out_8(&fifo->tfcntl, 0x07);
|
||||
out_be16(&fifo->tfalarm, 0x80);
|
||||
|
||||
port->read_status_mask |= MPC52xx_PSC_IMR_RXRDY | MPC52xx_PSC_IMR_TXRDY;
|
||||
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
|
||||
psc_ops->fifo_init(port);
|
||||
|
||||
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
|
||||
out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
|
||||
|
@ -333,8 +609,7 @@ mpc52xx_uart_set_termios(struct uart_port *port, struct ktermios *new,
|
|||
* boot for the console, all stuff is not yet ready to receive at that
|
||||
* time and that just makes the kernel oops */
|
||||
/* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
|
||||
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
|
||||
--j)
|
||||
while (!mpc52xx_uart_tx_empty(port) && --j)
|
||||
udelay(1);
|
||||
|
||||
if (!j)
|
||||
|
@ -462,11 +737,9 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
|||
unsigned short status;
|
||||
|
||||
/* While we can read, do so ! */
|
||||
while ((status = in_be16(&PSC(port)->mpc52xx_psc_status)) &
|
||||
MPC52xx_PSC_SR_RXRDY) {
|
||||
|
||||
while (psc_ops->raw_rx_rdy(port)) {
|
||||
/* Get the char */
|
||||
ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8);
|
||||
ch = psc_ops->read_char(port);
|
||||
|
||||
/* Handle sysreq char */
|
||||
#ifdef SUPPORT_SYSRQ
|
||||
|
@ -481,6 +754,8 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
|||
flag = TTY_NORMAL;
|
||||
port->icount.rx++;
|
||||
|
||||
status = in_be16(&PSC(port)->mpc52xx_psc_status);
|
||||
|
||||
if (status & (MPC52xx_PSC_SR_PE |
|
||||
MPC52xx_PSC_SR_FE |
|
||||
MPC52xx_PSC_SR_RB)) {
|
||||
|
@ -510,7 +785,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
|||
|
||||
tty_flip_buffer_push(tty);
|
||||
|
||||
return in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_RXRDY;
|
||||
return psc_ops->raw_rx_rdy(port);
|
||||
}
|
||||
|
||||
static inline int
|
||||
|
@ -520,7 +795,7 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
|
|||
|
||||
/* Process out of band chars */
|
||||
if (port->x_char) {
|
||||
out_8(&PSC(port)->mpc52xx_psc_buffer_8, port->x_char);
|
||||
psc_ops->write_char(port, port->x_char);
|
||||
port->icount.tx++;
|
||||
port->x_char = 0;
|
||||
return 1;
|
||||
|
@ -533,8 +808,8 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
|
|||
}
|
||||
|
||||
/* Send chars */
|
||||
while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) {
|
||||
out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]);
|
||||
while (psc_ops->raw_tx_rdy(port)) {
|
||||
psc_ops->write_char(port, xmit->buf[xmit->tail]);
|
||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||
port->icount.tx++;
|
||||
if (uart_circ_empty(xmit))
|
||||
|
@ -560,7 +835,6 @@ mpc52xx_uart_int(int irq, void *dev_id)
|
|||
struct uart_port *port = dev_id;
|
||||
unsigned long pass = ISR_PASS_LIMIT;
|
||||
unsigned int keepgoing;
|
||||
unsigned short status;
|
||||
|
||||
spin_lock(&port->lock);
|
||||
|
||||
|
@ -569,18 +843,12 @@ mpc52xx_uart_int(int irq, void *dev_id)
|
|||
/* If we don't find anything to do, we stop */
|
||||
keepgoing = 0;
|
||||
|
||||
/* Read status */
|
||||
status = in_be16(&PSC(port)->mpc52xx_psc_isr);
|
||||
status &= port->read_status_mask;
|
||||
|
||||
/* Do we need to receive chars ? */
|
||||
/* For this RX interrupts must be on and some chars waiting */
|
||||
if (status & MPC52xx_PSC_IMR_RXRDY)
|
||||
psc_ops->rx_clr_irq(port);
|
||||
if (psc_ops->rx_rdy(port))
|
||||
keepgoing |= mpc52xx_uart_int_rx_chars(port);
|
||||
|
||||
/* Do we need to send chars ? */
|
||||
/* For this, TX must be ready and TX interrupt enabled */
|
||||
if (status & MPC52xx_PSC_IMR_TXRDY)
|
||||
psc_ops->tx_clr_irq(port);
|
||||
if (psc_ops->tx_rdy(port))
|
||||
keepgoing |= mpc52xx_uart_int_tx_chars(port);
|
||||
|
||||
/* Limit number of iteration */
|
||||
|
@ -647,36 +915,33 @@ static void
|
|||
mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
|
||||
{
|
||||
struct uart_port *port = &mpc52xx_uart_ports[co->index];
|
||||
struct mpc52xx_psc __iomem *psc = PSC(port);
|
||||
unsigned int i, j;
|
||||
|
||||
/* Disable interrupts */
|
||||
out_be16(&psc->mpc52xx_psc_imr, 0);
|
||||
psc_ops->cw_disable_ints(port);
|
||||
|
||||
/* Wait the TX buffer to be empty */
|
||||
j = 5000000; /* Maximum wait */
|
||||
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
|
||||
--j)
|
||||
while (!mpc52xx_uart_tx_empty(port) && --j)
|
||||
udelay(1);
|
||||
|
||||
/* Write all the chars */
|
||||
for (i = 0; i < count; i++, s++) {
|
||||
/* Line return handling */
|
||||
if (*s == '\n')
|
||||
out_8(&psc->mpc52xx_psc_buffer_8, '\r');
|
||||
psc_ops->write_char(port, '\r');
|
||||
|
||||
/* Send the char */
|
||||
out_8(&psc->mpc52xx_psc_buffer_8, *s);
|
||||
psc_ops->write_char(port, *s);
|
||||
|
||||
/* Wait the TX buffer to be empty */
|
||||
j = 20000; /* Maximum wait */
|
||||
while (!(in_be16(&psc->mpc52xx_psc_status) &
|
||||
MPC52xx_PSC_SR_TXEMP) && --j)
|
||||
while (!mpc52xx_uart_tx_empty(port) && --j)
|
||||
udelay(1);
|
||||
}
|
||||
|
||||
/* Restore interrupt state */
|
||||
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
|
||||
psc_ops->cw_restore_ints(port);
|
||||
}
|
||||
|
||||
#if !defined(CONFIG_PPC_MERGE)
|
||||
|
@ -721,7 +986,7 @@ mpc52xx_console_setup(struct console *co, char *options)
|
|||
{
|
||||
struct uart_port *port = &mpc52xx_uart_ports[co->index];
|
||||
struct device_node *np = mpc52xx_uart_nodes[co->index];
|
||||
unsigned int ipb_freq;
|
||||
unsigned int uartclk;
|
||||
struct resource res;
|
||||
int ret;
|
||||
|
||||
|
@ -753,17 +1018,16 @@ mpc52xx_console_setup(struct console *co, char *options)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Search for bus-frequency property in this node or a parent */
|
||||
ipb_freq = mpc52xx_find_ipb_freq(np);
|
||||
if (ipb_freq == 0) {
|
||||
pr_debug("Could not find IPB bus frequency!\n");
|
||||
uartclk = psc_ops->getuartclk(np);
|
||||
if (uartclk == 0) {
|
||||
pr_debug("Could not find uart clock frequency!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Basic port init. Needed since we use some uart_??? func before
|
||||
* real init for early access */
|
||||
spin_lock_init(&port->lock);
|
||||
port->uartclk = ipb_freq / 2;
|
||||
port->uartclk = uartclk;
|
||||
port->ops = &mpc52xx_uart_ops;
|
||||
port->mapbase = res.start;
|
||||
port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
|
||||
|
@ -945,11 +1209,25 @@ static struct platform_driver mpc52xx_uart_platform_driver = {
|
|||
/* OF Platform Driver */
|
||||
/* ======================================================================== */
|
||||
|
||||
static struct of_device_id mpc52xx_uart_of_match[] = {
|
||||
#ifdef CONFIG_PPC_MPC52xx
|
||||
{ .compatible = "fsl,mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
|
||||
/* binding used by old lite5200 device trees: */
|
||||
{ .compatible = "mpc5200-psc-uart", .data = &mpc52xx_psc_ops, },
|
||||
/* binding used by efika: */
|
||||
{ .compatible = "mpc5200-serial", .data = &mpc52xx_psc_ops, },
|
||||
#endif
|
||||
#ifdef CONFIG_PPC_MPC512x
|
||||
{ .compatible = "fsl,mpc5121-psc-uart", .data = &mpc512x_psc_ops, },
|
||||
{},
|
||||
#endif
|
||||
};
|
||||
|
||||
static int __devinit
|
||||
mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
|
||||
{
|
||||
int idx = -1;
|
||||
unsigned int ipb_freq;
|
||||
unsigned int uartclk;
|
||||
struct uart_port *port = NULL;
|
||||
struct resource res;
|
||||
int ret;
|
||||
|
@ -965,10 +1243,9 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
|
|||
pr_debug("Found %s assigned to ttyPSC%x\n",
|
||||
mpc52xx_uart_nodes[idx]->full_name, idx);
|
||||
|
||||
/* Search for bus-frequency property in this node or a parent */
|
||||
ipb_freq = mpc52xx_find_ipb_freq(op->node);
|
||||
if (ipb_freq == 0) {
|
||||
dev_dbg(&op->dev, "Could not find IPB bus frequency!\n");
|
||||
uartclk = psc_ops->getuartclk(op->node);
|
||||
if (uartclk == 0) {
|
||||
dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -976,7 +1253,7 @@ mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
|
|||
port = &mpc52xx_uart_ports[idx];
|
||||
|
||||
spin_lock_init(&port->lock);
|
||||
port->uartclk = ipb_freq / 2;
|
||||
port->uartclk = uartclk;
|
||||
port->fifosize = 512;
|
||||
port->iotype = UPIO_MEM;
|
||||
port->flags = UPF_BOOT_AUTOCONF |
|
||||
|
@ -1080,15 +1357,19 @@ mpc52xx_uart_of_enumerate(void)
|
|||
static int enum_done;
|
||||
struct device_node *np;
|
||||
const unsigned int *devno;
|
||||
const struct of_device_id *match;
|
||||
int i;
|
||||
|
||||
if (enum_done)
|
||||
return;
|
||||
|
||||
for_each_node_by_type(np, "serial") {
|
||||
if (!of_match_node(mpc52xx_uart_of_match, np))
|
||||
match = of_match_node(mpc52xx_uart_of_match, np);
|
||||
if (!match)
|
||||
continue;
|
||||
|
||||
psc_ops = match->data;
|
||||
|
||||
/* Is a particular device number requested? */
|
||||
devno = of_get_property(np, "port-number", NULL);
|
||||
mpc52xx_uart_of_assign(np, devno ? *devno : -1);
|
||||
|
@ -1149,6 +1430,7 @@ mpc52xx_uart_init(void)
|
|||
return ret;
|
||||
}
|
||||
#else
|
||||
psc_ops = &mpc52xx_psc_ops;
|
||||
ret = platform_driver_register(&mpc52xx_uart_platform_driver);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
|
||||
|
|
|
@ -17,10 +17,21 @@
|
|||
#include <linux/tty.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
#include <asm/io.h>
|
||||
#if defined(CONFIG_OF)
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static struct of_device_id ulite_of_match[] __devinitdata = {
|
||||
{ .compatible = "xlnx,opb-uartlite-1.00.b", },
|
||||
{ .compatible = "xlnx,xps-uartlite-1.00.a", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ulite_of_match);
|
||||
|
||||
#endif
|
||||
|
||||
#define ULITE_NAME "ttyUL"
|
||||
|
@ -275,6 +286,9 @@ static void ulite_release_port(struct uart_port *port)
|
|||
|
||||
static int ulite_request_port(struct uart_port *port)
|
||||
{
|
||||
pr_debug("ulite console: port=%p; port->mapbase=%x\n",
|
||||
port, port->mapbase);
|
||||
|
||||
if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
|
||||
dev_err(port->dev, "Memory region busy\n");
|
||||
return -EBUSY;
|
||||
|
@ -375,32 +389,6 @@ static void ulite_console_write(struct console *co, const char *s,
|
|||
spin_unlock_irqrestore(&port->lock, flags);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_OF)
|
||||
static inline void __init ulite_console_of_find_device(int id)
|
||||
{
|
||||
struct device_node *np;
|
||||
struct resource res;
|
||||
const unsigned int *of_id;
|
||||
int rc;
|
||||
|
||||
for_each_compatible_node(np, NULL, "xilinx,uartlite") {
|
||||
of_id = of_get_property(np, "port-number", NULL);
|
||||
if ((!of_id) || (*of_id != id))
|
||||
continue;
|
||||
|
||||
rc = of_address_to_resource(np, 0, &res);
|
||||
if (rc)
|
||||
continue;
|
||||
|
||||
ulite_ports[id].mapbase = res.start;
|
||||
of_node_put(np);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#else /* CONFIG_OF */
|
||||
static inline void __init ulite_console_of_find_device(int id) { /* do nothing */ }
|
||||
#endif /* CONFIG_OF */
|
||||
|
||||
static int __init ulite_console_setup(struct console *co, char *options)
|
||||
{
|
||||
struct uart_port *port;
|
||||
|
@ -414,11 +402,7 @@ static int __init ulite_console_setup(struct console *co, char *options)
|
|||
|
||||
port = &ulite_ports[co->index];
|
||||
|
||||
/* Check if it is an OF device */
|
||||
if (!port->mapbase)
|
||||
ulite_console_of_find_device(co->index);
|
||||
|
||||
/* Do we have a device now? */
|
||||
/* Has the device been initialized yet? */
|
||||
if (!port->mapbase) {
|
||||
pr_debug("console on ttyUL%i not present\n", co->index);
|
||||
return -ENODEV;
|
||||
|
@ -617,13 +601,6 @@ static int __devexit ulite_of_remove(struct of_device *op)
|
|||
return ulite_release(&op->dev);
|
||||
}
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static struct of_device_id __devinit ulite_of_match[] = {
|
||||
{ .type = "serial", .compatible = "xilinx,uartlite", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ulite_of_match);
|
||||
|
||||
static struct of_platform_driver ulite_of_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "uartlite",
|
||||
|
|
|
@ -459,8 +459,8 @@ static int __devexit xilinxfb_of_remove(struct of_device *op)
|
|||
}
|
||||
|
||||
/* Match table for of_platform binding */
|
||||
static struct of_device_id __devinit xilinxfb_of_match[] = {
|
||||
{ .compatible = "xilinx,ml300-fb", },
|
||||
static struct of_device_id xilinxfb_of_match[] __devinitdata = {
|
||||
{ .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
|
||||
|
|
|
@ -46,7 +46,7 @@ enum powerpc_oprofile_type {
|
|||
PPC_OPROFILE_RS64 = 1,
|
||||
PPC_OPROFILE_POWER4 = 2,
|
||||
PPC_OPROFILE_G4 = 3,
|
||||
PPC_OPROFILE_BOOKE = 4,
|
||||
PPC_OPROFILE_FSL_EMB = 4,
|
||||
PPC_OPROFILE_CELL = 5,
|
||||
PPC_OPROFILE_PA6T = 6,
|
||||
};
|
||||
|
|
|
@ -59,25 +59,36 @@ do { \
|
|||
/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
|
||||
extern spinlock_t dcr_ind_lock;
|
||||
|
||||
#define mfdcri(base, reg) \
|
||||
({ \
|
||||
unsigned long flags; \
|
||||
unsigned int val; \
|
||||
spin_lock_irqsave(&dcr_ind_lock, flags); \
|
||||
mtdcr(DCRN_ ## base ## _CONFIG_ADDR, reg); \
|
||||
val = mfdcr(DCRN_ ## base ## _CONFIG_DATA); \
|
||||
spin_unlock_irqrestore(&dcr_ind_lock, flags); \
|
||||
val; \
|
||||
})
|
||||
static inline unsigned __mfdcri(int base_addr, int base_data, int reg)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int val;
|
||||
|
||||
#define mtdcri(base, reg, data) \
|
||||
do { \
|
||||
unsigned long flags; \
|
||||
spin_lock_irqsave(&dcr_ind_lock, flags); \
|
||||
mtdcr(DCRN_ ## base ## _CONFIG_ADDR, reg); \
|
||||
mtdcr(DCRN_ ## base ## _CONFIG_DATA, data); \
|
||||
spin_unlock_irqrestore(&dcr_ind_lock, flags); \
|
||||
} while (0)
|
||||
spin_lock_irqsave(&dcr_ind_lock, flags);
|
||||
__mtdcr(base_addr, reg);
|
||||
val = __mfdcr(base_data);
|
||||
spin_unlock_irqrestore(&dcr_ind_lock, flags);
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void __mtdcri(int base_addr, int base_data, int reg,
|
||||
unsigned val)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dcr_ind_lock, flags);
|
||||
__mtdcr(base_addr, reg);
|
||||
__mtdcr(base_data, val);
|
||||
spin_unlock_irqrestore(&dcr_ind_lock, flags);
|
||||
}
|
||||
|
||||
#define mfdcri(base, reg) __mfdcri(DCRN_ ## base ## _CONFIG_ADDR, \
|
||||
DCRN_ ## base ## _CONFIG_DATA, \
|
||||
reg)
|
||||
|
||||
#define mtdcri(base, reg, data) __mtdcri(DCRN_ ## base ## _CONFIG_ADDR, \
|
||||
DCRN_ ## base ## _CONFIG_DATA, \
|
||||
reg, data)
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
#endif /* __KERNEL__ */
|
||||
|
|
|
@ -165,8 +165,10 @@ typedef elf_vrreg_t elf_vrregset_t32[ELF_NVRREG32];
|
|||
* This is used to ensure we don't load something for the wrong architecture.
|
||||
*/
|
||||
#define elf_check_arch(x) ((x)->e_machine == ELF_ARCH)
|
||||
#define compat_elf_check_arch(x) ((x)->e_machine == EM_PPC)
|
||||
|
||||
#define USE_ELF_CORE_DUMP
|
||||
#define CORE_DUMP_USE_REGSET
|
||||
#define ELF_EXEC_PAGESIZE PAGE_SIZE
|
||||
|
||||
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
|
||||
|
|
22
include/asm-powerpc/mpc512x.h
Normal file
22
include/asm-powerpc/mpc512x.h
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
|
||||
*
|
||||
* Author: John Rigby, <jrigby@freescale.com>, Friday Apr 13 2007
|
||||
*
|
||||
* Description:
|
||||
* MPC5121 Prototypes and definitions
|
||||
*
|
||||
* This 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __ASM_POWERPC_MPC512x_H__
|
||||
#define __ASM_POWERPC_MPC512x_H__
|
||||
|
||||
extern unsigned long mpc512x_find_ips_freq(struct device_node *node);
|
||||
|
||||
#endif /* __ASM_POWERPC_MPC512x_H__ */
|
||||
|
|
@ -190,5 +190,53 @@ struct mpc52xx_psc_fifo {
|
|||
u16 tflwfptr; /* PSC + 0x9e */
|
||||
};
|
||||
|
||||
#define MPC512x_PSC_FIFO_RESET_SLICE 0x80
|
||||
#define MPC512x_PSC_FIFO_ENABLE_SLICE 0x01
|
||||
#define MPC512x_PSC_FIFO_ENABLE_DMA 0x04
|
||||
|
||||
#define MPC512x_PSC_FIFO_EMPTY 0x1
|
||||
#define MPC512x_PSC_FIFO_FULL 0x2
|
||||
#define MPC512x_PSC_FIFO_ALARM 0x4
|
||||
#define MPC512x_PSC_FIFO_URERR 0x8
|
||||
#define MPC512x_PSC_FIFO_ORERR 0x01
|
||||
#define MPC512x_PSC_FIFO_MEMERROR 0x02
|
||||
|
||||
struct mpc512x_psc_fifo {
|
||||
u32 reserved1[10];
|
||||
u32 txcmd; /* PSC + 0x80 */
|
||||
u32 txalarm; /* PSC + 0x84 */
|
||||
u32 txsr; /* PSC + 0x88 */
|
||||
u32 txisr; /* PSC + 0x8c */
|
||||
u32 tximr; /* PSC + 0x90 */
|
||||
u32 txcnt; /* PSC + 0x94 */
|
||||
u32 txptr; /* PSC + 0x98 */
|
||||
u32 txsz; /* PSC + 0x9c */
|
||||
u32 reserved2[7];
|
||||
union {
|
||||
u8 txdata_8;
|
||||
u16 txdata_16;
|
||||
u32 txdata_32;
|
||||
} txdata; /* PSC + 0xbc */
|
||||
#define txdata_8 txdata.txdata_8
|
||||
#define txdata_16 txdata.txdata_16
|
||||
#define txdata_32 txdata.txdata_32
|
||||
u32 rxcmd; /* PSC + 0xc0 */
|
||||
u32 rxalarm; /* PSC + 0xc4 */
|
||||
u32 rxsr; /* PSC + 0xc8 */
|
||||
u32 rxisr; /* PSC + 0xcc */
|
||||
u32 rximr; /* PSC + 0xd0 */
|
||||
u32 rxcnt; /* PSC + 0xd4 */
|
||||
u32 rxptr; /* PSC + 0xd8 */
|
||||
u32 rxsz; /* PSC + 0xdc */
|
||||
u32 reserved3[7];
|
||||
union {
|
||||
u8 rxdata_8;
|
||||
u16 rxdata_16;
|
||||
u32 rxdata_32;
|
||||
} rxdata; /* PSC + 0xfc */
|
||||
#define rxdata_8 rxdata.rxdata_8
|
||||
#define rxdata_16 rxdata.rxdata_16
|
||||
#define rxdata_32 rxdata.rxdata_32
|
||||
};
|
||||
|
||||
#endif /* __ASM_MPC52xx_PSC_H__ */
|
||||
|
|
|
@ -54,7 +54,7 @@ struct op_powerpc_model {
|
|||
int num_counters;
|
||||
};
|
||||
|
||||
extern struct op_powerpc_model op_model_fsl_booke;
|
||||
extern struct op_powerpc_model op_model_fsl_emb;
|
||||
extern struct op_powerpc_model op_model_rs64;
|
||||
extern struct op_powerpc_model op_model_power4;
|
||||
extern struct op_powerpc_model op_model_7450;
|
||||
|
|
|
@ -55,6 +55,8 @@ struct pt_regs {
|
|||
|
||||
#ifdef __powerpc64__
|
||||
|
||||
#define __ARCH_WANT_COMPAT_SYS_PTRACE
|
||||
|
||||
#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */
|
||||
|
||||
/* Size of dummy stack frame allocated when calling signal handler. */
|
||||
|
|
|
@ -18,6 +18,10 @@
|
|||
#include <asm/reg_booke.h>
|
||||
#endif /* CONFIG_BOOKE || CONFIG_40x */
|
||||
|
||||
#ifdef CONFIG_FSL_EMB_PERFMON
|
||||
#include <asm/reg_fsl_emb.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_8xx
|
||||
#include <asm/reg_8xx.h>
|
||||
#endif /* CONFIG_8xx */
|
||||
|
|
|
@ -9,68 +9,6 @@
|
|||
#ifndef __ASM_POWERPC_REG_BOOKE_H__
|
||||
#define __ASM_POWERPC_REG_BOOKE_H__
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/* Performance Monitor Registers */
|
||||
#define mfpmr(rn) ({unsigned int rval; \
|
||||
asm volatile("mfpmr %0," __stringify(rn) \
|
||||
: "=r" (rval)); rval;})
|
||||
#define mtpmr(rn, v) asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v))
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
/* Freescale Book E Performance Monitor APU Registers */
|
||||
#define PMRN_PMC0 0x010 /* Performance Monitor Counter 0 */
|
||||
#define PMRN_PMC1 0x011 /* Performance Monitor Counter 1 */
|
||||
#define PMRN_PMC2 0x012 /* Performance Monitor Counter 1 */
|
||||
#define PMRN_PMC3 0x013 /* Performance Monitor Counter 1 */
|
||||
#define PMRN_PMLCA0 0x090 /* PM Local Control A0 */
|
||||
#define PMRN_PMLCA1 0x091 /* PM Local Control A1 */
|
||||
#define PMRN_PMLCA2 0x092 /* PM Local Control A2 */
|
||||
#define PMRN_PMLCA3 0x093 /* PM Local Control A3 */
|
||||
|
||||
#define PMLCA_FC 0x80000000 /* Freeze Counter */
|
||||
#define PMLCA_FCS 0x40000000 /* Freeze in Supervisor */
|
||||
#define PMLCA_FCU 0x20000000 /* Freeze in User */
|
||||
#define PMLCA_FCM1 0x10000000 /* Freeze when PMM==1 */
|
||||
#define PMLCA_FCM0 0x08000000 /* Freeze when PMM==0 */
|
||||
#define PMLCA_CE 0x04000000 /* Condition Enable */
|
||||
|
||||
#define PMLCA_EVENT_MASK 0x007f0000 /* Event field */
|
||||
#define PMLCA_EVENT_SHIFT 16
|
||||
|
||||
#define PMRN_PMLCB0 0x110 /* PM Local Control B0 */
|
||||
#define PMRN_PMLCB1 0x111 /* PM Local Control B1 */
|
||||
#define PMRN_PMLCB2 0x112 /* PM Local Control B2 */
|
||||
#define PMRN_PMLCB3 0x113 /* PM Local Control B3 */
|
||||
|
||||
#define PMLCB_THRESHMUL_MASK 0x0700 /* Threshhold Multiple Field */
|
||||
#define PMLCB_THRESHMUL_SHIFT 8
|
||||
|
||||
#define PMLCB_THRESHOLD_MASK 0x003f /* Threshold Field */
|
||||
#define PMLCB_THRESHOLD_SHIFT 0
|
||||
|
||||
#define PMRN_PMGC0 0x190 /* PM Global Control 0 */
|
||||
|
||||
#define PMGC0_FAC 0x80000000 /* Freeze all Counters */
|
||||
#define PMGC0_PMIE 0x40000000 /* Interrupt Enable */
|
||||
#define PMGC0_FCECE 0x20000000 /* Freeze countes on
|
||||
Enabled Condition or
|
||||
Event */
|
||||
|
||||
#define PMRN_UPMC0 0x000 /* User Performance Monitor Counter 0 */
|
||||
#define PMRN_UPMC1 0x001 /* User Performance Monitor Counter 1 */
|
||||
#define PMRN_UPMC2 0x002 /* User Performance Monitor Counter 1 */
|
||||
#define PMRN_UPMC3 0x003 /* User Performance Monitor Counter 1 */
|
||||
#define PMRN_UPMLCA0 0x080 /* User PM Local Control A0 */
|
||||
#define PMRN_UPMLCA1 0x081 /* User PM Local Control A1 */
|
||||
#define PMRN_UPMLCA2 0x082 /* User PM Local Control A2 */
|
||||
#define PMRN_UPMLCA3 0x083 /* User PM Local Control A3 */
|
||||
#define PMRN_UPMLCB0 0x100 /* User PM Local Control B0 */
|
||||
#define PMRN_UPMLCB1 0x101 /* User PM Local Control B1 */
|
||||
#define PMRN_UPMLCB2 0x102 /* User PM Local Control B2 */
|
||||
#define PMRN_UPMLCB3 0x103 /* User PM Local Control B3 */
|
||||
#define PMRN_UPMGC0 0x180 /* User PM Global Control 0 */
|
||||
|
||||
|
||||
/* Machine State Register (MSR) Fields */
|
||||
#define MSR_UCLE (1<<26) /* User-mode cache lock enable */
|
||||
#define MSR_SPE (1<<25) /* Enable SPE */
|
||||
|
|
72
include/asm-powerpc/reg_fsl_emb.h
Normal file
72
include/asm-powerpc/reg_fsl_emb.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* Contains register definitions for the Freescale Embedded Performance
|
||||
* Monitor.
|
||||
*/
|
||||
#ifdef __KERNEL__
|
||||
#ifndef __ASM_POWERPC_REG_FSL_EMB_H__
|
||||
#define __ASM_POWERPC_REG_FSL_EMB_H__
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
/* Performance Monitor Registers */
|
||||
#define mfpmr(rn) ({unsigned int rval; \
|
||||
asm volatile("mfpmr %0," __stringify(rn) \
|
||||
: "=r" (rval)); rval;})
|
||||
#define mtpmr(rn, v) asm volatile("mtpmr " __stringify(rn) ",%0" : : "r" (v))
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
/* Freescale Book E Performance Monitor APU Registers */
|
||||
#define PMRN_PMC0 0x010 /* Performance Monitor Counter 0 */
|
||||
#define PMRN_PMC1 0x011 /* Performance Monitor Counter 1 */
|
||||
#define PMRN_PMC2 0x012 /* Performance Monitor Counter 1 */
|
||||
#define PMRN_PMC3 0x013 /* Performance Monitor Counter 1 */
|
||||
#define PMRN_PMLCA0 0x090 /* PM Local Control A0 */
|
||||
#define PMRN_PMLCA1 0x091 /* PM Local Control A1 */
|
||||
#define PMRN_PMLCA2 0x092 /* PM Local Control A2 */
|
||||
#define PMRN_PMLCA3 0x093 /* PM Local Control A3 */
|
||||
|
||||
#define PMLCA_FC 0x80000000 /* Freeze Counter */
|
||||
#define PMLCA_FCS 0x40000000 /* Freeze in Supervisor */
|
||||
#define PMLCA_FCU 0x20000000 /* Freeze in User */
|
||||
#define PMLCA_FCM1 0x10000000 /* Freeze when PMM==1 */
|
||||
#define PMLCA_FCM0 0x08000000 /* Freeze when PMM==0 */
|
||||
#define PMLCA_CE 0x04000000 /* Condition Enable */
|
||||
|
||||
#define PMLCA_EVENT_MASK 0x007f0000 /* Event field */
|
||||
#define PMLCA_EVENT_SHIFT 16
|
||||
|
||||
#define PMRN_PMLCB0 0x110 /* PM Local Control B0 */
|
||||
#define PMRN_PMLCB1 0x111 /* PM Local Control B1 */
|
||||
#define PMRN_PMLCB2 0x112 /* PM Local Control B2 */
|
||||
#define PMRN_PMLCB3 0x113 /* PM Local Control B3 */
|
||||
|
||||
#define PMLCB_THRESHMUL_MASK 0x0700 /* Threshhold Multiple Field */
|
||||
#define PMLCB_THRESHMUL_SHIFT 8
|
||||
|
||||
#define PMLCB_THRESHOLD_MASK 0x003f /* Threshold Field */
|
||||
#define PMLCB_THRESHOLD_SHIFT 0
|
||||
|
||||
#define PMRN_PMGC0 0x190 /* PM Global Control 0 */
|
||||
|
||||
#define PMGC0_FAC 0x80000000 /* Freeze all Counters */
|
||||
#define PMGC0_PMIE 0x40000000 /* Interrupt Enable */
|
||||
#define PMGC0_FCECE 0x20000000 /* Freeze countes on
|
||||
Enabled Condition or
|
||||
Event */
|
||||
|
||||
#define PMRN_UPMC0 0x000 /* User Performance Monitor Counter 0 */
|
||||
#define PMRN_UPMC1 0x001 /* User Performance Monitor Counter 1 */
|
||||
#define PMRN_UPMC2 0x002 /* User Performance Monitor Counter 1 */
|
||||
#define PMRN_UPMC3 0x003 /* User Performance Monitor Counter 1 */
|
||||
#define PMRN_UPMLCA0 0x080 /* User PM Local Control A0 */
|
||||
#define PMRN_UPMLCA1 0x081 /* User PM Local Control A1 */
|
||||
#define PMRN_UPMLCA2 0x082 /* User PM Local Control A2 */
|
||||
#define PMRN_UPMLCA3 0x083 /* User PM Local Control A3 */
|
||||
#define PMRN_UPMLCB0 0x100 /* User PM Local Control B0 */
|
||||
#define PMRN_UPMLCB1 0x101 /* User PM Local Control B1 */
|
||||
#define PMRN_UPMLCB2 0x102 /* User PM Local Control B2 */
|
||||
#define PMRN_UPMLCB3 0x103 /* User PM Local Control B3 */
|
||||
#define PMRN_UPMGC0 0x180 /* User PM Global Control 0 */
|
||||
|
||||
|
||||
#endif /* __ASM_POWERPC_REG_FSL_EMB_H__ */
|
||||
#endif /* __KERNEL__ */
|
|
@ -65,7 +65,7 @@
|
|||
struct task_struct;
|
||||
struct pt_regs;
|
||||
|
||||
#ifdef CONFIG_DEBUGGER
|
||||
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
|
||||
|
||||
extern int (*__debugger)(struct pt_regs *regs);
|
||||
extern int (*__debugger_ipi)(struct pt_regs *regs);
|
||||
|
|
|
@ -66,7 +66,7 @@ extern void __devinit vio_unregister_device(struct vio_dev *dev);
|
|||
|
||||
struct device_node;
|
||||
|
||||
extern struct vio_dev * __devinit vio_register_device_node(
|
||||
extern struct vio_dev *vio_register_device_node(
|
||||
struct device_node *node_vdev);
|
||||
extern const void *vio_get_attribute(struct vio_dev *vdev, char *which,
|
||||
int *length);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue