mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-29 15:14:18 +08:00
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
@ -57,6 +57,7 @@ Table of Contents
|
|||||||
n) 4xx/Axon EMAC ethernet nodes
|
n) 4xx/Axon EMAC ethernet nodes
|
||||||
o) Xilinx IP cores
|
o) Xilinx IP cores
|
||||||
p) Freescale Synchronous Serial Interface
|
p) Freescale Synchronous Serial Interface
|
||||||
|
q) USB EHCI controllers
|
||||||
|
|
||||||
VII - Specifying interrupt information for devices
|
VII - Specifying interrupt information for devices
|
||||||
1) interrupts property
|
1) interrupts property
|
||||||
@ -2577,6 +2578,20 @@ platforms are moved over to use the flattened-device-tree model.
|
|||||||
Requred properties:
|
Requred properties:
|
||||||
- current-speed : Baud rate of uartlite
|
- 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
|
p) Freescale Synchronous Serial Interface
|
||||||
|
|
||||||
The SSI is a serial device that communicates with audio codecs. It can
|
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 >;
|
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.
|
More devices will be defined as this spec matures.
|
||||||
|
|
||||||
VII - Specifying interrupt information for devices
|
VII - Specifying interrupt information for devices
|
||||||
|
@ -97,6 +97,7 @@ config EARLY_PRINTK
|
|||||||
config COMPAT
|
config COMPAT
|
||||||
bool
|
bool
|
||||||
default y if PPC64
|
default y if PPC64
|
||||||
|
select COMPAT_BINFMT_ELF
|
||||||
|
|
||||||
config SYSVIPC_COMPAT
|
config SYSVIPC_COMPAT
|
||||||
bool
|
bool
|
||||||
@ -438,25 +439,6 @@ config WANT_DEVICE_TREE
|
|||||||
bool
|
bool
|
||||||
default n
|
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
|
endmenu
|
||||||
|
|
||||||
config ISA_DMA_API
|
config ISA_DMA_API
|
||||||
@ -512,7 +494,7 @@ config PCI
|
|||||||
bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
|
bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
|
||||||
|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
|
|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
|
||||||
|| PPC_PS3 || 44x
|
|| 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
|
&& !PPC_85xx && !PPC_86xx
|
||||||
default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
|
default PCI_PERMEDIA if !4xx && !CPM2 && !8xx
|
||||||
default PCI_QSPAN 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/
|
drivers-$(CONFIG_OPROFILE) += arch/powerpc/oprofile/
|
||||||
|
|
||||||
# Default to zImage, override when needed
|
# Default to zImage, override when needed
|
||||||
defaultimage-y := zImage
|
all: zImage
|
||||||
defaultimage-$(CONFIG_DEFAULT_UIMAGE) := uImage
|
|
||||||
KBUILD_IMAGE := $(defaultimage-y)
|
|
||||||
all: $(KBUILD_IMAGE)
|
|
||||||
|
|
||||||
CPPFLAGS_vmlinux.lds := -Upowerpc
|
CPPFLAGS_vmlinux.lds := -Upowerpc
|
||||||
|
|
||||||
BOOT_TARGETS = zImage zImage.initrd uImage
|
BOOT_TARGETS = zImage zImage.initrd uImage treeImage.% cuImage.%
|
||||||
|
|
||||||
PHONY += $(BOOT_TARGETS)
|
PHONY += $(BOOT_TARGETS)
|
||||||
|
|
||||||
@ -180,7 +177,7 @@ define archhelp
|
|||||||
endef
|
endef
|
||||||
|
|
||||||
install: vdso_install
|
install: vdso_install
|
||||||
$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
|
$(Q)$(MAKE) $(build)=$(boot) install
|
||||||
|
|
||||||
vdso_install:
|
vdso_install:
|
||||||
ifeq ($(CONFIG_PPC64),y)
|
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 \
|
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 \
|
cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
|
||||||
ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.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 \
|
cuboot-pq2.c cuboot-sequoia.c treeboot-walnut.c \
|
||||||
fixed-head.S ep88xc.c cuboot-hpc2.c ep405.c cuboot-taishan.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-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \
|
||||||
cuboot-warp.c cuboot-85xx-cpm2.c
|
cuboot-warp.c cuboot-85xx-cpm2.c
|
||||||
src-boot := $(src-wlib) $(src-plat) empty.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 \
|
extra-y := $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
|
||||||
$(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds
|
$(obj)/zImage.lds $(obj)/zImage.coff.lds $(obj)/zImage.ps3.lds
|
||||||
|
|
||||||
|
dtstree := $(srctree)/$(src)/dts
|
||||||
|
|
||||||
wrapper :=$(srctree)/$(src)/wrapper
|
wrapper :=$(srctree)/$(src)/wrapper
|
||||||
wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc) \
|
wrapperbits := $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc) \
|
||||||
$(wrapper) FORCE
|
$(wrapper) FORCE
|
||||||
@ -181,7 +184,7 @@ quiet_cmd_wrap = WRAP $@
|
|||||||
image-$(CONFIG_PPC_PSERIES) += zImage.pseries
|
image-$(CONFIG_PPC_PSERIES) += zImage.pseries
|
||||||
image-$(CONFIG_PPC_MAPLE) += zImage.pseries
|
image-$(CONFIG_PPC_MAPLE) += zImage.pseries
|
||||||
image-$(CONFIG_PPC_IBM_CELL_BLADE) += 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_CELLEB) += zImage.pseries
|
||||||
image-$(CONFIG_PPC_CHRP) += zImage.chrp
|
image-$(CONFIG_PPC_CHRP) += zImage.chrp
|
||||||
image-$(CONFIG_PPC_EFIKA) += 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_PPC_ISERIES) += zImage.iseries
|
||||||
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
|
image-$(CONFIG_DEFAULT_UIMAGE) += uImage
|
||||||
|
|
||||||
ifneq ($(CONFIG_DEVICE_TREE),"")
|
#
|
||||||
image-$(CONFIG_PPC_8xx) += cuImage.8xx
|
# Targets which embed a device tree blob
|
||||||
image-$(CONFIG_PPC_EP88XC) += zImage.ep88xc
|
#
|
||||||
image-$(CONFIG_EP405) += zImage.ep405
|
# Theses are default targets to build images which embed device tree blobs.
|
||||||
image-$(CONFIG_8260) += cuImage.pq2
|
# They are only required on boards which do not have FDT support in firmware.
|
||||||
image-$(CONFIG_EP8248E) += zImage.ep8248e
|
# Boards with newish u-boot firmare can use the uImage target above
|
||||||
image-$(CONFIG_PPC_MPC52xx) += cuImage.52xx
|
#
|
||||||
image-$(CONFIG_STORCENTER) += cuImage.824x
|
|
||||||
image-$(CONFIG_PPC_83xx) += cuImage.83xx
|
# Board ports in arch/powerpc/platform/40x/Kconfig
|
||||||
image-$(CONFIG_PPC_85xx) += cuImage.85xx
|
image-$(CONFIG_EP405) += zImage-dtb.ep405
|
||||||
ifeq ($(CONFIG_CPM2),y)
|
image-$(CONFIG_WALNUT) += treeImage.walnut
|
||||||
image-$(CONFIG_PPC_85xx) += cuImage.85xx-cpm2
|
|
||||||
endif
|
# Board ports in arch/powerpc/platform/44x/Kconfig
|
||||||
image-$(CONFIG_MPC7448HPC2) += cuImage.hpc2
|
|
||||||
image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony
|
image-$(CONFIG_EBONY) += treeImage.ebony cuImage.ebony
|
||||||
image-$(CONFIG_BAMBOO) += treeImage.bamboo cuImage.bamboo
|
image-$(CONFIG_BAMBOO) += treeImage.bamboo cuImage.bamboo
|
||||||
image-$(CONFIG_SEQUOIA) += cuImage.sequoia
|
image-$(CONFIG_SEQUOIA) += cuImage.sequoia
|
||||||
image-$(CONFIG_RAINIER) += cuImage.rainier
|
image-$(CONFIG_RAINIER) += cuImage.rainier
|
||||||
image-$(CONFIG_WALNUT) += treeImage.walnut
|
|
||||||
image-$(CONFIG_TAISHAN) += cuImage.taishan
|
image-$(CONFIG_TAISHAN) += cuImage.taishan
|
||||||
image-$(CONFIG_KATMAI) += cuImage.katmai
|
image-$(CONFIG_KATMAI) += cuImage.katmai
|
||||||
image-$(CONFIG_WARP) += cuImage.warp
|
image-$(CONFIG_WARP) += cuImage.warp
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(CONFIG_REDBOOT),"")
|
# Board ports in arch/powerpc/platform/8xx/Kconfig
|
||||||
image-$(CONFIG_PPC_8xx) += zImage.redboot-8xx
|
image-$(CONFIG_PPC_MPC86XADS) += cuImage.mpc866ads
|
||||||
endif
|
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
|
# For 32-bit powermacs, build the COFF and miboot images
|
||||||
# as well as the ELF images.
|
# as well as the ELF images.
|
||||||
@ -233,24 +272,20 @@ targets += $(image-y) $(initrd-y)
|
|||||||
|
|
||||||
$(addprefix $(obj)/, $(initrd-y)): $(obj)/ramdisk.image.gz
|
$(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
|
# 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
|
# the pattern rule with less dependencies that also matches (even with the
|
||||||
# hard dependency listed).
|
# hard dependency listed).
|
||||||
$(obj)/zImage.initrd.%: vmlinux $(wrapperbits) $(dts)
|
$(obj)/zImage.initrd.%: vmlinux $(wrapperbits)
|
||||||
$(call if_changed,wrap,$*,$(dts),,$(obj)/ramdisk.image.gz)
|
$(call if_changed,wrap,$*,,,$(obj)/ramdisk.image.gz)
|
||||||
|
|
||||||
$(obj)/zImage.%: vmlinux $(wrapperbits) $(dts)
|
$(obj)/zImage.%: vmlinux $(wrapperbits)
|
||||||
$(call if_changed,wrap,$*,$(dts))
|
$(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)
|
# This cannot be in the root of $(src) as the zImage rule always adds a $(obj)
|
||||||
# prefix
|
# prefix
|
||||||
@ -260,24 +295,17 @@ $(obj)/vmlinux.strip: vmlinux
|
|||||||
$(obj)/zImage.iseries: vmlinux
|
$(obj)/zImage.iseries: vmlinux
|
||||||
$(STRIP) -s -R .comment $< -o $@
|
$(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)
|
$(obj)/uImage: vmlinux $(wrapperbits)
|
||||||
$(call if_changed,wrap,uboot)
|
$(call if_changed,wrap,uboot)
|
||||||
|
|
||||||
$(obj)/cuImage.%: vmlinux $(dts) $(wrapperbits)
|
$(obj)/cuImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
|
||||||
$(call if_changed,wrap,cuboot-$*,$(dts))
|
$(call if_changed,wrap,cuboot-$*,$(dtstree)/$*.dts)
|
||||||
|
|
||||||
$(obj)/treeImage.initrd.%: vmlinux $(dts) $(wrapperbits)
|
$(obj)/treeImage.initrd.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
|
||||||
$(call if_changed,wrap,treeboot-$*,$(dts),,$(obj)/ramdisk.image.gz)
|
$(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts,,$(obj)/ramdisk.image.gz)
|
||||||
|
|
||||||
$(obj)/treeImage.%: vmlinux $(dts) $(wrapperbits)
|
$(obj)/treeImage.%: vmlinux $(dtstree)/%.dts $(wrapperbits)
|
||||||
$(call if_changed,wrap,treeboot-$*,$(dts))
|
$(call if_changed,wrap,treeboot-$*,$(dtstree)/$*.dts)
|
||||||
|
|
||||||
# If there isn't a platform selected then just strip the vmlinux.
|
# If there isn't a platform selected then just strip the vmlinux.
|
||||||
ifeq (,$(image-y))
|
ifeq (,$(image-y))
|
||||||
|
@ -151,6 +151,7 @@
|
|||||||
compatible = "fsl,mpc875-brg",
|
compatible = "fsl,mpc875-brg",
|
||||||
"fsl,cpm1-brg",
|
"fsl,cpm1-brg",
|
||||||
"fsl,cpm-brg";
|
"fsl,cpm-brg";
|
||||||
|
clock-frequency = <50000000>;
|
||||||
reg = <0x9f0 0x10>;
|
reg = <0x9f0 0x10>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -150,6 +150,7 @@
|
|||||||
compatible = "fsl,mpc875-brg",
|
compatible = "fsl,mpc875-brg",
|
||||||
"fsl,cpm1-brg",
|
"fsl,cpm1-brg",
|
||||||
"fsl,cpm-brg";
|
"fsl,cpm-brg";
|
||||||
|
clock-frequency = <50000000>;
|
||||||
reg = <0x9f0 0x10>;
|
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>;
|
interrupts = <14 0x8>;
|
||||||
interrupt-parent = <&ipic>;
|
interrupt-parent = <&ipic>;
|
||||||
dfsrr;
|
dfsrr;
|
||||||
|
rtc@68 {
|
||||||
|
compatible = "dallas,ds1339";
|
||||||
|
reg = <0x68>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c@3100 {
|
i2c@3100 {
|
||||||
|
@ -96,7 +96,7 @@
|
|||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
device_type = "soc";
|
device_type = "soc";
|
||||||
compatible = "simple-bus";
|
compatible = "fsl,mpc8315-immr", "simple-bus";
|
||||||
ranges = <0 0xe0000000 0x00100000>;
|
ranges = <0 0xe0000000 0x00100000>;
|
||||||
reg = <0xe0000000 0x00000200>;
|
reg = <0xe0000000 0x00000200>;
|
||||||
bus-frequency = <0>;
|
bus-frequency = <0>;
|
||||||
|
@ -332,7 +332,7 @@
|
|||||||
0xc000 0x0 0x0 0x3 &ipic 23 0x8
|
0xc000 0x0 0x0 0x3 &ipic 23 0x8
|
||||||
0xc000 0x0 0x0 0x4 &ipic 20 0x8>;
|
0xc000 0x0 0x0 0x4 &ipic 20 0x8>;
|
||||||
interrupt-parent = <&ipic>;
|
interrupt-parent = <&ipic>;
|
||||||
interrupts = <66 0x8>;
|
interrupts = <67 0x8>;
|
||||||
bus-range = <0 0>;
|
bus-range = <0 0>;
|
||||||
ranges = <0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000
|
ranges = <0x02000000 0x0 0xb0000000 0xb0000000 0x0 0x10000000
|
||||||
0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
|
0x42000000 0x0 0xa0000000 0xa0000000 0x0 0x10000000
|
||||||
|
@ -42,6 +42,18 @@
|
|||||||
bus-frequency = <0>;
|
bus-frequency = <0>;
|
||||||
clock-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 {
|
memory {
|
||||||
|
@ -166,6 +166,7 @@
|
|||||||
compatible = "fsl,mpc885-brg",
|
compatible = "fsl,mpc885-brg",
|
||||||
"fsl,cpm1-brg",
|
"fsl,cpm1-brg",
|
||||||
"fsl,cpm-brg";
|
"fsl,cpm-brg";
|
||||||
|
clock-frequency = <0>;
|
||||||
reg = <9f0 10>;
|
reg = <9f0 10>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -138,6 +138,14 @@
|
|||||||
interrupts = <15 8>;
|
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 {
|
POB0: opb {
|
||||||
compatible = "ibm,opb-440epx", "ibm,opb";
|
compatible = "ibm,opb-440epx", "ibm,opb";
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
/ {
|
/ {
|
||||||
model = "StorCenter";
|
model = "StorCenter";
|
||||||
compatible = "storcenter";
|
compatible = "iomega,storcenter";
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <1>;
|
#size-cells = <1>;
|
||||||
|
|
||||||
@ -62,12 +62,12 @@
|
|||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
compatible = "fsl-i2c";
|
compatible = "fsl-i2c";
|
||||||
reg = <0x3000 0x100>;
|
reg = <0x3000 0x100>;
|
||||||
interrupts = <5 2>;
|
interrupts = <17 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
|
|
||||||
rtc@68 {
|
rtc@68 {
|
||||||
compatible = "dallas,ds1337";
|
compatible = "dallas,ds1337";
|
||||||
reg = <68>;
|
reg = <0x68>;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -78,7 +78,7 @@
|
|||||||
reg = <0x4500 0x20>;
|
reg = <0x4500 0x20>;
|
||||||
clock-frequency = <97553800>; /* Hz */
|
clock-frequency = <97553800>; /* Hz */
|
||||||
current-speed = <115200>;
|
current-speed = <115200>;
|
||||||
interrupts = <9 2>;
|
interrupts = <25 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -89,7 +89,7 @@
|
|||||||
reg = <0x4600 0x20>;
|
reg = <0x4600 0x20>;
|
||||||
clock-frequency = <97553800>; /* Hz */
|
clock-frequency = <97553800>; /* Hz */
|
||||||
current-speed = <9600>;
|
current-speed = <9600>;
|
||||||
interrupts = <10 2>;
|
interrupts = <26 2>;
|
||||||
interrupt-parent = <&mpic>;
|
interrupt-parent = <&mpic>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -136,6 +136,6 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
chosen {
|
chosen {
|
||||||
linux,stdout-path = "/soc/serial@4500";
|
linux,stdout-path = &serial0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -158,6 +158,29 @@ miboot|uboot)
|
|||||||
cuboot*)
|
cuboot*)
|
||||||
binary=y
|
binary=y
|
||||||
gzip=
|
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)
|
ps3)
|
||||||
platformo="$object/ps3-head.o $object/ps3-hvcall.o $object/ps3.o"
|
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_PREEMPT is not set
|
||||||
CONFIG_BINFMT_ELF=y
|
CONFIG_BINFMT_ELF=y
|
||||||
# CONFIG_BINFMT_MISC is not set
|
# CONFIG_BINFMT_MISC is not set
|
||||||
# CONFIG_MATH_EMULATION is not set
|
CONFIG_MATH_EMULATION=y
|
||||||
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
|
||||||
CONFIG_ARCH_FLATMEM_ENABLE=y
|
CONFIG_ARCH_FLATMEM_ENABLE=y
|
||||||
CONFIG_ARCH_POPULATES_NODE_MAP=y
|
CONFIG_ARCH_POPULATES_NODE_MAP=y
|
||||||
@ -416,14 +416,14 @@ CONFIG_PHYLIB=y
|
|||||||
# MII PHY device drivers
|
# MII PHY device drivers
|
||||||
#
|
#
|
||||||
CONFIG_MARVELL_PHY=y
|
CONFIG_MARVELL_PHY=y
|
||||||
# CONFIG_DAVICOM_PHY is not set
|
CONFIG_DAVICOM_PHY=y
|
||||||
# CONFIG_QSEMI_PHY is not set
|
# CONFIG_QSEMI_PHY is not set
|
||||||
# CONFIG_LXT_PHY is not set
|
# CONFIG_LXT_PHY is not set
|
||||||
# CONFIG_CICADA_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_SMSC_PHY is not set
|
||||||
# CONFIG_BROADCOM_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_FIXED_PHY is not set
|
||||||
# CONFIG_MDIO_BITBANG is not set
|
# CONFIG_MDIO_BITBANG is not set
|
||||||
CONFIG_NET_ETHERNET=y
|
CONFIG_NET_ETHERNET=y
|
||||||
@ -436,7 +436,7 @@ CONFIG_MII=y
|
|||||||
CONFIG_NETDEV_1000=y
|
CONFIG_NETDEV_1000=y
|
||||||
CONFIG_GIANFAR=y
|
CONFIG_GIANFAR=y
|
||||||
# CONFIG_GFAR_NAPI is not set
|
# CONFIG_GFAR_NAPI is not set
|
||||||
# CONFIG_UCC_GETH is not set
|
CONFIG_UCC_GETH=y
|
||||||
CONFIG_NETDEV_10000=y
|
CONFIG_NETDEV_10000=y
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
# Makefile for the linux kernel.
|
# Makefile for the linux kernel.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
|
||||||
|
|
||||||
ifeq ($(CONFIG_PPC64),y)
|
ifeq ($(CONFIG_PPC64),y)
|
||||||
CFLAGS_prom_init.o += -mno-minimal-toc
|
CFLAGS_prom_init.o += -mno-minimal-toc
|
||||||
endif
|
endif
|
||||||
@ -15,7 +17,7 @@ obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
|
|||||||
init_task.o process.o systbl.o idle.o \
|
init_task.o process.o systbl.o idle.o \
|
||||||
signal.o
|
signal.o
|
||||||
obj-y += vdso32/
|
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 \
|
signal_64.o ptrace32.o \
|
||||||
paca.o cpu_setup_ppc970.o \
|
paca.o cpu_setup_ppc970.o \
|
||||||
cpu_setup_pa6t.o \
|
cpu_setup_pa6t.o \
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <linux/mman.h>
|
#include <linux/mman.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
|
#include <linux/hrtimer.h>
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
#include <linux/hardirq.h>
|
#include <linux/hardirq.h>
|
||||||
@ -312,7 +313,7 @@ int main(void)
|
|||||||
DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
|
DEFINE(CLOCK_REALTIME, CLOCK_REALTIME);
|
||||||
DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
|
DEFINE(CLOCK_MONOTONIC, CLOCK_MONOTONIC);
|
||||||
DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
|
DEFINE(NSEC_PER_SEC, NSEC_PER_SEC);
|
||||||
DEFINE(CLOCK_REALTIME_RES, TICK_NSEC);
|
DEFINE(CLOCK_REALTIME_RES, (KTIME_MONOTONIC_RES).tv64);
|
||||||
|
|
||||||
#ifdef CONFIG_BUG
|
#ifdef CONFIG_BUG
|
||||||
DEFINE(BUG_ENTRY_SIZE, sizeof(struct bug_entry));
|
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,
|
.icache_bsize = 32,
|
||||||
.dcache_bsize = 32,
|
.dcache_bsize = 32,
|
||||||
.cpu_setup = __setup_cpu_603,
|
.cpu_setup = __setup_cpu_603,
|
||||||
|
.num_pmcs = 4,
|
||||||
|
.oprofile_cpu_type = "ppc/e300",
|
||||||
|
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||||
.platform = "ppc603",
|
.platform = "ppc603",
|
||||||
},
|
},
|
||||||
{ /* e300c4 (e300c1, plus one IU) */
|
{ /* e300c4 (e300c1, plus one IU) */
|
||||||
@ -971,6 +974,9 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
|||||||
.dcache_bsize = 32,
|
.dcache_bsize = 32,
|
||||||
.cpu_setup = __setup_cpu_603,
|
.cpu_setup = __setup_cpu_603,
|
||||||
.machine_check = machine_check_generic,
|
.machine_check = machine_check_generic,
|
||||||
|
.num_pmcs = 4,
|
||||||
|
.oprofile_cpu_type = "ppc/e300",
|
||||||
|
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||||
.platform = "ppc603",
|
.platform = "ppc603",
|
||||||
},
|
},
|
||||||
{ /* default match, we assume split I/D cache & TB (non-601)... */
|
{ /* 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,
|
.dcache_bsize = 32,
|
||||||
.num_pmcs = 4,
|
.num_pmcs = 4,
|
||||||
.oprofile_cpu_type = "ppc/e500",
|
.oprofile_cpu_type = "ppc/e500",
|
||||||
.oprofile_type = PPC_OPROFILE_BOOKE,
|
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||||
.machine_check = machine_check_e500,
|
.machine_check = machine_check_e500,
|
||||||
.platform = "ppc8540",
|
.platform = "ppc8540",
|
||||||
},
|
},
|
||||||
@ -1453,7 +1459,7 @@ static struct cpu_spec __initdata cpu_specs[] = {
|
|||||||
.dcache_bsize = 32,
|
.dcache_bsize = 32,
|
||||||
.num_pmcs = 4,
|
.num_pmcs = 4,
|
||||||
.oprofile_cpu_type = "ppc/e500",
|
.oprofile_cpu_type = "ppc/e500",
|
||||||
.oprofile_type = PPC_OPROFILE_BOOKE,
|
.oprofile_type = PPC_OPROFILE_FSL_EMB,
|
||||||
.machine_check = machine_check_e500,
|
.machine_check = machine_check_e500,
|
||||||
.platform = "ppc8548",
|
.platform = "ppc8548",
|
||||||
},
|
},
|
||||||
|
@ -36,7 +36,8 @@ static struct legacy_serial_info {
|
|||||||
static struct __initdata of_device_id parents[] = {
|
static struct __initdata of_device_id parents[] = {
|
||||||
{.type = "soc",},
|
{.type = "soc",},
|
||||||
{.type = "tsi-bridge",},
|
{.type = "tsi-bridge",},
|
||||||
{.type = "opb", .compatible = "ibm,opb",},
|
{.type = "opb", },
|
||||||
|
{.compatible = "ibm,opb",},
|
||||||
{.compatible = "simple-bus",},
|
{.compatible = "simple-bus",},
|
||||||
{.compatible = "wrs,epld-localbus",},
|
{.compatible = "wrs,epld-localbus",},
|
||||||
};
|
};
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
static void dummy_perf(struct pt_regs *regs)
|
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);
|
mtpmr(PMRN_PMGC0, mfpmr(PMRN_PMGC0) & ~PMGC0_PMIE);
|
||||||
#elif defined(CONFIG_PPC64) || defined(CONFIG_6xx)
|
#elif defined(CONFIG_PPC64) || defined(CONFIG_6xx)
|
||||||
if (cur_cpu_spec->pmc_type == PPC_PMC_IBM)
|
if (cur_cpu_spec->pmc_type == PPC_PMC_IBM)
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
#include <linux/smp.h>
|
#include <linux/smp.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
|
#include <linux/regset.h>
|
||||||
|
#include <linux/elf.h>
|
||||||
#include <linux/user.h>
|
#include <linux/user.h>
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/signal.h>
|
#include <linux/signal.h>
|
||||||
@ -58,20 +60,38 @@
|
|||||||
#define PT_MAX_PUT_REG PT_CCR
|
#define PT_MAX_PUT_REG PT_CCR
|
||||||
#endif
|
#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.
|
* Get contents of register REGNO in task TASK.
|
||||||
*/
|
*/
|
||||||
unsigned long ptrace_get_reg(struct task_struct *task, int regno)
|
unsigned long ptrace_get_reg(struct task_struct *task, int regno)
|
||||||
{
|
{
|
||||||
unsigned long tmp = 0;
|
|
||||||
|
|
||||||
if (task->thread.regs == NULL)
|
if (task->thread.regs == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (regno == PT_MSR) {
|
if (regno == PT_MSR)
|
||||||
tmp = ((unsigned long *)task->thread.regs)[PT_MSR];
|
return get_user_msr(task);
|
||||||
return tmp | task->thread.fpexc_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
|
if (regno < (sizeof(struct pt_regs) / sizeof(unsigned long)))
|
||||||
return ((unsigned long *)task->thread.regs)[regno];
|
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)
|
if (task->thread.regs == NULL)
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
|
||||||
if (regno <= PT_MAX_PUT_REG || regno == PT_TRAP) {
|
if (regno == PT_MSR)
|
||||||
if (regno == PT_MSR)
|
return set_user_msr(task, data);
|
||||||
data = (data & MSR_DEBUGCHANGE)
|
if (regno == PT_TRAP)
|
||||||
| (task->thread.regs->msr & ~MSR_DEBUGCHANGE);
|
return set_user_trap(task, data);
|
||||||
/* We prevent mucking around with the reserved area of trap
|
|
||||||
* which are used internally by the kernel
|
if (regno <= PT_MAX_PUT_REG) {
|
||||||
*/
|
|
||||||
if (regno == PT_TRAP)
|
|
||||||
data &= 0xfff0;
|
|
||||||
((unsigned long *)task->thread.regs)[regno] = data;
|
((unsigned long *)task->thread.regs)[regno] = data;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int gpr_get(struct task_struct *target, const struct user_regset *regset,
|
||||||
static int get_fpregs(void __user *data, struct task_struct *task,
|
unsigned int pos, unsigned int count,
|
||||||
int has_fpscr)
|
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)))
|
if (target->thread.regs == NULL)
|
||||||
return -EFAULT;
|
return -EIO;
|
||||||
return 0;
|
|
||||||
|
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,
|
static int gpr_set(struct task_struct *target, const struct user_regset *regset,
|
||||||
int has_fpscr)
|
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)))
|
if (target->thread.regs == NULL)
|
||||||
return -EFAULT;
|
return -EIO;
|
||||||
return 0;
|
|
||||||
|
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.
|
* (combined (32- and 64-bit) gdb.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
static int vr_active(struct task_struct *target,
|
||||||
* Get contents of AltiVec register state in task TASK
|
const struct user_regset *regset)
|
||||||
*/
|
|
||||||
static int get_vrregs(unsigned long __user *data, struct task_struct *task)
|
|
||||||
{
|
{
|
||||||
unsigned long regsize;
|
flush_altivec_to_thread(target);
|
||||||
|
return target->thread.used_vr ? regset->n : 0;
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int vr_get(struct task_struct *target, const struct user_regset *regset,
|
||||||
* Write contents of AltiVec register state into task TASK.
|
unsigned int pos, unsigned int count,
|
||||||
*/
|
void *kbuf, void __user *ubuf)
|
||||||
static int set_vrregs(struct task_struct *task, unsigned long __user *data)
|
|
||||||
{
|
{
|
||||||
unsigned long regsize;
|
int ret;
|
||||||
|
|
||||||
/* copy AltiVec registers VR[0] .. VR[31] */
|
flush_altivec_to_thread(target);
|
||||||
regsize = 32 * sizeof(vector128);
|
|
||||||
if (copy_from_user(task->thread.vr, data, regsize))
|
|
||||||
return -EFAULT;
|
|
||||||
data += (regsize / sizeof(unsigned long));
|
|
||||||
|
|
||||||
/* copy VSCR */
|
BUILD_BUG_ON(offsetof(struct thread_struct, vscr) !=
|
||||||
regsize = 1 * sizeof(vector128);
|
offsetof(struct thread_struct, vr[32]));
|
||||||
if (copy_from_user(&task->thread.vscr, data, regsize))
|
|
||||||
return -EFAULT;
|
|
||||||
data += (regsize / sizeof(unsigned long));
|
|
||||||
|
|
||||||
/* copy VRSAVE */
|
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||||
if (get_user(task->thread.vrsave, (u32 __user *)data))
|
&target->thread.vr, 0,
|
||||||
return -EFAULT;
|
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 */
|
#endif /* CONFIG_ALTIVEC */
|
||||||
|
|
||||||
@ -203,59 +335,275 @@ static int set_vrregs(struct task_struct *task, unsigned long __user *data)
|
|||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
static int evr_active(struct task_struct *target,
|
||||||
* Get contents of SPE register state in task TASK.
|
const struct user_regset *regset)
|
||||||
*/
|
|
||||||
static int get_evrregs(unsigned long *data, struct task_struct *task)
|
|
||||||
{
|
{
|
||||||
int i;
|
flush_spe_to_thread(target);
|
||||||
|
return target->thread.used_spe ? regset->n : 0;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static int evr_get(struct task_struct *target, const struct user_regset *regset,
|
||||||
* Write contents of SPE register state into task TASK.
|
unsigned int pos, unsigned int count,
|
||||||
*/
|
void *kbuf, void __user *ubuf)
|
||||||
static int set_evrregs(struct task_struct *task, unsigned long *data)
|
|
||||||
{
|
{
|
||||||
int i;
|
int ret;
|
||||||
|
|
||||||
if (!access_ok(VERIFY_READ, data, 35 * sizeof(unsigned long)))
|
flush_spe_to_thread(target);
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
/* copy SPEFSCR */
|
ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf,
|
||||||
if (__get_user(task->thread.spefscr, &data[34]))
|
&target->thread.evr,
|
||||||
return -EFAULT;
|
0, sizeof(target->thread.evr));
|
||||||
|
|
||||||
/* copy SPE registers EVR[0] .. EVR[31] */
|
BUILD_BUG_ON(offsetof(struct thread_struct, acc) + sizeof(u64) !=
|
||||||
for (i = 0; i < 32; i++, data++)
|
offsetof(struct thread_struct, spefscr));
|
||||||
if (__get_user(task->thread.evr[i], data))
|
|
||||||
return -EFAULT;
|
|
||||||
/* copy ACC */
|
|
||||||
if (__get_user64(task->thread.acc, (unsigned long long*)data))
|
|
||||||
return -EFAULT;
|
|
||||||
|
|
||||||
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 */
|
#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)
|
void user_enable_single_step(struct task_struct *task)
|
||||||
{
|
{
|
||||||
struct pt_regs *regs = task->thread.regs;
|
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,
|
static long arch_ptrace_old(struct task_struct *child, long request, long addr,
|
||||||
long data)
|
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_SETREGS: /* Set GPRs 0 - 31. */
|
||||||
case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
|
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||||
int i;
|
REGSET_GPR, 0, 32 * sizeof(long),
|
||||||
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
|
(const void __user *) data);
|
||||||
unsigned long __user *tmp = (unsigned long __user *)addr;
|
|
||||||
|
|
||||||
CHECK_FULL_REGS(child->thread.regs);
|
case PPC_PTRACE_GETFPREGS: /* Get FPRs 0 - 31. */
|
||||||
for (i = 0; i < 32; i++) {
|
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||||
ret = put_user(*reg, tmp);
|
REGSET_FPR, 0, 32 * sizeof(double),
|
||||||
if (ret)
|
(void __user *) data);
|
||||||
break;
|
|
||||||
reg++;
|
case PPC_PTRACE_SETFPREGS: /* Set FPRs 0 - 31. */
|
||||||
tmp++;
|
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||||
}
|
REGSET_FPR, 0, 32 * sizeof(double),
|
||||||
break;
|
(const void __user *) data);
|
||||||
}
|
}
|
||||||
|
|
||||||
case PPC_PTRACE_SETREGS: { /* Set GPRs 0 - 31. */
|
return -EPERM;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
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;
|
int ret = -EPERM;
|
||||||
|
|
||||||
switch (request) {
|
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. */
|
/* read the word at location addr in the USER area. */
|
||||||
case PTRACE_PEEKUSR: {
|
case PTRACE_PEEKUSR: {
|
||||||
unsigned long index, tmp;
|
unsigned long index, tmp;
|
||||||
@ -412,12 +728,6 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||||||
break;
|
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 */
|
/* write the word at location addr in the USER area */
|
||||||
case PTRACE_POKEUSR: {
|
case PTRACE_POKEUSR: {
|
||||||
unsigned long index;
|
unsigned long index;
|
||||||
@ -462,85 +772,60 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
|
|||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
case PTRACE_GETREGS64:
|
case PTRACE_GETREGS64:
|
||||||
#endif
|
#endif
|
||||||
case PTRACE_GETREGS: { /* Get all pt_regs from the child. */
|
case PTRACE_GETREGS: /* Get all pt_regs from the child. */
|
||||||
int ui;
|
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||||
if (!access_ok(VERIFY_WRITE, (void __user *)data,
|
REGSET_GPR,
|
||||||
sizeof(struct pt_regs))) {
|
0, sizeof(struct pt_regs),
|
||||||
ret = -EIO;
|
(void __user *) data);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
case PTRACE_SETREGS64:
|
case PTRACE_SETREGS64:
|
||||||
#endif
|
#endif
|
||||||
case PTRACE_SETREGS: { /* Set all gp regs in the child. */
|
case PTRACE_SETREGS: /* Set all gp regs in the child. */
|
||||||
unsigned long tmp;
|
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||||
int ui;
|
REGSET_GPR,
|
||||||
if (!access_ok(VERIFY_READ, (void __user *)data,
|
0, sizeof(struct pt_regs),
|
||||||
sizeof(struct pt_regs))) {
|
(const void __user *) data);
|
||||||
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_GETFPREGS: { /* Get the child FPU state (FPR0...31 + FPSCR) */
|
case PTRACE_GETFPREGS: /* Get the child FPU state (FPR0...31 + FPSCR) */
|
||||||
flush_fp_to_thread(child);
|
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||||
ret = get_fpregs((void __user *)data, child, 1);
|
REGSET_FPR,
|
||||||
break;
|
0, sizeof(elf_fpregset_t),
|
||||||
}
|
(void __user *) data);
|
||||||
|
|
||||||
case PTRACE_SETFPREGS: { /* Set the child FPU state (FPR0...31 + FPSCR) */
|
case PTRACE_SETFPREGS: /* Set the child FPU state (FPR0...31 + FPSCR) */
|
||||||
flush_fp_to_thread(child);
|
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||||
ret = set_fpregs((void __user *)data, child, 1);
|
REGSET_FPR,
|
||||||
break;
|
0, sizeof(elf_fpregset_t),
|
||||||
}
|
(const void __user *) data);
|
||||||
|
|
||||||
#ifdef CONFIG_ALTIVEC
|
#ifdef CONFIG_ALTIVEC
|
||||||
case PTRACE_GETVRREGS:
|
case PTRACE_GETVRREGS:
|
||||||
/* Get the child altivec register state. */
|
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||||
flush_altivec_to_thread(child);
|
REGSET_VMX,
|
||||||
ret = get_vrregs((unsigned long __user *)data, child);
|
0, (33 * sizeof(vector128) +
|
||||||
break;
|
sizeof(u32)),
|
||||||
|
(void __user *) data);
|
||||||
|
|
||||||
case PTRACE_SETVRREGS:
|
case PTRACE_SETVRREGS:
|
||||||
/* Set the child altivec register state. */
|
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||||
flush_altivec_to_thread(child);
|
REGSET_VMX,
|
||||||
ret = set_vrregs(child, (unsigned long __user *)data);
|
0, (33 * sizeof(vector128) +
|
||||||
break;
|
sizeof(u32)),
|
||||||
|
(const void __user *) data);
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SPE
|
#ifdef CONFIG_SPE
|
||||||
case PTRACE_GETEVRREGS:
|
case PTRACE_GETEVRREGS:
|
||||||
/* Get the child spe register state. */
|
/* Get the child spe register state. */
|
||||||
flush_spe_to_thread(child);
|
return copy_regset_to_user(child, &user_ppc_native_view,
|
||||||
ret = get_evrregs((unsigned long __user *)data, child);
|
REGSET_SPE, 0, 35 * sizeof(u32),
|
||||||
break;
|
(void __user *) data);
|
||||||
|
|
||||||
case PTRACE_SETEVRREGS:
|
case PTRACE_SETEVRREGS:
|
||||||
/* Set the child spe register state. */
|
/* Set the child spe register state. */
|
||||||
/* this is to clear the MSR_SPE bit to force a reload
|
return copy_regset_from_user(child, &user_ppc_native_view,
|
||||||
* of register state from memory */
|
REGSET_SPE, 0, 35 * sizeof(u32),
|
||||||
flush_spe_to_thread(child);
|
(const void __user *) data);
|
||||||
ret = set_evrregs(child, (unsigned long __user *)data);
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Old reverse args ptrace callss */
|
/* Old reverse args ptrace callss */
|
||||||
|
@ -24,9 +24,11 @@
|
|||||||
#include <linux/smp_lock.h>
|
#include <linux/smp_lock.h>
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
|
#include <linux/regset.h>
|
||||||
#include <linux/user.h>
|
#include <linux/user.h>
|
||||||
#include <linux/security.h>
|
#include <linux/security.h>
|
||||||
#include <linux/signal.h>
|
#include <linux/signal.h>
|
||||||
|
#include <linux/compat.h>
|
||||||
|
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
@ -45,87 +47,31 @@
|
|||||||
static long compat_ptrace_old(struct task_struct *child, long request,
|
static long compat_ptrace_old(struct task_struct *child, long request,
|
||||||
long addr, long data)
|
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_SETREGS: /* Set GPRs 0 - 31. */
|
||||||
case PPC_PTRACE_GETREGS: { /* Get GPRs 0 - 31. */
|
return copy_regset_from_user(child,
|
||||||
int i;
|
task_user_regset_view(current), 0,
|
||||||
unsigned long *reg = &((unsigned long *)child->thread.regs)[0];
|
0, 32 * sizeof(compat_long_t),
|
||||||
unsigned int __user *tmp = (unsigned int __user *)addr;
|
compat_ptr(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_SETREGS: { /* Set GPRs 0 - 31. */
|
return -EPERM;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
long compat_sys_ptrace(int request, int pid, unsigned long addr,
|
long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
|
||||||
unsigned long data)
|
compat_ulong_t caddr, compat_ulong_t cdata)
|
||||||
{
|
{
|
||||||
struct task_struct *child;
|
unsigned long addr = caddr;
|
||||||
|
unsigned long data = cdata;
|
||||||
int ret;
|
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) {
|
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
|
* Read 4 bytes of the other process' storage
|
||||||
* data is a pointer specifying where the user wants the
|
* 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;
|
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
|
* Write 4 bytes into the other process' storage
|
||||||
* data is the 4 bytes that the user wants written
|
* 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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case PTRACE_GETEVENTMSG:
|
case PTRACE_GETREGS: /* Get all pt_regs from the child. */
|
||||||
ret = put_user(child->ptrace_message, (unsigned int __user *) data);
|
return copy_regset_to_user(
|
||||||
break;
|
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. */
|
case PTRACE_SETREGS: /* Set all gp regs in the child. */
|
||||||
int ui;
|
return copy_regset_from_user(
|
||||||
if (!access_ok(VERIFY_WRITE, (void __user *)data,
|
child, task_user_regset_view(current), 0,
|
||||||
PT_REGS_COUNT * sizeof(int))) {
|
0, PT_REGS_COUNT * sizeof(compat_long_t),
|
||||||
ret = -EIO;
|
compat_ptr(data));
|
||||||
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_GETFPREGS:
|
case PTRACE_GETFPREGS:
|
||||||
case PTRACE_SETFPREGS:
|
case PTRACE_SETFPREGS:
|
||||||
@ -402,12 +306,9 @@ long compat_sys_ptrace(int request, int pid, unsigned long addr,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ret = ptrace_request(child, request, addr, data);
|
ret = compat_ptrace_request(child, request, addr, data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
out_tsk:
|
|
||||||
put_task_struct(child);
|
|
||||||
out:
|
|
||||||
unlock_kernel();
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <asm/kexec.h>
|
#include <asm/kexec.h>
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUGGER
|
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
|
||||||
int (*__debugger)(struct pt_regs *regs);
|
int (*__debugger)(struct pt_regs *regs);
|
||||||
int (*__debugger_ipi)(struct pt_regs *regs);
|
int (*__debugger_ipi)(struct pt_regs *regs);
|
||||||
int (*__debugger_bpt)(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
|
* Returns a pointer to the created vio_dev or NULL if node has
|
||||||
* NULL device_type or compatible fields.
|
* 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;
|
struct vio_dev *viodev;
|
||||||
const unsigned int *unit_address;
|
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 */);
|
_tlbie(address, 0 /* 8xx doesn't care about PID */);
|
||||||
#endif
|
#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)) {
|
&& !test_bit(PG_arch_1, &page->flags)) {
|
||||||
if (vma->vm_mm == current->active_mm) {
|
if (vma->vm_mm == current->active_mm) {
|
||||||
__flush_dcache_icache((void *) address);
|
__flush_dcache_icache((void *) address);
|
||||||
|
@ -24,6 +24,8 @@
|
|||||||
|
|
||||||
static int numa_enabled = 1;
|
static int numa_enabled = 1;
|
||||||
|
|
||||||
|
static char *cmdline __initdata;
|
||||||
|
|
||||||
static int numa_debug;
|
static int numa_debug;
|
||||||
#define dbg(args...) if (numa_debug) { printk(KERN_INFO args); }
|
#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 min_common_depth;
|
||||||
static int n_mem_addr_cells, n_mem_size_cells;
|
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)
|
static void __cpuinit map_cpu_to_node(int cpu, int node)
|
||||||
{
|
{
|
||||||
numa_cpu_lookup_table[cpu] = 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)
|
if (nid == 0xffff || nid >= MAX_NUMNODES)
|
||||||
nid = default_nid;
|
nid = default_nid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fake_numa_create_new_node(((start + lmb_size) >> PAGE_SHIFT),
|
||||||
|
&nid);
|
||||||
node_set_online(nid);
|
node_set_online(nid);
|
||||||
|
|
||||||
size = numa_enforce_memory_limit(start, lmb_size);
|
size = numa_enforce_memory_limit(start, lmb_size);
|
||||||
@ -429,6 +481,8 @@ new_range:
|
|||||||
nid = of_node_to_nid_single(memory);
|
nid = of_node_to_nid_single(memory);
|
||||||
if (nid < 0)
|
if (nid < 0)
|
||||||
nid = default_nid;
|
nid = default_nid;
|
||||||
|
|
||||||
|
fake_numa_create_new_node(((start + size) >> PAGE_SHIFT), &nid);
|
||||||
node_set_online(nid);
|
node_set_online(nid);
|
||||||
|
|
||||||
if (!(size = numa_enforce_memory_limit(start, size))) {
|
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 top_of_ram = lmb_end_of_DRAM();
|
||||||
unsigned long total_ram = lmb_phys_mem_size();
|
unsigned long total_ram = lmb_phys_mem_size();
|
||||||
unsigned long start_pfn, end_pfn;
|
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",
|
printk(KERN_DEBUG "Top of RAM: 0x%lx, Total RAM: 0x%lx\n",
|
||||||
top_of_ram, total_ram);
|
top_of_ram, total_ram);
|
||||||
@ -471,9 +525,11 @@ static void __init setup_nonnuma(void)
|
|||||||
for (i = 0; i < lmb.memory.cnt; ++i) {
|
for (i = 0; i < lmb.memory.cnt; ++i) {
|
||||||
start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
|
start_pfn = lmb.memory.region[i].base >> PAGE_SHIFT;
|
||||||
end_pfn = start_pfn + lmb_size_pages(&lmb.memory, i);
|
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)
|
void __init dump_numa_cpu_topology(void)
|
||||||
@ -702,6 +758,10 @@ static int __init early_numa(char *p)
|
|||||||
if (strstr(p, "debug"))
|
if (strstr(p, "debug"))
|
||||||
numa_debug = 1;
|
numa_debug = 1;
|
||||||
|
|
||||||
|
p = strstr(p, "fake=");
|
||||||
|
if (p)
|
||||||
|
cmdline = p + strlen("fake=");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
early_param("numa", early_numa);
|
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_profiler.o cell/vma_map.o \
|
||||||
cell/spu_task_sync.o
|
cell/spu_task_sync.o
|
||||||
oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o op_model_pa6t.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
|
oprofile-$(CONFIG_6xx) += op_model_7450.o
|
||||||
|
@ -202,9 +202,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
|
|||||||
model = &op_model_7450;
|
model = &op_model_7450;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_FSL_BOOKE
|
#if defined(CONFIG_FSL_EMB_PERFMON)
|
||||||
case PPC_OPROFILE_BOOKE:
|
case PPC_OPROFILE_FSL_EMB:
|
||||||
model = &op_model_fsl_booke;
|
model = &op_model_fsl_emb;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* arch/powerpc/oprofile/op_model_fsl_booke.c
|
* Freescale Embedded oprofile support, based on ppc64 oprofile support
|
||||||
*
|
|
||||||
* Freescale Book-E oprofile support, based on ppc64 oprofile support
|
|
||||||
* Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
|
* Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004 Freescale Semiconductor, Inc
|
* Copyright (c) 2004 Freescale Semiconductor, Inc
|
||||||
@ -22,7 +20,7 @@
|
|||||||
#include <asm/system.h>
|
#include <asm/system.h>
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/cputable.h>
|
#include <asm/cputable.h>
|
||||||
#include <asm/reg_booke.h>
|
#include <asm/reg_fsl_emb.h>
|
||||||
#include <asm/page.h>
|
#include <asm/page.h>
|
||||||
#include <asm/pmc.h>
|
#include <asm/pmc.h>
|
||||||
#include <asm/oprofile_impl.h>
|
#include <asm/oprofile_impl.h>
|
||||||
@ -244,7 +242,7 @@ static void dump_pmcs(void)
|
|||||||
mfpmr(PMRN_PMLCA3), mfpmr(PMRN_PMLCB3));
|
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;
|
int i;
|
||||||
|
|
||||||
@ -262,7 +260,7 @@ static int fsl_booke_cpu_setup(struct op_counter_config *ctr)
|
|||||||
return 0;
|
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,
|
struct op_system_config *sys,
|
||||||
int num_ctrs)
|
int num_ctrs)
|
||||||
{
|
{
|
||||||
@ -281,7 +279,7 @@ static int fsl_booke_reg_setup(struct op_counter_config *ctr,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int fsl_booke_start(struct op_counter_config *ctr)
|
static int fsl_emb_start(struct op_counter_config *ctr)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -315,7 +313,7 @@ static int fsl_booke_start(struct op_counter_config *ctr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fsl_booke_stop(void)
|
static void fsl_emb_stop(void)
|
||||||
{
|
{
|
||||||
/* freeze counters */
|
/* freeze counters */
|
||||||
pmc_stop_ctrs();
|
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)
|
struct op_counter_config *ctr)
|
||||||
{
|
{
|
||||||
unsigned long pc;
|
unsigned long pc;
|
||||||
@ -362,10 +360,10 @@ static void fsl_booke_handle_interrupt(struct pt_regs *regs,
|
|||||||
pmc_start_ctrs(1);
|
pmc_start_ctrs(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct op_powerpc_model op_model_fsl_booke = {
|
struct op_powerpc_model op_model_fsl_emb = {
|
||||||
.reg_setup = fsl_booke_reg_setup,
|
.reg_setup = fsl_emb_reg_setup,
|
||||||
.cpu_setup = fsl_booke_cpu_setup,
|
.cpu_setup = fsl_emb_cpu_setup,
|
||||||
.start = fsl_booke_start,
|
.start = fsl_emb_start,
|
||||||
.stop = fsl_booke_stop,
|
.stop = fsl_emb_stop,
|
||||||
.handle_interrupt = fsl_booke_handle_interrupt,
|
.handle_interrupt = fsl_emb_handle_interrupt,
|
||||||
};
|
};
|
@ -72,6 +72,7 @@ config WALNUT
|
|||||||
default y
|
default y
|
||||||
select 405GP
|
select 405GP
|
||||||
select PCI
|
select PCI
|
||||||
|
select OF_RTC
|
||||||
help
|
help
|
||||||
This option enables support for the IBM PPC405GP evaluation board.
|
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();
|
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 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
|
#include <linux/rtc.h>
|
||||||
|
|
||||||
#include <asm/machdep.h>
|
#include <asm/machdep.h>
|
||||||
#include <asm/prom.h>
|
#include <asm/prom.h>
|
||||||
|
@ -137,7 +137,7 @@ static int __init pika_dtm_start(void)
|
|||||||
}
|
}
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
|
|
||||||
fpga = ioremap(res.start + 0x20, 4);
|
fpga = ioremap(res.start, 0x24);
|
||||||
if (fpga == NULL)
|
if (fpga == NULL)
|
||||||
return -ENOENT;
|
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);
|
bcsr = of_iomap(np, 0);
|
||||||
|
of_node_put(np);
|
||||||
if (!bcsr) {
|
if (!bcsr) {
|
||||||
printk(KERN_ERR "Cannot map BCSR registers\n");
|
printk(KERN_ERR "Cannot map BCSR registers\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
of_node_put(np);
|
|
||||||
|
|
||||||
clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
|
clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
|
||||||
setbits32(&bcsr[1], BCSR1_FETH_RST);
|
setbits32(&bcsr[1], BCSR1_FETH_RST);
|
||||||
|
|
||||||
|
@ -130,13 +130,12 @@ static void __init pq2fads_setup_arch(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bcsr = of_iomap(np, 0);
|
bcsr = of_iomap(np, 0);
|
||||||
|
of_node_put(np);
|
||||||
if (!bcsr) {
|
if (!bcsr) {
|
||||||
printk(KERN_ERR "Cannot map BCSR registers\n");
|
printk(KERN_ERR "Cannot map BCSR registers\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
of_node_put(np);
|
|
||||||
|
|
||||||
/* Enable the serial and ethernet ports */
|
/* Enable the serial and ethernet ports */
|
||||||
|
|
||||||
clrbits32(&bcsr[1], BCSR1_RS232_EN1 | BCSR1_RS232_EN2 | BCSR1_FETHIEN);
|
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
|
#ifdef CONFIG_QUICC_ENGINE
|
||||||
qe_reset();
|
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);
|
par_io_init(np);
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
#define MPC83XX_SCCR_USB_DRCM_11 0x00300000
|
#define MPC83XX_SCCR_USB_DRCM_11 0x00300000
|
||||||
#define MPC83XX_SCCR_USB_DRCM_01 0x00100000
|
#define MPC83XX_SCCR_USB_DRCM_01 0x00100000
|
||||||
#define MPC83XX_SCCR_USB_DRCM_10 0x00200000
|
#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
|
#define MPC837X_SCCR_USB_DRCM_11 0x00c00000
|
||||||
|
|
||||||
/* system i/o configuration register low */
|
/* system i/o configuration register low */
|
||||||
|
@ -104,6 +104,7 @@ int mpc831x_usb_cfg(void)
|
|||||||
u32 temp;
|
u32 temp;
|
||||||
void __iomem *immap, *usb_regs;
|
void __iomem *immap, *usb_regs;
|
||||||
struct device_node *np = NULL;
|
struct device_node *np = NULL;
|
||||||
|
struct device_node *immr_node = NULL;
|
||||||
const void *prop;
|
const void *prop;
|
||||||
struct resource res;
|
struct resource res;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
@ -124,10 +125,15 @@ int mpc831x_usb_cfg(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Configure clock */
|
/* Configure clock */
|
||||||
temp = in_be32(immap + MPC83XX_SCCR_OFFS);
|
immr_node = of_get_parent(np);
|
||||||
temp &= ~MPC83XX_SCCR_USB_MASK;
|
if (immr_node && of_device_is_compatible(immr_node, "fsl,mpc8315-immr"))
|
||||||
temp |= MPC83XX_SCCR_USB_DRCM_11; /* 1:3 */
|
clrsetbits_be32(immap + MPC83XX_SCCR_OFFS,
|
||||||
out_be32(immap + MPC83XX_SCCR_OFFS, temp);
|
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 */
|
/* Configure pin mux for ULPI. There is no pin mux for UTMI */
|
||||||
if (prop && !strcmp(prop, "ulpi")) {
|
if (prop && !strcmp(prop, "ulpi")) {
|
||||||
@ -144,6 +150,9 @@ int mpc831x_usb_cfg(void)
|
|||||||
|
|
||||||
iounmap(immap);
|
iounmap(immap);
|
||||||
|
|
||||||
|
if (immr_node)
|
||||||
|
of_node_put(immr_node);
|
||||||
|
|
||||||
/* Map USB SOC space */
|
/* Map USB SOC space */
|
||||||
ret = of_address_to_resource(np, 0, &res);
|
ret = of_address_to_resource(np, 0, &res);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -15,12 +15,12 @@
|
|||||||
|
|
||||||
#include <asm/time.h>
|
#include <asm/time.h>
|
||||||
#include <asm/machdep.h>
|
#include <asm/machdep.h>
|
||||||
#include <asm/commproc.h>
|
#include <asm/cpm1.h>
|
||||||
#include <asm/fs_pd.h>
|
#include <asm/fs_pd.h>
|
||||||
#include <asm/udbg.h>
|
#include <asm/udbg.h>
|
||||||
#include <asm/prom.h>
|
#include <asm/prom.h>
|
||||||
|
|
||||||
#include <sysdev/commproc.h>
|
#include "mpc8xx.h"
|
||||||
|
|
||||||
struct cpm_pin {
|
struct cpm_pin {
|
||||||
int port, pin, flags;
|
int port, pin, flags;
|
||||||
@ -108,7 +108,7 @@ define_machine(adder875) {
|
|||||||
.name = "Adder MPC875",
|
.name = "Adder MPC875",
|
||||||
.probe = adder875_probe,
|
.probe = adder875_probe,
|
||||||
.setup_arch = adder875_setup,
|
.setup_arch = adder875_setup,
|
||||||
.init_IRQ = m8xx_pic_init,
|
.init_IRQ = mpc8xx_pics_init,
|
||||||
.get_irq = mpc8xx_get_irq,
|
.get_irq = mpc8xx_get_irq,
|
||||||
.restart = mpc8xx_restart,
|
.restart = mpc8xx_restart,
|
||||||
.calibrate_decr = generic_calibrate_decr,
|
.calibrate_decr = generic_calibrate_decr,
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
#include <asm/machdep.h>
|
#include <asm/machdep.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/udbg.h>
|
#include <asm/udbg.h>
|
||||||
#include <asm/commproc.h>
|
|
||||||
#include <asm/cpm1.h>
|
#include <asm/cpm1.h>
|
||||||
|
|
||||||
#include "mpc8xx.h"
|
#include "mpc8xx.h"
|
||||||
|
@ -24,6 +24,7 @@ config PPC_83xx
|
|||||||
select MPC83xx
|
select MPC83xx
|
||||||
select IPIC
|
select IPIC
|
||||||
select WANT_DEVICE_TREE
|
select WANT_DEVICE_TREE
|
||||||
|
select FSL_EMB_PERFMON
|
||||||
|
|
||||||
config PPC_86xx
|
config PPC_86xx
|
||||||
bool "Freescale 86xx"
|
bool "Freescale 86xx"
|
||||||
@ -41,6 +42,7 @@ config CLASSIC32
|
|||||||
source "arch/powerpc/platforms/pseries/Kconfig"
|
source "arch/powerpc/platforms/pseries/Kconfig"
|
||||||
source "arch/powerpc/platforms/iseries/Kconfig"
|
source "arch/powerpc/platforms/iseries/Kconfig"
|
||||||
source "arch/powerpc/platforms/chrp/Kconfig"
|
source "arch/powerpc/platforms/chrp/Kconfig"
|
||||||
|
source "arch/powerpc/platforms/512x/Kconfig"
|
||||||
source "arch/powerpc/platforms/52xx/Kconfig"
|
source "arch/powerpc/platforms/52xx/Kconfig"
|
||||||
source "arch/powerpc/platforms/powermac/Kconfig"
|
source "arch/powerpc/platforms/powermac/Kconfig"
|
||||||
source "arch/powerpc/platforms/prep/Kconfig"
|
source "arch/powerpc/platforms/prep/Kconfig"
|
||||||
|
@ -14,7 +14,7 @@ choice
|
|||||||
There are five families of 32 bit PowerPC chips supported.
|
There are five families of 32 bit PowerPC chips supported.
|
||||||
The most common ones are the desktop and server CPUs (601, 603,
|
The most common ones are the desktop and server CPUs (601, 603,
|
||||||
604, 740, 750, 74xx) CPUs from Freescale and IBM, with their
|
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
|
The other embeeded parts, namely 4xx, 8xx, e200 (55xx) and e500
|
||||||
(85xx) each form a family of their own that is not compatible
|
(85xx) each form a family of their own that is not compatible
|
||||||
with the others.
|
with the others.
|
||||||
@ -22,7 +22,7 @@ choice
|
|||||||
If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx.
|
If unsure, select 52xx/6xx/7xx/74xx/82xx/83xx/86xx.
|
||||||
|
|
||||||
config 6xx
|
config 6xx
|
||||||
bool "52xx/6xx/7xx/74xx/82xx/83xx/86xx"
|
bool "512x/52xx/6xx/7xx/74xx/82xx/83xx/86xx"
|
||||||
select PPC_FPU
|
select PPC_FPU
|
||||||
|
|
||||||
config PPC_85xx
|
config PPC_85xx
|
||||||
@ -94,6 +94,7 @@ config 8xx
|
|||||||
bool
|
bool
|
||||||
|
|
||||||
config E500
|
config E500
|
||||||
|
select FSL_EMB_PERFMON
|
||||||
bool
|
bool
|
||||||
|
|
||||||
config PPC_FPU
|
config PPC_FPU
|
||||||
@ -115,6 +116,9 @@ config FSL_BOOKE
|
|||||||
depends on E200 || E500
|
depends on E200 || E500
|
||||||
default y
|
default y
|
||||||
|
|
||||||
|
config FSL_EMB_PERFMON
|
||||||
|
bool
|
||||||
|
|
||||||
config PTE_64BIT
|
config PTE_64BIT
|
||||||
bool
|
bool
|
||||||
depends on 44x || E500
|
depends on 44x || E500
|
||||||
@ -221,7 +225,7 @@ config NR_CPUS
|
|||||||
|
|
||||||
config NOT_COHERENT_CACHE
|
config NOT_COHERENT_CACHE
|
||||||
bool
|
bool
|
||||||
depends on 4xx || 8xx || E200
|
depends on 4xx || 8xx || E200 || PPC_MPC512x
|
||||||
default y
|
default y
|
||||||
|
|
||||||
config CHECK_CACHE_COHERENCY
|
config CHECK_CACHE_COHERENCY
|
||||||
|
@ -11,6 +11,7 @@ endif
|
|||||||
obj-$(CONFIG_PPC_CHRP) += chrp/
|
obj-$(CONFIG_PPC_CHRP) += chrp/
|
||||||
obj-$(CONFIG_40x) += 40x/
|
obj-$(CONFIG_40x) += 40x/
|
||||||
obj-$(CONFIG_44x) += 44x/
|
obj-$(CONFIG_44x) += 44x/
|
||||||
|
obj-$(CONFIG_PPC_MPC512x) += 512x/
|
||||||
obj-$(CONFIG_PPC_MPC52xx) += 52xx/
|
obj-$(CONFIG_PPC_MPC52xx) += 52xx/
|
||||||
obj-$(CONFIG_PPC_8xx) += 8xx/
|
obj-$(CONFIG_PPC_8xx) += 8xx/
|
||||||
obj-$(CONFIG_PPC_82xx) += 82xx/
|
obj-$(CONFIG_PPC_82xx) += 82xx/
|
||||||
|
@ -54,6 +54,13 @@ config SPU_FS_64K_LS
|
|||||||
uses 4K pages. This can improve performances of applications
|
uses 4K pages. This can improve performances of applications
|
||||||
using multiple SPEs by lowering the TLB pressure on them.
|
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
|
config SPU_BASE
|
||||||
bool
|
bool
|
||||||
default n
|
default n
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/pci.h>
|
#include <linux/pci.h>
|
||||||
#include <linux/msi.h>
|
#include <linux/msi.h>
|
||||||
#include <linux/reboot.h>
|
#include <linux/of_platform.h>
|
||||||
|
|
||||||
#include <asm/dcr.h>
|
#include <asm/dcr.h>
|
||||||
#include <asm/machdep.h>
|
#include <asm/machdep.h>
|
||||||
@ -65,14 +65,12 @@
|
|||||||
|
|
||||||
struct axon_msic {
|
struct axon_msic {
|
||||||
struct irq_host *irq_host;
|
struct irq_host *irq_host;
|
||||||
__le32 *fifo;
|
__le32 *fifo_virt;
|
||||||
|
dma_addr_t fifo_phys;
|
||||||
dcr_host_t dcr_host;
|
dcr_host_t dcr_host;
|
||||||
struct list_head list;
|
|
||||||
u32 read_offset;
|
u32 read_offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
static LIST_HEAD(axon_msic_list);
|
|
||||||
|
|
||||||
static void msic_dcr_write(struct axon_msic *msic, unsigned int dcr_n, u32 val)
|
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);
|
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) {
|
while (msic->read_offset != write_offset) {
|
||||||
idx = msic->read_offset / sizeof(__le32);
|
idx = msic->read_offset / sizeof(__le32);
|
||||||
msi = le32_to_cpu(msic->fifo[idx]);
|
msi = le32_to_cpu(msic->fifo_virt[idx]);
|
||||||
msi &= 0xFFFF;
|
msi &= 0xFFFF;
|
||||||
|
|
||||||
pr_debug("axon_msi: woff %x roff %x msi %x\n",
|
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;
|
tmp = dn;
|
||||||
dn = of_find_node_by_phandle(*ph);
|
dn = of_find_node_by_phandle(*ph);
|
||||||
|
of_node_put(tmp);
|
||||||
if (!dn) {
|
if (!dn) {
|
||||||
dev_dbg(&dev->dev,
|
dev_dbg(&dev->dev,
|
||||||
"axon_msi: msi-translator doesn't point to a node\n");
|
"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:
|
out_error:
|
||||||
of_node_put(dn);
|
of_node_put(dn);
|
||||||
of_node_put(tmp);
|
|
||||||
|
|
||||||
return msic;
|
return msic;
|
||||||
}
|
}
|
||||||
@ -292,30 +290,24 @@ static struct irq_host_ops msic_host_ops = {
|
|||||||
.map = msic_host_map,
|
.map = msic_host_map,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int axon_msi_notify_reboot(struct notifier_block *nb,
|
static int axon_msi_shutdown(struct of_device *device)
|
||||||
unsigned long code, void *data)
|
|
||||||
{
|
{
|
||||||
struct axon_msic *msic;
|
struct axon_msic *msic = device->dev.platform_data;
|
||||||
u32 tmp;
|
u32 tmp;
|
||||||
|
|
||||||
list_for_each_entry(msic, &axon_msic_list, list) {
|
pr_debug("axon_msi: disabling %s\n",
|
||||||
pr_debug("axon_msi: disabling %s\n",
|
msic->irq_host->of_node->full_name);
|
||||||
msic->irq_host->of_node->full_name);
|
tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
|
||||||
tmp = dcr_read(msic->dcr_host, MSIC_CTRL_REG);
|
tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
|
||||||
tmp &= ~MSIC_CTRL_ENABLE & ~MSIC_CTRL_IRQ_ENABLE;
|
msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
|
||||||
msic_dcr_write(msic, MSIC_CTRL_REG, tmp);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct notifier_block axon_msi_reboot_notifier = {
|
static int axon_msi_probe(struct of_device *device,
|
||||||
.notifier_call = axon_msi_notify_reboot
|
const struct of_device_id *device_id)
|
||||||
};
|
|
||||||
|
|
||||||
static int axon_msi_setup_one(struct device_node *dn)
|
|
||||||
{
|
{
|
||||||
struct page *page;
|
struct device_node *dn = device->node;
|
||||||
struct axon_msic *msic;
|
struct axon_msic *msic;
|
||||||
unsigned int virq;
|
unsigned int virq;
|
||||||
int dcr_base, dcr_len;
|
int dcr_base, dcr_len;
|
||||||
@ -346,16 +338,14 @@ static int axon_msi_setup_one(struct device_node *dn)
|
|||||||
goto out_free_msic;
|
goto out_free_msic;
|
||||||
}
|
}
|
||||||
|
|
||||||
page = alloc_pages_node(of_node_to_nid(dn), GFP_KERNEL,
|
msic->fifo_virt = dma_alloc_coherent(&device->dev, MSIC_FIFO_SIZE_BYTES,
|
||||||
get_order(MSIC_FIFO_SIZE_BYTES));
|
&msic->fifo_phys, GFP_KERNEL);
|
||||||
if (!page) {
|
if (!msic->fifo_virt) {
|
||||||
printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
|
printk(KERN_ERR "axon_msi: couldn't allocate fifo for %s\n",
|
||||||
dn->full_name);
|
dn->full_name);
|
||||||
goto out_free_msic;
|
goto out_free_msic;
|
||||||
}
|
}
|
||||||
|
|
||||||
msic->fifo = page_address(page);
|
|
||||||
|
|
||||||
msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP,
|
msic->irq_host = irq_alloc_host(of_node_get(dn), IRQ_HOST_MAP_NOMAP,
|
||||||
NR_IRQS, &msic_host_ops, 0);
|
NR_IRQS, &msic_host_ops, 0);
|
||||||
if (!msic->irq_host) {
|
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);
|
pr_debug("axon_msi: irq 0x%x setup for axon_msi\n", virq);
|
||||||
|
|
||||||
/* Enable the MSIC hardware */
|
/* 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,
|
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_dcr_write(msic, MSIC_CTRL_REG,
|
||||||
MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
|
MSIC_CTRL_IRQ_ENABLE | MSIC_CTRL_ENABLE |
|
||||||
MSIC_CTRL_FIFO_SIZE);
|
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);
|
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:
|
out_free_host:
|
||||||
kfree(msic->irq_host);
|
kfree(msic->irq_host);
|
||||||
out_free_fifo:
|
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:
|
out_free_msic:
|
||||||
kfree(msic);
|
kfree(msic);
|
||||||
out:
|
out:
|
||||||
@ -402,28 +397,24 @@ out:
|
|||||||
return -1;
|
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;
|
return of_register_platform_driver(&axon_msi_driver);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
arch_initcall(axon_msi_init);
|
subsys_initcall(axon_msi_init);
|
||||||
|
@ -98,7 +98,7 @@ static int __init cell_publish_devices(void)
|
|||||||
}
|
}
|
||||||
return 0;
|
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)
|
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 += sched.o backing_ops.o hw_ops.o run.o gang.o
|
||||||
spufs-y += switch.o fault.o lscsa_alloc.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
|
# Rules to build switch.o with the help of SPU tool chain
|
||||||
SPU_CROSS := spu-
|
SPU_CROSS := spu-
|
||||||
SPU_CC := $(SPU_CROSS)gcc
|
SPU_CC := $(SPU_CROSS)gcc
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include <linux/poll.h>
|
#include <linux/poll.h>
|
||||||
#include <linux/ptrace.h>
|
#include <linux/ptrace.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/marker.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/semaphore.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;
|
struct spu_context *ctx = vma->vm_file->private_data;
|
||||||
unsigned long area, offset = address - vma->vm_start;
|
unsigned long area, offset = address - vma->vm_start;
|
||||||
|
|
||||||
|
spu_context_nospu_trace(spufs_ps_nopfn__enter, ctx);
|
||||||
|
|
||||||
offset += vma->vm_pgoff << PAGE_SHIFT;
|
offset += vma->vm_pgoff << PAGE_SHIFT;
|
||||||
if (offset >= ps_size)
|
if (offset >= ps_size)
|
||||||
return NOPFN_SIGBUS;
|
return NOPFN_SIGBUS;
|
||||||
@ -375,11 +378,14 @@ static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
|
|||||||
|
|
||||||
if (ctx->state == SPU_STATE_SAVED) {
|
if (ctx->state == SPU_STATE_SAVED) {
|
||||||
up_read(¤t->mm->mmap_sem);
|
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);
|
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);
|
down_read(¤t->mm->mmap_sem);
|
||||||
} else {
|
} else {
|
||||||
area = ctx->spu->problem_phys + ps_offs;
|
area = ctx->spu->problem_phys + ps_offs;
|
||||||
vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT);
|
vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT);
|
||||||
|
spu_context_trace(spufs_ps_nopfn__insert, ctx, ctx->spu);
|
||||||
}
|
}
|
||||||
|
|
||||||
spu_release(ctx);
|
spu_release(ctx);
|
||||||
|
@ -322,7 +322,7 @@ static struct spu_context *
|
|||||||
spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
|
spufs_assert_affinity(unsigned int flags, struct spu_gang *gang,
|
||||||
struct file *filp)
|
struct file *filp)
|
||||||
{
|
{
|
||||||
struct spu_context *tmp, *neighbor;
|
struct spu_context *tmp, *neighbor, *err;
|
||||||
int count, node;
|
int count, node;
|
||||||
int aff_supp;
|
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) &&
|
if (!list_empty(&neighbor->aff_list) && !(neighbor->aff_head) &&
|
||||||
!list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
|
!list_is_last(&neighbor->aff_list, &gang->aff_list_head) &&
|
||||||
!list_entry(neighbor->aff_list.next, struct spu_context,
|
!list_entry(neighbor->aff_list.next, struct spu_context,
|
||||||
aff_list)->aff_head)
|
aff_list)->aff_head) {
|
||||||
return ERR_PTR(-EEXIST);
|
err = ERR_PTR(-EEXIST);
|
||||||
|
goto out_put_neighbor;
|
||||||
|
}
|
||||||
|
|
||||||
if (gang != neighbor->gang)
|
if (gang != neighbor->gang) {
|
||||||
return ERR_PTR(-EINVAL);
|
err = ERR_PTR(-EINVAL);
|
||||||
|
goto out_put_neighbor;
|
||||||
|
}
|
||||||
|
|
||||||
count = 1;
|
count = 1;
|
||||||
list_for_each_entry(tmp, &gang->aff_list_head, aff_list)
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node == MAX_NUMNODES)
|
if (node == MAX_NUMNODES) {
|
||||||
return ERR_PTR(-EEXIST);
|
err = ERR_PTR(-EEXIST);
|
||||||
|
goto out_put_neighbor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return neighbor;
|
return neighbor;
|
||||||
|
|
||||||
|
out_put_neighbor:
|
||||||
|
put_spu_context(neighbor);
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -454,9 +464,12 @@ spufs_create_context(struct inode *inode, struct dentry *dentry,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out_aff_unlock;
|
goto out_aff_unlock;
|
||||||
|
|
||||||
if (affinity)
|
if (affinity) {
|
||||||
spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
|
spufs_set_affinity(flags, SPUFS_I(dentry->d_inode)->i_ctx,
|
||||||
neighbor);
|
neighbor);
|
||||||
|
if (neighbor)
|
||||||
|
put_spu_context(neighbor);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* get references for dget and mntget, will be released
|
* 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
|
* since we have TIF_SINGLESTEP set, thus the kernel will do
|
||||||
* it upon return from the syscall anyawy
|
* it upon return from the syscall anyawy
|
||||||
*/
|
*/
|
||||||
if ((status & SPU_STATUS_STOPPED_BY_STOP)
|
if (unlikely(status & SPU_STATUS_SINGLE_STEP))
|
||||||
&& (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff) {
|
ret = -ERESTARTSYS;
|
||||||
|
|
||||||
|
else if (unlikely((status & SPU_STATUS_STOPPED_BY_STOP)
|
||||||
|
&& (status >> SPU_STOP_STATUS_SHIFT) == 0x3fff)) {
|
||||||
force_sig(SIGTRAP, current);
|
force_sig(SIGTRAP, current);
|
||||||
ret = -ERESTARTSYS;
|
ret = -ERESTARTSYS;
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <linux/pid_namespace.h>
|
#include <linux/pid_namespace.h>
|
||||||
#include <linux/proc_fs.h>
|
#include <linux/proc_fs.h>
|
||||||
#include <linux/seq_file.h>
|
#include <linux/seq_file.h>
|
||||||
|
#include <linux/marker.h>
|
||||||
|
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#include <asm/mmu_context.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)
|
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_context_trace(spu_bind_context__enter, ctx, spu);
|
||||||
spu->number, spu->node);
|
|
||||||
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
|
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
|
||||||
|
|
||||||
if (ctx->flags & SPU_CREATE_NOSCHED)
|
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)
|
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_context_trace(spu_unbind_context__enter, ctx, spu);
|
||||||
spu->pid, spu->number, spu->node);
|
|
||||||
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
|
spuctx_switch_state(ctx, SPU_UTIL_SYSTEM);
|
||||||
|
|
||||||
if (spu->ctx->flags & SPU_CREATE_NOSCHED)
|
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;
|
struct spu *spu, *aff_ref_spu;
|
||||||
int node, n;
|
int node, n;
|
||||||
|
|
||||||
|
spu_context_nospu_trace(spu_get_idle__enter, ctx);
|
||||||
|
|
||||||
if (ctx->gang) {
|
if (ctx->gang) {
|
||||||
mutex_lock(&ctx->gang->aff_mutex);
|
mutex_lock(&ctx->gang->aff_mutex);
|
||||||
if (has_affinity(ctx)) {
|
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))
|
if (atomic_dec_and_test(&ctx->gang->aff_sched_count))
|
||||||
ctx->gang->aff_ref_spu = NULL;
|
ctx->gang->aff_ref_spu = NULL;
|
||||||
mutex_unlock(&ctx->gang->aff_mutex);
|
mutex_unlock(&ctx->gang->aff_mutex);
|
||||||
|
goto not_found;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
mutex_unlock(&ctx->gang->aff_mutex);
|
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);
|
mutex_unlock(&cbe_spu_info[node].list_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
not_found:
|
||||||
|
spu_context_nospu_trace(spu_get_idle__not_found, ctx);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
found:
|
found:
|
||||||
spu->alloc_state = SPU_USED;
|
spu->alloc_state = SPU_USED;
|
||||||
mutex_unlock(&cbe_spu_info[node].list_mutex);
|
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);
|
spu_init_channels(spu);
|
||||||
return spu;
|
return spu;
|
||||||
}
|
}
|
||||||
@ -587,6 +591,8 @@ static struct spu *find_victim(struct spu_context *ctx)
|
|||||||
struct spu *spu;
|
struct spu *spu;
|
||||||
int node, n;
|
int node, n;
|
||||||
|
|
||||||
|
spu_context_nospu_trace(spu_find_vitim__enter, ctx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look for a possible preemption candidate on the local node first.
|
* Look for a possible preemption candidate on the local node first.
|
||||||
* If there is no candidate look at the other nodes. This isn't
|
* 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;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spu_context_trace(__spu_deactivate__unload, ctx, spu);
|
||||||
|
|
||||||
mutex_lock(&cbe_spu_info[node].list_mutex);
|
mutex_lock(&cbe_spu_info[node].list_mutex);
|
||||||
cbe_spu_info[node].nr_active--;
|
cbe_spu_info[node].nr_active--;
|
||||||
spu_unbind_context(spu, victim);
|
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)
|
void spu_deactivate(struct spu_context *ctx)
|
||||||
{
|
{
|
||||||
|
spu_context_nospu_trace(spu_deactivate__enter, ctx);
|
||||||
__spu_deactivate(ctx, 1, MAX_PRIO);
|
__spu_deactivate(ctx, 1, MAX_PRIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -835,6 +844,7 @@ void spu_deactivate(struct spu_context *ctx)
|
|||||||
*/
|
*/
|
||||||
void spu_yield(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)) {
|
if (!(ctx->flags & SPU_CREATE_NOSCHED)) {
|
||||||
mutex_lock(&ctx->state_mutex);
|
mutex_lock(&ctx->state_mutex);
|
||||||
__spu_deactivate(ctx, 0, MAX_PRIO);
|
__spu_deactivate(ctx, 0, MAX_PRIO);
|
||||||
@ -864,11 +874,15 @@ static noinline void spusched_tick(struct spu_context *ctx)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
spu = ctx->spu;
|
spu = ctx->spu;
|
||||||
|
|
||||||
|
spu_context_trace(spusched_tick__preempt, ctx, spu);
|
||||||
|
|
||||||
new = grab_runnable_context(ctx->prio + 1, spu->node);
|
new = grab_runnable_context(ctx->prio + 1, spu->node);
|
||||||
if (new) {
|
if (new) {
|
||||||
spu_unschedule(spu, ctx);
|
spu_unschedule(spu, ctx);
|
||||||
spu_add_to_rq(ctx);
|
spu_add_to_rq(ctx);
|
||||||
} else {
|
} else {
|
||||||
|
spu_context_nospu_trace(spusched_tick__newslice, ctx);
|
||||||
ctx->time_slice++;
|
ctx->time_slice++;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
@ -325,4 +325,9 @@ extern void spu_free_lscsa(struct spu_state *csa);
|
|||||||
extern void spuctx_switch_state(struct spu_context *ctx,
|
extern void spuctx_switch_state(struct spu_context *ctx,
|
||||||
enum spu_utilization_state new_state);
|
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
|
#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);
|
paddr = (phys_addr_t)of_translate_address(dnp, prop);
|
||||||
mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET,
|
mpic = mpic_alloc(dnp, paddr, MPIC_PRIMARY | MPIC_WANTS_RESET,
|
||||||
4, 32, " EPIC ");
|
16, 32, " OpenPIC ");
|
||||||
|
|
||||||
of_node_put(dnp);
|
of_node_put(dnp);
|
||||||
|
|
||||||
BUG_ON(mpic == NULL);
|
BUG_ON(mpic == NULL);
|
||||||
|
|
||||||
/* PCI IRQs */
|
|
||||||
/*
|
/*
|
||||||
* 2.6.12 patch:
|
* 16 Serial Interrupts followed by 16 Internal Interrupts.
|
||||||
* openpic_set_sources(0, 5, OpenPIC_Addr + 0x10200);
|
* I2C is the second internal, so it is at 17, 0x11020.
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
mpic_assign_isu(mpic, 0, paddr + 0x10200);
|
mpic_assign_isu(mpic, 0, paddr + 0x10200);
|
||||||
mpic_assign_isu(mpic, 1, paddr + 0x10220);
|
mpic_assign_isu(mpic, 1, paddr + 0x11000);
|
||||||
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_init(mpic);
|
mpic_init(mpic);
|
||||||
}
|
}
|
||||||
@ -178,7 +163,7 @@ static int __init storcenter_probe(void)
|
|||||||
{
|
{
|
||||||
unsigned long root = of_get_flat_dt_root();
|
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){
|
define_machine(storcenter){
|
||||||
|
@ -58,7 +58,7 @@ static void pseries_mach_cpu_die(void)
|
|||||||
{
|
{
|
||||||
local_irq_disable();
|
local_irq_disable();
|
||||||
idle_task_exit();
|
idle_task_exit();
|
||||||
xics_teardown_cpu(0);
|
xics_teardown_cpu();
|
||||||
unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow()));
|
unregister_slb_shadow(hard_smp_processor_id(), __pa(get_slb_shadow()));
|
||||||
rtas_stop_self();
|
rtas_stop_self();
|
||||||
/* Should never get here... */
|
/* 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)
|
static void pseries_kexec_cpu_down_xics(int crash_shutdown, int secondary)
|
||||||
{
|
{
|
||||||
pseries_kexec_cpu_down(crash_shutdown, 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)
|
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))) {
|
if ((child = of_get_next_child(np, NULL))) {
|
||||||
of_node_put(child);
|
of_node_put(child);
|
||||||
|
of_node_put(parent);
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,6 +160,46 @@ static inline void lpar_qirr_info(int n_cpu , u8 value)
|
|||||||
|
|
||||||
/* High level handlers and init code */
|
/* 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
|
#ifdef CONFIG_SMP
|
||||||
static int get_irq_server(unsigned int virq, unsigned int strict_check)
|
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 cpumask = irq_desc[virq].affinity;
|
||||||
cpumask_t tmp = CPU_MASK_NONE;
|
cpumask_t tmp = CPU_MASK_NONE;
|
||||||
|
|
||||||
|
if (! cpu_isset(default_server, cpu_online_map))
|
||||||
|
xics_update_irq_servers();
|
||||||
|
|
||||||
if (!distribute_irqs)
|
if (!distribute_irqs)
|
||||||
return default_server;
|
return default_server;
|
||||||
|
|
||||||
@ -658,39 +701,11 @@ static void __init xics_setup_8259_cascade(void)
|
|||||||
set_irq_chained_handler(cascade, pseries_8259_cascade);
|
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)
|
void __init xics_init_IRQ(void)
|
||||||
{
|
{
|
||||||
int i, j;
|
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
u32 ilen, indx = 0;
|
u32 indx = 0;
|
||||||
const u32 *ireg, *isize;
|
|
||||||
int found = 0;
|
int found = 0;
|
||||||
u32 hcpuid;
|
|
||||||
|
|
||||||
ppc64_boot_msg(0x20, "XICS Init");
|
ppc64_boot_msg(0x20, "XICS Init");
|
||||||
|
|
||||||
@ -709,34 +724,7 @@ void __init xics_init_IRQ(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
xics_init_host();
|
xics_init_host();
|
||||||
|
xics_update_irq_servers();
|
||||||
/* 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);
|
|
||||||
|
|
||||||
if (firmware_has_feature(FW_FEATURE_LPAR))
|
if (firmware_has_feature(FW_FEATURE_LPAR))
|
||||||
ppc_md.get_irq = xics_get_irq_lpar;
|
ppc_md.get_irq = xics_get_irq_lpar;
|
||||||
@ -775,11 +763,9 @@ void xics_request_IPIs(void)
|
|||||||
}
|
}
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
void xics_teardown_cpu(int secondary)
|
void xics_teardown_cpu()
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
int cpu = smp_processor_id();
|
||||||
unsigned int ipi;
|
|
||||||
struct irq_desc *desc;
|
|
||||||
|
|
||||||
xics_set_cpu_priority(0);
|
xics_set_cpu_priority(0);
|
||||||
|
|
||||||
@ -790,9 +776,17 @@ void xics_teardown_cpu(int secondary)
|
|||||||
lpar_qirr_info(cpu, 0xff);
|
lpar_qirr_info(cpu, 0xff);
|
||||||
else
|
else
|
||||||
direct_qirr_info(cpu, 0xff);
|
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
|
* probably need to check all the other interrupts too
|
||||||
* should we be flagging idle loop instead?
|
* should we be flagging idle loop instead?
|
||||||
@ -880,8 +874,8 @@ void xics_migrate_irqs_away(void)
|
|||||||
virq, cpu);
|
virq, cpu);
|
||||||
|
|
||||||
/* Reset affinity to all cpus */
|
/* Reset affinity to all cpus */
|
||||||
|
irq_desc[virq].affinity = CPU_MASK_ALL;
|
||||||
desc->chip->set_affinity(virq, CPU_MASK_ALL);
|
desc->chip->set_affinity(virq, CPU_MASK_ALL);
|
||||||
irq_desc[irq].affinity = CPU_MASK_ALL;
|
|
||||||
unlock:
|
unlock:
|
||||||
spin_unlock_irqrestore(&desc->lock, flags);
|
spin_unlock_irqrestore(&desc->lock, flags);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
|
|
||||||
extern void xics_init_IRQ(void);
|
extern void xics_init_IRQ(void);
|
||||||
extern void xics_setup_cpu(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_cause_IPI(int cpu);
|
||||||
extern void xics_request_IPIs(void);
|
extern void xics_request_IPIs(void);
|
||||||
extern void xics_migrate_irqs_away(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;
|
h.token = NULL;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dcr_unmap);
|
EXPORT_SYMBOL_GPL(dcr_unmap);
|
||||||
|
#else /* defined(CONFIG_PPC_DCR_NATIVE) */
|
||||||
#endif /* !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)
|
if (ret)
|
||||||
goto unreg;
|
goto unreg;
|
||||||
|
|
||||||
ret = platform_device_register(pdev);
|
ret = platform_device_add(pdev);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto unreg;
|
goto unreg;
|
||||||
|
|
||||||
|
@ -174,15 +174,19 @@ int mpc8xx_pic_init(void)
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
siu_reg = ioremap(res.start, res.end - res.start + 1);
|
siu_reg = ioremap(res.start, res.end - res.start + 1);
|
||||||
if (siu_reg == NULL)
|
if (siu_reg == NULL) {
|
||||||
return -EINVAL;
|
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);
|
64, &mpc8xx_pic_host_ops, 64);
|
||||||
if (mpc8xx_pic_host == NULL) {
|
if (mpc8xx_pic_host == NULL) {
|
||||||
printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
|
printk(KERN_ERR "MPC8xx PIC: failed to allocate irq host!\n");
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
of_node_put(np);
|
of_node_put(np);
|
||||||
|
@ -66,7 +66,7 @@ phys_addr_t get_qe_base(void)
|
|||||||
{
|
{
|
||||||
struct device_node *qe;
|
struct device_node *qe;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
const void *prop;
|
const u32 *prop;
|
||||||
|
|
||||||
if (qebase != -1)
|
if (qebase != -1)
|
||||||
return qebase;
|
return qebase;
|
||||||
@ -79,7 +79,8 @@ phys_addr_t get_qe_base(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
prop = of_get_property(qe, "reg", &size);
|
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);
|
of_node_put(qe);
|
||||||
|
|
||||||
return qebase;
|
return qebase;
|
||||||
@ -172,10 +173,9 @@ unsigned int get_brg_clk(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
prop = of_get_property(qe, "brg-frequency", &size);
|
prop = of_get_property(qe, "brg-frequency", &size);
|
||||||
if (!prop || size != sizeof(*prop))
|
if (prop && size == sizeof(*prop))
|
||||||
return brg_clk;
|
brg_clk = *prop;
|
||||||
|
|
||||||
brg_clk = *prop;
|
|
||||||
of_node_put(qe);
|
of_node_put(qe);
|
||||||
|
|
||||||
return brg_clk;
|
return brg_clk;
|
||||||
|
@ -1202,8 +1202,10 @@ static int __devexit ace_of_remove(struct of_device *op)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Match table for of_platform binding */
|
/* Match table for of_platform binding */
|
||||||
static struct of_device_id __devinit ace_of_match[] = {
|
static struct of_device_id ace_of_match[] __devinitdata = {
|
||||||
{ .compatible = "xilinx,xsysace", },
|
{ .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);
|
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
|
.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;
|
struct capability_entry *entry;
|
||||||
|
|
||||||
|
@ -830,6 +830,16 @@ config DTLK
|
|||||||
To compile this driver as a module, choose M here: the
|
To compile this driver as a module, choose M here: the
|
||||||
module will be called dtlk.
|
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
|
config R3964
|
||||||
tristate "Siemens R3964 line discipline"
|
tristate "Siemens R3964 line discipline"
|
||||||
---help---
|
---help---
|
||||||
|
@ -76,6 +76,7 @@ obj-$(CONFIG_EFI_RTC) += efirtc.o
|
|||||||
obj-$(CONFIG_SGI_DS1286) += ds1286.o
|
obj-$(CONFIG_SGI_DS1286) += ds1286.o
|
||||||
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
|
obj-$(CONFIG_SGI_IP27_RTC) += ip27-rtc.o
|
||||||
obj-$(CONFIG_DS1302) += ds1302.o
|
obj-$(CONFIG_DS1302) += ds1302.o
|
||||||
|
obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/
|
||||||
ifeq ($(CONFIG_GENERIC_NVRAM),y)
|
ifeq ($(CONFIG_GENERIC_NVRAM),y)
|
||||||
obj-$(CONFIG_NVRAM) += generic_nvram.o
|
obj-$(CONFIG_NVRAM) += generic_nvram.o
|
||||||
else
|
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
|
config CPMAC
|
||||||
tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
|
tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)"
|
||||||
depends on NET_ETHERNET && EXPERIMENTAL && AR7
|
depends on NET_ETHERNET && EXPERIMENTAL && AR7 && BROKEN
|
||||||
select PHYLIB
|
select PHYLIB
|
||||||
select FIXED_PHY
|
|
||||||
select FIXED_MII_100_FDX
|
|
||||||
help
|
help
|
||||||
TI AR7 CPMAC Ethernet support
|
TI AR7 CPMAC Ethernet support
|
||||||
|
|
||||||
|
@ -845,15 +845,6 @@ static void cpmac_adjust_link(struct net_device *dev)
|
|||||||
spin_unlock(&priv->lock);
|
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)
|
static int cpmac_open(struct net_device *dev)
|
||||||
{
|
{
|
||||||
int i, size, res;
|
int i, size, res;
|
||||||
@ -996,11 +987,11 @@ static int external_switch;
|
|||||||
static int __devinit cpmac_probe(struct platform_device *pdev)
|
static int __devinit cpmac_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int rc, phy_id, i;
|
int rc, phy_id, i;
|
||||||
|
int mdio_bus_id = cpmac_mii.id;
|
||||||
struct resource *mem;
|
struct resource *mem;
|
||||||
struct cpmac_priv *priv;
|
struct cpmac_priv *priv;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
struct plat_cpmac_data *pdata;
|
struct plat_cpmac_data *pdata;
|
||||||
struct fixed_info *fixed_phy;
|
|
||||||
DECLARE_MAC_BUF(mac);
|
DECLARE_MAC_BUF(mac);
|
||||||
|
|
||||||
pdata = pdev->dev.platform_data;
|
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 (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;
|
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");
|
printk(KERN_ERR "cpmac: no PHY present\n");
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@ -1060,32 +1065,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev)
|
|||||||
priv->msg_enable = netif_msg_init(debug_level, 0xff);
|
priv->msg_enable = netif_msg_init(debug_level, 0xff);
|
||||||
memcpy(dev->dev_addr, pdata->dev_addr, sizeof(dev->dev_addr));
|
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, mdio_bus_id, phy_id);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
phy_found:
|
|
||||||
priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0,
|
priv->phy = phy_connect(dev, priv->phy_name, &cpmac_adjust_link, 0,
|
||||||
PHY_INTERFACE_MODE_MII);
|
PHY_INTERFACE_MODE_MII);
|
||||||
if (IS_ERR(priv->phy)) {
|
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);
|
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
|
* of_get_next_child - Iterate a node childs
|
||||||
* @node: parent node
|
* @node: parent node
|
||||||
|
@ -85,6 +85,15 @@ static int of_platform_device_resume(struct device * dev)
|
|||||||
return error;
|
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)
|
int of_bus_type_init(struct bus_type *bus, const char *name)
|
||||||
{
|
{
|
||||||
bus->name = 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->remove = of_platform_device_remove;
|
||||||
bus->suspend = of_platform_device_suspend;
|
bus->suspend = of_platform_device_suspend;
|
||||||
bus->resume = of_platform_device_resume;
|
bus->resume = of_platform_device_resume;
|
||||||
|
bus->shutdown = of_platform_device_shutdown;
|
||||||
return bus_register(bus);
|
return bus_register(bus);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1142,17 +1142,17 @@ config SERIAL_SGI_L1_CONSOLE
|
|||||||
say Y. Otherwise, say N.
|
say Y. Otherwise, say N.
|
||||||
|
|
||||||
config SERIAL_MPC52xx
|
config SERIAL_MPC52xx
|
||||||
tristate "Freescale MPC52xx family PSC serial support"
|
tristate "Freescale MPC52xx/MPC512x family PSC serial support"
|
||||||
depends on PPC_MPC52xx
|
depends on PPC_MPC52xx || PPC_MPC512x
|
||||||
select SERIAL_CORE
|
select SERIAL_CORE
|
||||||
help
|
help
|
||||||
This drivers support the MPC52xx PSC serial ports. If you would
|
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. Not that
|
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
|
for use as console, it must be included in kernel and not as a
|
||||||
module.
|
module.
|
||||||
|
|
||||||
config SERIAL_MPC52xx_CONSOLE
|
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
|
depends on SERIAL_MPC52xx=y
|
||||||
select SERIAL_CORE_CONSOLE
|
select SERIAL_CORE_CONSOLE
|
||||||
help
|
help
|
||||||
@ -1160,7 +1160,7 @@ config SERIAL_MPC52xx_CONSOLE
|
|||||||
of the Freescale MPC52xx family as a console.
|
of the Freescale MPC52xx family as a console.
|
||||||
|
|
||||||
config SERIAL_MPC52xx_CONSOLE_BAUD
|
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
|
depends on SERIAL_MPC52xx_CONSOLE=y
|
||||||
default "9600"
|
default "9600"
|
||||||
help
|
help
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
* Some of the code has been inspired/copied from the 2.4 code written
|
* Some of the code has been inspired/copied from the 2.4 code written
|
||||||
* by Dale Farnsworth <dfarnsworth@mvista.com>.
|
* 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.
|
* Copyright (C) 2006 Secret Lab Technologies Ltd.
|
||||||
* Grant Likely <grant.likely@secretlab.ca>
|
* Grant Likely <grant.likely@secretlab.ca>
|
||||||
* Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
|
* Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
|
||||||
@ -67,7 +70,6 @@
|
|||||||
#include <linux/serial.h>
|
#include <linux/serial.h>
|
||||||
#include <linux/sysrq.h>
|
#include <linux/sysrq.h>
|
||||||
#include <linux/console.h>
|
#include <linux/console.h>
|
||||||
|
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
|
||||||
@ -79,6 +81,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <asm/mpc52xx.h>
|
#include <asm/mpc52xx.h>
|
||||||
|
#include <asm/mpc512x.h>
|
||||||
#include <asm/mpc52xx_psc.h>
|
#include <asm/mpc52xx_psc.h>
|
||||||
|
|
||||||
#if defined(CONFIG_SERIAL_MPC52xx_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
|
#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);
|
static void mpc52xx_uart_of_enumerate(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
|
#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 */
|
/* 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)
|
#define uart_console(port) (0)
|
||||||
#endif
|
#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)
|
#if defined(CONFIG_PPC_MERGE)
|
||||||
static struct of_device_id mpc52xx_uart_of_match[] = {
|
/*
|
||||||
{ .type = "serial", .compatible = "fsl,mpc5200-psc-uart", },
|
* 5200 UARTs have a / 32 prescaler
|
||||||
{ .type = "serial", .compatible = "mpc5200-psc-uart", }, /* lite5200 */
|
* but the generic serial code assumes 16
|
||||||
{ .type = "serial", .compatible = "mpc5200-serial", }, /* efika */
|
* 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
|
#endif
|
||||||
|
|
||||||
|
static struct psc_ops *psc_ops;
|
||||||
|
|
||||||
/* ======================================================================== */
|
/* ======================================================================== */
|
||||||
/* UART operations */
|
/* UART operations */
|
||||||
@ -145,8 +434,7 @@ static struct of_device_id mpc52xx_uart_of_match[] = {
|
|||||||
static unsigned int
|
static unsigned int
|
||||||
mpc52xx_uart_tx_empty(struct uart_port *port)
|
mpc52xx_uart_tx_empty(struct uart_port *port)
|
||||||
{
|
{
|
||||||
int status = in_be16(&PSC(port)->mpc52xx_psc_status);
|
return psc_ops->tx_empty(port) ? TIOCSER_TEMT : 0;
|
||||||
return (status & MPC52xx_PSC_SR_TXEMP) ? TIOCSER_TEMT : 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -166,16 +454,14 @@ static void
|
|||||||
mpc52xx_uart_stop_tx(struct uart_port *port)
|
mpc52xx_uart_stop_tx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
/* port->lock taken by caller */
|
/* port->lock taken by caller */
|
||||||
port->read_status_mask &= ~MPC52xx_PSC_IMR_TXRDY;
|
psc_ops->stop_tx(port);
|
||||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mpc52xx_uart_start_tx(struct uart_port *port)
|
mpc52xx_uart_start_tx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
/* port->lock taken by caller */
|
/* port->lock taken by caller */
|
||||||
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
|
psc_ops->start_tx(port);
|
||||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -188,8 +474,7 @@ mpc52xx_uart_send_xchar(struct uart_port *port, char ch)
|
|||||||
if (ch) {
|
if (ch) {
|
||||||
/* Make sure tx interrupts are on */
|
/* Make sure tx interrupts are on */
|
||||||
/* Truly necessary ??? They should be anyway */
|
/* Truly necessary ??? They should be anyway */
|
||||||
port->read_status_mask |= MPC52xx_PSC_IMR_TXRDY;
|
psc_ops->start_tx(port);
|
||||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&port->lock, flags);
|
spin_unlock_irqrestore(&port->lock, flags);
|
||||||
@ -199,8 +484,7 @@ static void
|
|||||||
mpc52xx_uart_stop_rx(struct uart_port *port)
|
mpc52xx_uart_stop_rx(struct uart_port *port)
|
||||||
{
|
{
|
||||||
/* port->lock taken by caller */
|
/* port->lock taken by caller */
|
||||||
port->read_status_mask &= ~MPC52xx_PSC_IMR_RXRDY;
|
psc_ops->stop_rx(port);
|
||||||
out_be16(&PSC(port)->mpc52xx_psc_imr, port->read_status_mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -227,12 +511,12 @@ static int
|
|||||||
mpc52xx_uart_startup(struct uart_port *port)
|
mpc52xx_uart_startup(struct uart_port *port)
|
||||||
{
|
{
|
||||||
struct mpc52xx_psc __iomem *psc = PSC(port);
|
struct mpc52xx_psc __iomem *psc = PSC(port);
|
||||||
struct mpc52xx_psc_fifo __iomem *fifo = FIFO(port);
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Request IRQ */
|
/* Request IRQ */
|
||||||
ret = request_irq(port->irq, mpc52xx_uart_int,
|
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)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
@ -242,15 +526,7 @@ mpc52xx_uart_startup(struct uart_port *port)
|
|||||||
|
|
||||||
out_be32(&psc->sicr, 0); /* UART mode DCD ignored */
|
out_be32(&psc->sicr, 0); /* UART mode DCD ignored */
|
||||||
|
|
||||||
out_be16(&psc->mpc52xx_psc_clock_select, 0xdd00); /* /16 prescaler on */
|
psc_ops->fifo_init(port);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
|
out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
|
||||||
out_8(&psc->command, MPC52xx_PSC_RX_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
|
* boot for the console, all stuff is not yet ready to receive at that
|
||||||
* time and that just makes the kernel oops */
|
* time and that just makes the kernel oops */
|
||||||
/* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
|
/* while (j-- && mpc52xx_uart_int_rx_chars(port)); */
|
||||||
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
|
while (!mpc52xx_uart_tx_empty(port) && --j)
|
||||||
--j)
|
|
||||||
udelay(1);
|
udelay(1);
|
||||||
|
|
||||||
if (!j)
|
if (!j)
|
||||||
@ -462,11 +737,9 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
|||||||
unsigned short status;
|
unsigned short status;
|
||||||
|
|
||||||
/* While we can read, do so ! */
|
/* While we can read, do so ! */
|
||||||
while ((status = in_be16(&PSC(port)->mpc52xx_psc_status)) &
|
while (psc_ops->raw_rx_rdy(port)) {
|
||||||
MPC52xx_PSC_SR_RXRDY) {
|
|
||||||
|
|
||||||
/* Get the char */
|
/* Get the char */
|
||||||
ch = in_8(&PSC(port)->mpc52xx_psc_buffer_8);
|
ch = psc_ops->read_char(port);
|
||||||
|
|
||||||
/* Handle sysreq char */
|
/* Handle sysreq char */
|
||||||
#ifdef SUPPORT_SYSRQ
|
#ifdef SUPPORT_SYSRQ
|
||||||
@ -481,6 +754,8 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
|||||||
flag = TTY_NORMAL;
|
flag = TTY_NORMAL;
|
||||||
port->icount.rx++;
|
port->icount.rx++;
|
||||||
|
|
||||||
|
status = in_be16(&PSC(port)->mpc52xx_psc_status);
|
||||||
|
|
||||||
if (status & (MPC52xx_PSC_SR_PE |
|
if (status & (MPC52xx_PSC_SR_PE |
|
||||||
MPC52xx_PSC_SR_FE |
|
MPC52xx_PSC_SR_FE |
|
||||||
MPC52xx_PSC_SR_RB)) {
|
MPC52xx_PSC_SR_RB)) {
|
||||||
@ -510,7 +785,7 @@ mpc52xx_uart_int_rx_chars(struct uart_port *port)
|
|||||||
|
|
||||||
tty_flip_buffer_push(tty);
|
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
|
static inline int
|
||||||
@ -520,7 +795,7 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
|
|||||||
|
|
||||||
/* Process out of band chars */
|
/* Process out of band chars */
|
||||||
if (port->x_char) {
|
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->icount.tx++;
|
||||||
port->x_char = 0;
|
port->x_char = 0;
|
||||||
return 1;
|
return 1;
|
||||||
@ -533,8 +808,8 @@ mpc52xx_uart_int_tx_chars(struct uart_port *port)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Send chars */
|
/* Send chars */
|
||||||
while (in_be16(&PSC(port)->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXRDY) {
|
while (psc_ops->raw_tx_rdy(port)) {
|
||||||
out_8(&PSC(port)->mpc52xx_psc_buffer_8, xmit->buf[xmit->tail]);
|
psc_ops->write_char(port, xmit->buf[xmit->tail]);
|
||||||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||||||
port->icount.tx++;
|
port->icount.tx++;
|
||||||
if (uart_circ_empty(xmit))
|
if (uart_circ_empty(xmit))
|
||||||
@ -560,7 +835,6 @@ mpc52xx_uart_int(int irq, void *dev_id)
|
|||||||
struct uart_port *port = dev_id;
|
struct uart_port *port = dev_id;
|
||||||
unsigned long pass = ISR_PASS_LIMIT;
|
unsigned long pass = ISR_PASS_LIMIT;
|
||||||
unsigned int keepgoing;
|
unsigned int keepgoing;
|
||||||
unsigned short status;
|
|
||||||
|
|
||||||
spin_lock(&port->lock);
|
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 */
|
/* If we don't find anything to do, we stop */
|
||||||
keepgoing = 0;
|
keepgoing = 0;
|
||||||
|
|
||||||
/* Read status */
|
psc_ops->rx_clr_irq(port);
|
||||||
status = in_be16(&PSC(port)->mpc52xx_psc_isr);
|
if (psc_ops->rx_rdy(port))
|
||||||
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)
|
|
||||||
keepgoing |= mpc52xx_uart_int_rx_chars(port);
|
keepgoing |= mpc52xx_uart_int_rx_chars(port);
|
||||||
|
|
||||||
/* Do we need to send chars ? */
|
psc_ops->tx_clr_irq(port);
|
||||||
/* For this, TX must be ready and TX interrupt enabled */
|
if (psc_ops->tx_rdy(port))
|
||||||
if (status & MPC52xx_PSC_IMR_TXRDY)
|
|
||||||
keepgoing |= mpc52xx_uart_int_tx_chars(port);
|
keepgoing |= mpc52xx_uart_int_tx_chars(port);
|
||||||
|
|
||||||
/* Limit number of iteration */
|
/* Limit number of iteration */
|
||||||
@ -647,36 +915,33 @@ static void
|
|||||||
mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
|
mpc52xx_console_write(struct console *co, const char *s, unsigned int count)
|
||||||
{
|
{
|
||||||
struct uart_port *port = &mpc52xx_uart_ports[co->index];
|
struct uart_port *port = &mpc52xx_uart_ports[co->index];
|
||||||
struct mpc52xx_psc __iomem *psc = PSC(port);
|
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
|
|
||||||
/* Disable interrupts */
|
/* Disable interrupts */
|
||||||
out_be16(&psc->mpc52xx_psc_imr, 0);
|
psc_ops->cw_disable_ints(port);
|
||||||
|
|
||||||
/* Wait the TX buffer to be empty */
|
/* Wait the TX buffer to be empty */
|
||||||
j = 5000000; /* Maximum wait */
|
j = 5000000; /* Maximum wait */
|
||||||
while (!(in_be16(&psc->mpc52xx_psc_status) & MPC52xx_PSC_SR_TXEMP) &&
|
while (!mpc52xx_uart_tx_empty(port) && --j)
|
||||||
--j)
|
|
||||||
udelay(1);
|
udelay(1);
|
||||||
|
|
||||||
/* Write all the chars */
|
/* Write all the chars */
|
||||||
for (i = 0; i < count; i++, s++) {
|
for (i = 0; i < count; i++, s++) {
|
||||||
/* Line return handling */
|
/* Line return handling */
|
||||||
if (*s == '\n')
|
if (*s == '\n')
|
||||||
out_8(&psc->mpc52xx_psc_buffer_8, '\r');
|
psc_ops->write_char(port, '\r');
|
||||||
|
|
||||||
/* Send the char */
|
/* Send the char */
|
||||||
out_8(&psc->mpc52xx_psc_buffer_8, *s);
|
psc_ops->write_char(port, *s);
|
||||||
|
|
||||||
/* Wait the TX buffer to be empty */
|
/* Wait the TX buffer to be empty */
|
||||||
j = 20000; /* Maximum wait */
|
j = 20000; /* Maximum wait */
|
||||||
while (!(in_be16(&psc->mpc52xx_psc_status) &
|
while (!mpc52xx_uart_tx_empty(port) && --j)
|
||||||
MPC52xx_PSC_SR_TXEMP) && --j)
|
|
||||||
udelay(1);
|
udelay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Restore interrupt state */
|
/* Restore interrupt state */
|
||||||
out_be16(&psc->mpc52xx_psc_imr, port->read_status_mask);
|
psc_ops->cw_restore_ints(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(CONFIG_PPC_MERGE)
|
#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 uart_port *port = &mpc52xx_uart_ports[co->index];
|
||||||
struct device_node *np = mpc52xx_uart_nodes[co->index];
|
struct device_node *np = mpc52xx_uart_nodes[co->index];
|
||||||
unsigned int ipb_freq;
|
unsigned int uartclk;
|
||||||
struct resource res;
|
struct resource res;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -753,17 +1018,16 @@ mpc52xx_console_setup(struct console *co, char *options)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Search for bus-frequency property in this node or a parent */
|
uartclk = psc_ops->getuartclk(np);
|
||||||
ipb_freq = mpc52xx_find_ipb_freq(np);
|
if (uartclk == 0) {
|
||||||
if (ipb_freq == 0) {
|
pr_debug("Could not find uart clock frequency!\n");
|
||||||
pr_debug("Could not find IPB bus frequency!\n");
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Basic port init. Needed since we use some uart_??? func before
|
/* Basic port init. Needed since we use some uart_??? func before
|
||||||
* real init for early access */
|
* real init for early access */
|
||||||
spin_lock_init(&port->lock);
|
spin_lock_init(&port->lock);
|
||||||
port->uartclk = ipb_freq / 2;
|
port->uartclk = uartclk;
|
||||||
port->ops = &mpc52xx_uart_ops;
|
port->ops = &mpc52xx_uart_ops;
|
||||||
port->mapbase = res.start;
|
port->mapbase = res.start;
|
||||||
port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
|
port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
|
||||||
@ -945,11 +1209,25 @@ static struct platform_driver mpc52xx_uart_platform_driver = {
|
|||||||
/* OF 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
|
static int __devinit
|
||||||
mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
|
mpc52xx_uart_of_probe(struct of_device *op, const struct of_device_id *match)
|
||||||
{
|
{
|
||||||
int idx = -1;
|
int idx = -1;
|
||||||
unsigned int ipb_freq;
|
unsigned int uartclk;
|
||||||
struct uart_port *port = NULL;
|
struct uart_port *port = NULL;
|
||||||
struct resource res;
|
struct resource res;
|
||||||
int ret;
|
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",
|
pr_debug("Found %s assigned to ttyPSC%x\n",
|
||||||
mpc52xx_uart_nodes[idx]->full_name, idx);
|
mpc52xx_uart_nodes[idx]->full_name, idx);
|
||||||
|
|
||||||
/* Search for bus-frequency property in this node or a parent */
|
uartclk = psc_ops->getuartclk(op->node);
|
||||||
ipb_freq = mpc52xx_find_ipb_freq(op->node);
|
if (uartclk == 0) {
|
||||||
if (ipb_freq == 0) {
|
dev_dbg(&op->dev, "Could not find uart clock frequency!\n");
|
||||||
dev_dbg(&op->dev, "Could not find IPB bus frequency!\n");
|
|
||||||
return -EINVAL;
|
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];
|
port = &mpc52xx_uart_ports[idx];
|
||||||
|
|
||||||
spin_lock_init(&port->lock);
|
spin_lock_init(&port->lock);
|
||||||
port->uartclk = ipb_freq / 2;
|
port->uartclk = uartclk;
|
||||||
port->fifosize = 512;
|
port->fifosize = 512;
|
||||||
port->iotype = UPIO_MEM;
|
port->iotype = UPIO_MEM;
|
||||||
port->flags = UPF_BOOT_AUTOCONF |
|
port->flags = UPF_BOOT_AUTOCONF |
|
||||||
@ -1080,15 +1357,19 @@ mpc52xx_uart_of_enumerate(void)
|
|||||||
static int enum_done;
|
static int enum_done;
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
const unsigned int *devno;
|
const unsigned int *devno;
|
||||||
|
const struct of_device_id *match;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (enum_done)
|
if (enum_done)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for_each_node_by_type(np, "serial") {
|
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;
|
continue;
|
||||||
|
|
||||||
|
psc_ops = match->data;
|
||||||
|
|
||||||
/* Is a particular device number requested? */
|
/* Is a particular device number requested? */
|
||||||
devno = of_get_property(np, "port-number", NULL);
|
devno = of_get_property(np, "port-number", NULL);
|
||||||
mpc52xx_uart_of_assign(np, devno ? *devno : -1);
|
mpc52xx_uart_of_assign(np, devno ? *devno : -1);
|
||||||
@ -1149,6 +1430,7 @@ mpc52xx_uart_init(void)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
psc_ops = &mpc52xx_psc_ops;
|
||||||
ret = platform_driver_register(&mpc52xx_uart_platform_driver);
|
ret = platform_driver_register(&mpc52xx_uart_platform_driver);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
|
printk(KERN_ERR "%s: platform_driver_register failed (%i)\n",
|
||||||
|
@ -17,10 +17,21 @@
|
|||||||
#include <linux/tty.h>
|
#include <linux/tty.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/init.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
#if defined(CONFIG_OF)
|
#if defined(CONFIG_OF)
|
||||||
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
#include <linux/of_platform.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
|
#endif
|
||||||
|
|
||||||
#define ULITE_NAME "ttyUL"
|
#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)
|
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")) {
|
if (!request_mem_region(port->mapbase, ULITE_REGION, "uartlite")) {
|
||||||
dev_err(port->dev, "Memory region busy\n");
|
dev_err(port->dev, "Memory region busy\n");
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
@ -375,32 +389,6 @@ static void ulite_console_write(struct console *co, const char *s,
|
|||||||
spin_unlock_irqrestore(&port->lock, flags);
|
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)
|
static int __init ulite_console_setup(struct console *co, char *options)
|
||||||
{
|
{
|
||||||
struct uart_port *port;
|
struct uart_port *port;
|
||||||
@ -414,11 +402,7 @@ static int __init ulite_console_setup(struct console *co, char *options)
|
|||||||
|
|
||||||
port = &ulite_ports[co->index];
|
port = &ulite_ports[co->index];
|
||||||
|
|
||||||
/* Check if it is an OF device */
|
/* Has the device been initialized yet? */
|
||||||
if (!port->mapbase)
|
|
||||||
ulite_console_of_find_device(co->index);
|
|
||||||
|
|
||||||
/* Do we have a device now? */
|
|
||||||
if (!port->mapbase) {
|
if (!port->mapbase) {
|
||||||
pr_debug("console on ttyUL%i not present\n", co->index);
|
pr_debug("console on ttyUL%i not present\n", co->index);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@ -617,13 +601,6 @@ static int __devexit ulite_of_remove(struct of_device *op)
|
|||||||
return ulite_release(&op->dev);
|
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 = {
|
static struct of_platform_driver ulite_of_driver = {
|
||||||
.owner = THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
.name = "uartlite",
|
.name = "uartlite",
|
||||||
|
@ -459,8 +459,8 @@ static int __devexit xilinxfb_of_remove(struct of_device *op)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Match table for of_platform binding */
|
/* Match table for of_platform binding */
|
||||||
static struct of_device_id __devinit xilinxfb_of_match[] = {
|
static struct of_device_id xilinxfb_of_match[] __devinitdata = {
|
||||||
{ .compatible = "xilinx,ml300-fb", },
|
{ .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
|
||||||
{},
|
{},
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
|
MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
|
||||||
|
@ -46,7 +46,7 @@ enum powerpc_oprofile_type {
|
|||||||
PPC_OPROFILE_RS64 = 1,
|
PPC_OPROFILE_RS64 = 1,
|
||||||
PPC_OPROFILE_POWER4 = 2,
|
PPC_OPROFILE_POWER4 = 2,
|
||||||
PPC_OPROFILE_G4 = 3,
|
PPC_OPROFILE_G4 = 3,
|
||||||
PPC_OPROFILE_BOOKE = 4,
|
PPC_OPROFILE_FSL_EMB = 4,
|
||||||
PPC_OPROFILE_CELL = 5,
|
PPC_OPROFILE_CELL = 5,
|
||||||
PPC_OPROFILE_PA6T = 6,
|
PPC_OPROFILE_PA6T = 6,
|
||||||
};
|
};
|
||||||
|
@ -59,25 +59,36 @@ do { \
|
|||||||
/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
|
/* R/W of indirect DCRs make use of standard naming conventions for DCRs */
|
||||||
extern spinlock_t dcr_ind_lock;
|
extern spinlock_t dcr_ind_lock;
|
||||||
|
|
||||||
#define mfdcri(base, reg) \
|
static inline unsigned __mfdcri(int base_addr, int base_data, int reg)
|
||||||
({ \
|
{
|
||||||
unsigned long flags; \
|
unsigned long flags;
|
||||||
unsigned int val; \
|
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; \
|
|
||||||
})
|
|
||||||
|
|
||||||
#define mtdcri(base, reg, data) \
|
spin_lock_irqsave(&dcr_ind_lock, flags);
|
||||||
do { \
|
__mtdcr(base_addr, reg);
|
||||||
unsigned long flags; \
|
val = __mfdcr(base_data);
|
||||||
spin_lock_irqsave(&dcr_ind_lock, flags); \
|
spin_unlock_irqrestore(&dcr_ind_lock, flags);
|
||||||
mtdcr(DCRN_ ## base ## _CONFIG_ADDR, reg); \
|
return val;
|
||||||
mtdcr(DCRN_ ## base ## _CONFIG_DATA, data); \
|
}
|
||||||
spin_unlock_irqrestore(&dcr_ind_lock, flags); \
|
|
||||||
} while (0)
|
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 /* __ASSEMBLY__ */
|
||||||
#endif /* __KERNEL__ */
|
#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.
|
* 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 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 USE_ELF_CORE_DUMP
|
||||||
|
#define CORE_DUMP_USE_REGSET
|
||||||
#define ELF_EXEC_PAGESIZE PAGE_SIZE
|
#define ELF_EXEC_PAGESIZE PAGE_SIZE
|
||||||
|
|
||||||
/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
|
/* 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 */
|
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__ */
|
#endif /* __ASM_MPC52xx_PSC_H__ */
|
||||||
|
@ -54,7 +54,7 @@ struct op_powerpc_model {
|
|||||||
int num_counters;
|
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_rs64;
|
||||||
extern struct op_powerpc_model op_model_power4;
|
extern struct op_powerpc_model op_model_power4;
|
||||||
extern struct op_powerpc_model op_model_7450;
|
extern struct op_powerpc_model op_model_7450;
|
||||||
|
@ -55,6 +55,8 @@ struct pt_regs {
|
|||||||
|
|
||||||
#ifdef __powerpc64__
|
#ifdef __powerpc64__
|
||||||
|
|
||||||
|
#define __ARCH_WANT_COMPAT_SYS_PTRACE
|
||||||
|
|
||||||
#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */
|
#define STACK_FRAME_OVERHEAD 112 /* size of minimum stack frame */
|
||||||
|
|
||||||
/* Size of dummy stack frame allocated when calling signal handler. */
|
/* Size of dummy stack frame allocated when calling signal handler. */
|
||||||
|
@ -18,6 +18,10 @@
|
|||||||
#include <asm/reg_booke.h>
|
#include <asm/reg_booke.h>
|
||||||
#endif /* CONFIG_BOOKE || CONFIG_40x */
|
#endif /* CONFIG_BOOKE || CONFIG_40x */
|
||||||
|
|
||||||
|
#ifdef CONFIG_FSL_EMB_PERFMON
|
||||||
|
#include <asm/reg_fsl_emb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_8xx
|
#ifdef CONFIG_8xx
|
||||||
#include <asm/reg_8xx.h>
|
#include <asm/reg_8xx.h>
|
||||||
#endif /* CONFIG_8xx */
|
#endif /* CONFIG_8xx */
|
||||||
|
@ -9,68 +9,6 @@
|
|||||||
#ifndef __ASM_POWERPC_REG_BOOKE_H__
|
#ifndef __ASM_POWERPC_REG_BOOKE_H__
|
||||||
#define __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 */
|
/* Machine State Register (MSR) Fields */
|
||||||
#define MSR_UCLE (1<<26) /* User-mode cache lock enable */
|
#define MSR_UCLE (1<<26) /* User-mode cache lock enable */
|
||||||
#define MSR_SPE (1<<25) /* Enable SPE */
|
#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 task_struct;
|
||||||
struct pt_regs;
|
struct pt_regs;
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUGGER
|
#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
|
||||||
|
|
||||||
extern int (*__debugger)(struct pt_regs *regs);
|
extern int (*__debugger)(struct pt_regs *regs);
|
||||||
extern int (*__debugger_ipi)(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;
|
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);
|
struct device_node *node_vdev);
|
||||||
extern const void *vio_get_attribute(struct vio_dev *vdev, char *which,
|
extern const void *vio_get_attribute(struct vio_dev *vdev, char *which,
|
||||||
int *length);
|
int *length);
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user