diff options
157 files changed, 8708 insertions, 2893 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index caa7c3a1fef9..6bc2d87b042f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -8373,9 +8373,14 @@ M: Chris Metcalf <cmetcalf@tilera.com> | |||
8373 | W: http://www.tilera.com/scm/ | 8373 | W: http://www.tilera.com/scm/ |
8374 | S: Supported | 8374 | S: Supported |
8375 | F: arch/tile/ | 8375 | F: arch/tile/ |
8376 | F: drivers/tty/hvc/hvc_tile.c | 8376 | F: drivers/char/tile-srom.c |
8377 | F: drivers/net/ethernet/tile/ | ||
8378 | F: drivers/edac/tile_edac.c | 8377 | F: drivers/edac/tile_edac.c |
8378 | F: drivers/net/ethernet/tile/ | ||
8379 | F: drivers/rtc/rtc-tile.c | ||
8380 | F: drivers/tty/hvc/hvc_tile.c | ||
8381 | F: drivers/tty/serial/tilegx.c | ||
8382 | F: drivers/usb/host/*-tilegx.c | ||
8383 | F: include/linux/usb/tilegx.h | ||
8379 | 8384 | ||
8380 | TLAN NETWORK DRIVER | 8385 | TLAN NETWORK DRIVER |
8381 | M: Samuel Chessman <chessman@tux.org> | 8386 | M: Samuel Chessman <chessman@tux.org> |
diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 24565a7ffe6d..6e1ed55f6cfc 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig | |||
@@ -26,6 +26,7 @@ config TILE | |||
26 | select HAVE_SYSCALL_TRACEPOINTS | 26 | select HAVE_SYSCALL_TRACEPOINTS |
27 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE | 27 | select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE |
28 | select HAVE_DEBUG_STACKOVERFLOW | 28 | select HAVE_DEBUG_STACKOVERFLOW |
29 | select ARCH_WANT_FRAME_POINTERS | ||
29 | 30 | ||
30 | # FIXME: investigate whether we need/want these options. | 31 | # FIXME: investigate whether we need/want these options. |
31 | # select HAVE_IOREMAP_PROT | 32 | # select HAVE_IOREMAP_PROT |
@@ -64,6 +65,9 @@ config HUGETLB_SUPER_PAGES | |||
64 | depends on HUGETLB_PAGE && TILEGX | 65 | depends on HUGETLB_PAGE && TILEGX |
65 | def_bool y | 66 | def_bool y |
66 | 67 | ||
68 | config GENERIC_TIME_VSYSCALL | ||
69 | def_bool y | ||
70 | |||
67 | # FIXME: tilegx can implement a more efficient rwsem. | 71 | # FIXME: tilegx can implement a more efficient rwsem. |
68 | config RWSEM_GENERIC_SPINLOCK | 72 | config RWSEM_GENERIC_SPINLOCK |
69 | def_bool y | 73 | def_bool y |
@@ -112,10 +116,19 @@ config SMP | |||
112 | config HVC_TILE | 116 | config HVC_TILE |
113 | depends on TTY | 117 | depends on TTY |
114 | select HVC_DRIVER | 118 | select HVC_DRIVER |
119 | select HVC_IRQ if TILEGX | ||
115 | def_bool y | 120 | def_bool y |
116 | 121 | ||
117 | config TILEGX | 122 | config TILEGX |
118 | bool "Building with TILE-Gx (64-bit) compiler and toolchain" | 123 | bool "Building for TILE-Gx (64-bit) processor" |
124 | select HAVE_FUNCTION_TRACER | ||
125 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST | ||
126 | select HAVE_FUNCTION_GRAPH_TRACER | ||
127 | select HAVE_DYNAMIC_FTRACE | ||
128 | select HAVE_FTRACE_MCOUNT_RECORD | ||
129 | select HAVE_KPROBES | ||
130 | select HAVE_KRETPROBES | ||
131 | select HAVE_ARCH_KGDB | ||
119 | 132 | ||
120 | config TILEPRO | 133 | config TILEPRO |
121 | def_bool !TILEGX | 134 | def_bool !TILEGX |
@@ -194,7 +207,7 @@ config SYSVIPC_COMPAT | |||
194 | def_bool y | 207 | def_bool y |
195 | depends on COMPAT && SYSVIPC | 208 | depends on COMPAT && SYSVIPC |
196 | 209 | ||
197 | # We do not currently support disabling HIGHMEM on tile64 and tilepro. | 210 | # We do not currently support disabling HIGHMEM on tilepro. |
198 | config HIGHMEM | 211 | config HIGHMEM |
199 | bool # "Support for more than 512 MB of RAM" | 212 | bool # "Support for more than 512 MB of RAM" |
200 | default !TILEGX | 213 | default !TILEGX |
@@ -300,6 +313,8 @@ config PAGE_OFFSET | |||
300 | 313 | ||
301 | source "mm/Kconfig" | 314 | source "mm/Kconfig" |
302 | 315 | ||
316 | source "kernel/Kconfig.preempt" | ||
317 | |||
303 | config CMDLINE_BOOL | 318 | config CMDLINE_BOOL |
304 | bool "Built-in kernel command line" | 319 | bool "Built-in kernel command line" |
305 | default n | 320 | default n |
@@ -396,8 +411,20 @@ config NO_IOMEM | |||
396 | config NO_IOPORT | 411 | config NO_IOPORT |
397 | def_bool !PCI | 412 | def_bool !PCI |
398 | 413 | ||
414 | config TILE_PCI_IO | ||
415 | bool "PCI I/O space support" | ||
416 | default n | ||
417 | depends on PCI | ||
418 | depends on TILEGX | ||
419 | ---help--- | ||
420 | Enable PCI I/O space support on TILEGx. Since the PCI I/O space | ||
421 | is used by few modern PCIe endpoint devices, its support is disabled | ||
422 | by default to save the TRIO PIO Region resource for other purposes. | ||
423 | |||
399 | source "drivers/pci/Kconfig" | 424 | source "drivers/pci/Kconfig" |
400 | 425 | ||
426 | source "drivers/pci/pcie/Kconfig" | ||
427 | |||
401 | config TILE_USB | 428 | config TILE_USB |
402 | tristate "Tilera USB host adapter support" | 429 | tristate "Tilera USB host adapter support" |
403 | default y | 430 | default y |
diff --git a/arch/tile/Kconfig.debug b/arch/tile/Kconfig.debug index 9165ea979e85..19734d3ab1e8 100644 --- a/arch/tile/Kconfig.debug +++ b/arch/tile/Kconfig.debug | |||
@@ -14,14 +14,12 @@ config EARLY_PRINTK | |||
14 | with klogd/syslogd. You should normally N here, | 14 | with klogd/syslogd. You should normally N here, |
15 | unless you want to debug such a crash. | 15 | unless you want to debug such a crash. |
16 | 16 | ||
17 | config DEBUG_EXTRA_FLAGS | 17 | config TILE_HVGLUE_TRACE |
18 | string "Additional compiler arguments when building with '-g'" | 18 | bool "Provide wrapper functions for hypervisor ABI calls" |
19 | depends on DEBUG_INFO | 19 | default n |
20 | default "" | ||
21 | help | 20 | help |
22 | Debug info can be large, and flags like | 21 | Provide wrapper functions for the hypervisor ABI calls |
23 | `-femit-struct-debug-baseonly' can reduce the kernel file | 22 | defined in arch/tile/kernel/hvglue.S. This allows tracing |
24 | size and build time noticeably. Such flags are often | 23 | mechanisms, etc., to have visibility into those calls. |
25 | helpful if the main use of debug info is line number info. | ||
26 | 24 | ||
27 | endmenu | 25 | endmenu |
diff --git a/arch/tile/Makefile b/arch/tile/Makefile index 3d15364c6071..4dc380a519d4 100644 --- a/arch/tile/Makefile +++ b/arch/tile/Makefile | |||
@@ -30,10 +30,6 @@ endif | |||
30 | # In kernel modules, this causes load failures due to unsupported relocations. | 30 | # In kernel modules, this causes load failures due to unsupported relocations. |
31 | KBUILD_CFLAGS += -fno-asynchronous-unwind-tables | 31 | KBUILD_CFLAGS += -fno-asynchronous-unwind-tables |
32 | 32 | ||
33 | ifneq ($(CONFIG_DEBUG_EXTRA_FLAGS),"") | ||
34 | KBUILD_CFLAGS += $(CONFIG_DEBUG_EXTRA_FLAGS) | ||
35 | endif | ||
36 | |||
37 | LIBGCC_PATH := \ | 33 | LIBGCC_PATH := \ |
38 | $(shell $(CC) $(KBUILD_CFLAGS) $(KCFLAGS) -print-libgcc-file-name) | 34 | $(shell $(CC) $(KBUILD_CFLAGS) $(KCFLAGS) -print-libgcc-file-name) |
39 | 35 | ||
diff --git a/arch/tile/configs/tilegx_defconfig b/arch/tile/configs/tilegx_defconfig index 47684815e5c8..730e40d9cf62 100644 --- a/arch/tile/configs/tilegx_defconfig +++ b/arch/tile/configs/tilegx_defconfig | |||
@@ -1,16 +1,15 @@ | |||
1 | CONFIG_TILEGX=y | 1 | CONFIG_TILEGX=y |
2 | CONFIG_EXPERIMENTAL=y | ||
3 | # CONFIG_LOCALVERSION_AUTO is not set | ||
4 | CONFIG_SYSVIPC=y | 2 | CONFIG_SYSVIPC=y |
5 | CONFIG_POSIX_MQUEUE=y | 3 | CONFIG_POSIX_MQUEUE=y |
4 | CONFIG_FHANDLE=y | ||
5 | CONFIG_AUDIT=y | ||
6 | CONFIG_NO_HZ=y | ||
6 | CONFIG_BSD_PROCESS_ACCT=y | 7 | CONFIG_BSD_PROCESS_ACCT=y |
7 | CONFIG_BSD_PROCESS_ACCT_V3=y | 8 | CONFIG_BSD_PROCESS_ACCT_V3=y |
8 | CONFIG_FHANDLE=y | ||
9 | CONFIG_TASKSTATS=y | 9 | CONFIG_TASKSTATS=y |
10 | CONFIG_TASK_DELAY_ACCT=y | 10 | CONFIG_TASK_DELAY_ACCT=y |
11 | CONFIG_TASK_XACCT=y | 11 | CONFIG_TASK_XACCT=y |
12 | CONFIG_TASK_IO_ACCOUNTING=y | 12 | CONFIG_TASK_IO_ACCOUNTING=y |
13 | CONFIG_AUDIT=y | ||
14 | CONFIG_LOG_BUF_SHIFT=19 | 13 | CONFIG_LOG_BUF_SHIFT=19 |
15 | CONFIG_CGROUPS=y | 14 | CONFIG_CGROUPS=y |
16 | CONFIG_CGROUP_DEBUG=y | 15 | CONFIG_CGROUP_DEBUG=y |
@@ -18,18 +17,18 @@ CONFIG_CGROUP_DEVICE=y | |||
18 | CONFIG_CPUSETS=y | 17 | CONFIG_CPUSETS=y |
19 | CONFIG_CGROUP_CPUACCT=y | 18 | CONFIG_CGROUP_CPUACCT=y |
20 | CONFIG_RESOURCE_COUNTERS=y | 19 | CONFIG_RESOURCE_COUNTERS=y |
21 | CONFIG_CGROUP_MEMCG=y | ||
22 | CONFIG_CGROUP_MEMCG_SWAP=y | ||
23 | CONFIG_CGROUP_SCHED=y | 20 | CONFIG_CGROUP_SCHED=y |
24 | CONFIG_RT_GROUP_SCHED=y | 21 | CONFIG_RT_GROUP_SCHED=y |
25 | CONFIG_BLK_CGROUP=y | 22 | CONFIG_BLK_CGROUP=y |
26 | CONFIG_NAMESPACES=y | 23 | CONFIG_NAMESPACES=y |
27 | CONFIG_RELAY=y | 24 | CONFIG_RELAY=y |
28 | CONFIG_BLK_DEV_INITRD=y | 25 | CONFIG_BLK_DEV_INITRD=y |
26 | CONFIG_RD_XZ=y | ||
29 | CONFIG_SYSCTL_SYSCALL=y | 27 | CONFIG_SYSCTL_SYSCALL=y |
30 | CONFIG_EMBEDDED=y | 28 | CONFIG_EMBEDDED=y |
31 | # CONFIG_COMPAT_BRK is not set | 29 | # CONFIG_COMPAT_BRK is not set |
32 | CONFIG_PROFILING=y | 30 | CONFIG_PROFILING=y |
31 | CONFIG_KPROBES=y | ||
33 | CONFIG_MODULES=y | 32 | CONFIG_MODULES=y |
34 | CONFIG_MODULE_FORCE_LOAD=y | 33 | CONFIG_MODULE_FORCE_LOAD=y |
35 | CONFIG_MODULE_UNLOAD=y | 34 | CONFIG_MODULE_UNLOAD=y |
@@ -45,12 +44,12 @@ CONFIG_UNIXWARE_DISKLABEL=y | |||
45 | CONFIG_SGI_PARTITION=y | 44 | CONFIG_SGI_PARTITION=y |
46 | CONFIG_SUN_PARTITION=y | 45 | CONFIG_SUN_PARTITION=y |
47 | CONFIG_KARMA_PARTITION=y | 46 | CONFIG_KARMA_PARTITION=y |
48 | CONFIG_EFI_PARTITION=y | ||
49 | CONFIG_CFQ_GROUP_IOSCHED=y | 47 | CONFIG_CFQ_GROUP_IOSCHED=y |
50 | CONFIG_NR_CPUS=100 | 48 | CONFIG_NR_CPUS=100 |
51 | CONFIG_NO_HZ=y | ||
52 | CONFIG_HIGH_RES_TIMERS=y | ||
53 | CONFIG_HZ_100=y | 49 | CONFIG_HZ_100=y |
50 | # CONFIG_COMPACTION is not set | ||
51 | CONFIG_PREEMPT_VOLUNTARY=y | ||
52 | CONFIG_TILE_PCI_IO=y | ||
54 | CONFIG_PCI_DEBUG=y | 53 | CONFIG_PCI_DEBUG=y |
55 | # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set | 54 | # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set |
56 | CONFIG_BINFMT_MISC=y | 55 | CONFIG_BINFMT_MISC=y |
@@ -108,150 +107,9 @@ CONFIG_IPV6_MULTIPLE_TABLES=y | |||
108 | CONFIG_IPV6_MROUTE=y | 107 | CONFIG_IPV6_MROUTE=y |
109 | CONFIG_IPV6_PIMSM_V2=y | 108 | CONFIG_IPV6_PIMSM_V2=y |
110 | CONFIG_NETLABEL=y | 109 | CONFIG_NETLABEL=y |
111 | CONFIG_NETFILTER=y | ||
112 | CONFIG_NF_CONNTRACK=m | ||
113 | CONFIG_NF_CONNTRACK_SECMARK=y | ||
114 | CONFIG_NF_CONNTRACK_ZONES=y | ||
115 | CONFIG_NF_CONNTRACK_EVENTS=y | ||
116 | CONFIG_NF_CT_PROTO_DCCP=m | ||
117 | CONFIG_NF_CT_PROTO_UDPLITE=m | ||
118 | CONFIG_NF_CONNTRACK_AMANDA=m | ||
119 | CONFIG_NF_CONNTRACK_FTP=m | ||
120 | CONFIG_NF_CONNTRACK_H323=m | ||
121 | CONFIG_NF_CONNTRACK_IRC=m | ||
122 | CONFIG_NF_CONNTRACK_NETBIOS_NS=m | ||
123 | CONFIG_NF_CONNTRACK_PPTP=m | ||
124 | CONFIG_NF_CONNTRACK_SANE=m | ||
125 | CONFIG_NF_CONNTRACK_SIP=m | ||
126 | CONFIG_NF_CONNTRACK_TFTP=m | ||
127 | CONFIG_NETFILTER_TPROXY=m | ||
128 | CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m | ||
129 | CONFIG_NETFILTER_XT_TARGET_CONNMARK=m | ||
130 | CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m | ||
131 | CONFIG_NETFILTER_XT_TARGET_CT=m | ||
132 | CONFIG_NETFILTER_XT_TARGET_DSCP=m | ||
133 | CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m | ||
134 | CONFIG_NETFILTER_XT_TARGET_MARK=m | ||
135 | CONFIG_NETFILTER_XT_TARGET_NFLOG=m | ||
136 | CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m | ||
137 | CONFIG_NETFILTER_XT_TARGET_TEE=m | ||
138 | CONFIG_NETFILTER_XT_TARGET_TPROXY=m | ||
139 | CONFIG_NETFILTER_XT_TARGET_TRACE=m | ||
140 | CONFIG_NETFILTER_XT_TARGET_SECMARK=m | ||
141 | CONFIG_NETFILTER_XT_TARGET_TCPMSS=m | ||
142 | CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m | ||
143 | CONFIG_NETFILTER_XT_MATCH_CLUSTER=m | ||
144 | CONFIG_NETFILTER_XT_MATCH_COMMENT=m | ||
145 | CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m | ||
146 | CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m | ||
147 | CONFIG_NETFILTER_XT_MATCH_CONNMARK=m | ||
148 | CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m | ||
149 | CONFIG_NETFILTER_XT_MATCH_DCCP=m | ||
150 | CONFIG_NETFILTER_XT_MATCH_DSCP=m | ||
151 | CONFIG_NETFILTER_XT_MATCH_ESP=m | ||
152 | CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m | ||
153 | CONFIG_NETFILTER_XT_MATCH_HELPER=m | ||
154 | CONFIG_NETFILTER_XT_MATCH_IPRANGE=m | ||
155 | CONFIG_NETFILTER_XT_MATCH_IPVS=m | ||
156 | CONFIG_NETFILTER_XT_MATCH_LENGTH=m | ||
157 | CONFIG_NETFILTER_XT_MATCH_LIMIT=m | ||
158 | CONFIG_NETFILTER_XT_MATCH_MAC=m | ||
159 | CONFIG_NETFILTER_XT_MATCH_MARK=m | ||
160 | CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m | ||
161 | CONFIG_NETFILTER_XT_MATCH_OSF=m | ||
162 | CONFIG_NETFILTER_XT_MATCH_OWNER=m | ||
163 | CONFIG_NETFILTER_XT_MATCH_POLICY=m | ||
164 | CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m | ||
165 | CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m | ||
166 | CONFIG_NETFILTER_XT_MATCH_QUOTA=m | ||
167 | CONFIG_NETFILTER_XT_MATCH_RATEEST=m | ||
168 | CONFIG_NETFILTER_XT_MATCH_REALM=m | ||
169 | CONFIG_NETFILTER_XT_MATCH_RECENT=m | ||
170 | CONFIG_NETFILTER_XT_MATCH_SOCKET=m | ||
171 | CONFIG_NETFILTER_XT_MATCH_STATE=m | ||
172 | CONFIG_NETFILTER_XT_MATCH_STATISTIC=m | ||
173 | CONFIG_NETFILTER_XT_MATCH_STRING=m | ||
174 | CONFIG_NETFILTER_XT_MATCH_TCPMSS=m | ||
175 | CONFIG_NETFILTER_XT_MATCH_TIME=m | ||
176 | CONFIG_NETFILTER_XT_MATCH_U32=m | ||
177 | CONFIG_IP_VS=m | ||
178 | CONFIG_IP_VS_IPV6=y | ||
179 | CONFIG_IP_VS_PROTO_TCP=y | ||
180 | CONFIG_IP_VS_PROTO_UDP=y | ||
181 | CONFIG_IP_VS_PROTO_ESP=y | ||
182 | CONFIG_IP_VS_PROTO_AH=y | ||
183 | CONFIG_IP_VS_PROTO_SCTP=y | ||
184 | CONFIG_IP_VS_RR=m | ||
185 | CONFIG_IP_VS_WRR=m | ||
186 | CONFIG_IP_VS_LC=m | ||
187 | CONFIG_IP_VS_WLC=m | ||
188 | CONFIG_IP_VS_LBLC=m | ||
189 | CONFIG_IP_VS_LBLCR=m | ||
190 | CONFIG_IP_VS_SED=m | ||
191 | CONFIG_IP_VS_NQ=m | ||
192 | CONFIG_NF_CONNTRACK_IPV4=m | ||
193 | # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set | ||
194 | CONFIG_IP_NF_QUEUE=m | ||
195 | CONFIG_IP_NF_IPTABLES=y | ||
196 | CONFIG_IP_NF_MATCH_AH=m | ||
197 | CONFIG_IP_NF_MATCH_ECN=m | ||
198 | CONFIG_IP_NF_MATCH_TTL=m | ||
199 | CONFIG_IP_NF_FILTER=y | ||
200 | CONFIG_IP_NF_TARGET_REJECT=y | ||
201 | CONFIG_IP_NF_TARGET_LOG=m | ||
202 | CONFIG_IP_NF_TARGET_ULOG=m | ||
203 | CONFIG_IP_NF_MANGLE=m | ||
204 | CONFIG_IP_NF_TARGET_ECN=m | ||
205 | CONFIG_IP_NF_TARGET_TTL=m | ||
206 | CONFIG_IP_NF_RAW=m | ||
207 | CONFIG_IP_NF_SECURITY=m | ||
208 | CONFIG_IP_NF_ARPTABLES=m | ||
209 | CONFIG_IP_NF_ARPFILTER=m | ||
210 | CONFIG_IP_NF_ARP_MANGLE=m | ||
211 | CONFIG_NF_CONNTRACK_IPV6=m | ||
212 | CONFIG_IP6_NF_QUEUE=m | ||
213 | CONFIG_IP6_NF_IPTABLES=m | ||
214 | CONFIG_IP6_NF_MATCH_AH=m | ||
215 | CONFIG_IP6_NF_MATCH_EUI64=m | ||
216 | CONFIG_IP6_NF_MATCH_FRAG=m | ||
217 | CONFIG_IP6_NF_MATCH_OPTS=m | ||
218 | CONFIG_IP6_NF_MATCH_HL=m | ||
219 | CONFIG_IP6_NF_MATCH_IPV6HEADER=m | ||
220 | CONFIG_IP6_NF_MATCH_MH=m | ||
221 | CONFIG_IP6_NF_MATCH_RT=m | ||
222 | CONFIG_IP6_NF_TARGET_HL=m | ||
223 | CONFIG_IP6_NF_TARGET_LOG=m | ||
224 | CONFIG_IP6_NF_FILTER=m | ||
225 | CONFIG_IP6_NF_TARGET_REJECT=m | ||
226 | CONFIG_IP6_NF_MANGLE=m | ||
227 | CONFIG_IP6_NF_RAW=m | ||
228 | CONFIG_IP6_NF_SECURITY=m | ||
229 | CONFIG_BRIDGE_NF_EBTABLES=m | ||
230 | CONFIG_BRIDGE_EBT_BROUTE=m | ||
231 | CONFIG_BRIDGE_EBT_T_FILTER=m | ||
232 | CONFIG_BRIDGE_EBT_T_NAT=m | ||
233 | CONFIG_BRIDGE_EBT_802_3=m | ||
234 | CONFIG_BRIDGE_EBT_AMONG=m | ||
235 | CONFIG_BRIDGE_EBT_ARP=m | ||
236 | CONFIG_BRIDGE_EBT_IP=m | ||
237 | CONFIG_BRIDGE_EBT_IP6=m | ||
238 | CONFIG_BRIDGE_EBT_LIMIT=m | ||
239 | CONFIG_BRIDGE_EBT_MARK=m | ||
240 | CONFIG_BRIDGE_EBT_PKTTYPE=m | ||
241 | CONFIG_BRIDGE_EBT_STP=m | ||
242 | CONFIG_BRIDGE_EBT_VLAN=m | ||
243 | CONFIG_BRIDGE_EBT_ARPREPLY=m | ||
244 | CONFIG_BRIDGE_EBT_DNAT=m | ||
245 | CONFIG_BRIDGE_EBT_MARK_T=m | ||
246 | CONFIG_BRIDGE_EBT_REDIRECT=m | ||
247 | CONFIG_BRIDGE_EBT_SNAT=m | ||
248 | CONFIG_BRIDGE_EBT_LOG=m | ||
249 | CONFIG_BRIDGE_EBT_ULOG=m | ||
250 | CONFIG_BRIDGE_EBT_NFLOG=m | ||
251 | CONFIG_RDS=m | 110 | CONFIG_RDS=m |
252 | CONFIG_RDS_TCP=m | 111 | CONFIG_RDS_TCP=m |
253 | CONFIG_BRIDGE=m | 112 | CONFIG_BRIDGE=m |
254 | CONFIG_NET_DSA=y | ||
255 | CONFIG_VLAN_8021Q=m | 113 | CONFIG_VLAN_8021Q=m |
256 | CONFIG_VLAN_8021Q_GVRP=y | 114 | CONFIG_VLAN_8021Q_GVRP=y |
257 | CONFIG_PHONET=m | 115 | CONFIG_PHONET=m |
@@ -292,13 +150,13 @@ CONFIG_NET_ACT_POLICE=m | |||
292 | CONFIG_NET_ACT_GACT=m | 150 | CONFIG_NET_ACT_GACT=m |
293 | CONFIG_GACT_PROB=y | 151 | CONFIG_GACT_PROB=y |
294 | CONFIG_NET_ACT_MIRRED=m | 152 | CONFIG_NET_ACT_MIRRED=m |
295 | CONFIG_NET_ACT_IPT=m | ||
296 | CONFIG_NET_ACT_NAT=m | 153 | CONFIG_NET_ACT_NAT=m |
297 | CONFIG_NET_ACT_PEDIT=m | 154 | CONFIG_NET_ACT_PEDIT=m |
298 | CONFIG_NET_ACT_SIMP=m | 155 | CONFIG_NET_ACT_SIMP=m |
299 | CONFIG_NET_ACT_SKBEDIT=m | 156 | CONFIG_NET_ACT_SKBEDIT=m |
300 | CONFIG_NET_CLS_IND=y | 157 | CONFIG_NET_CLS_IND=y |
301 | CONFIG_DCB=y | 158 | CONFIG_DCB=y |
159 | CONFIG_DNS_RESOLVER=y | ||
302 | # CONFIG_WIRELESS is not set | 160 | # CONFIG_WIRELESS is not set |
303 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | 161 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" |
304 | CONFIG_DEVTMPFS=y | 162 | CONFIG_DEVTMPFS=y |
@@ -317,10 +175,12 @@ CONFIG_BLK_DEV_SD=y | |||
317 | CONFIG_SCSI_CONSTANTS=y | 175 | CONFIG_SCSI_CONSTANTS=y |
318 | CONFIG_SCSI_LOGGING=y | 176 | CONFIG_SCSI_LOGGING=y |
319 | CONFIG_SCSI_SAS_ATA=y | 177 | CONFIG_SCSI_SAS_ATA=y |
178 | CONFIG_ISCSI_TCP=m | ||
320 | CONFIG_SCSI_MVSAS=y | 179 | CONFIG_SCSI_MVSAS=y |
321 | # CONFIG_SCSI_MVSAS_DEBUG is not set | 180 | # CONFIG_SCSI_MVSAS_DEBUG is not set |
322 | CONFIG_SCSI_MVSAS_TASKLET=y | 181 | CONFIG_SCSI_MVSAS_TASKLET=y |
323 | CONFIG_ATA=y | 182 | CONFIG_ATA=y |
183 | CONFIG_SATA_AHCI=y | ||
324 | CONFIG_SATA_SIL24=y | 184 | CONFIG_SATA_SIL24=y |
325 | # CONFIG_ATA_SFF is not set | 185 | # CONFIG_ATA_SFF is not set |
326 | CONFIG_MD=y | 186 | CONFIG_MD=y |
@@ -343,6 +203,12 @@ CONFIG_DM_MULTIPATH_QL=m | |||
343 | CONFIG_DM_MULTIPATH_ST=m | 203 | CONFIG_DM_MULTIPATH_ST=m |
344 | CONFIG_DM_DELAY=m | 204 | CONFIG_DM_DELAY=m |
345 | CONFIG_DM_UEVENT=y | 205 | CONFIG_DM_UEVENT=y |
206 | CONFIG_TARGET_CORE=m | ||
207 | CONFIG_TCM_IBLOCK=m | ||
208 | CONFIG_TCM_FILEIO=m | ||
209 | CONFIG_TCM_PSCSI=m | ||
210 | CONFIG_LOOPBACK_TARGET=m | ||
211 | CONFIG_ISCSI_TARGET=m | ||
346 | CONFIG_FUSION=y | 212 | CONFIG_FUSION=y |
347 | CONFIG_FUSION_SAS=y | 213 | CONFIG_FUSION_SAS=y |
348 | CONFIG_NETDEVICES=y | 214 | CONFIG_NETDEVICES=y |
@@ -359,42 +225,8 @@ CONFIG_VETH=m | |||
359 | CONFIG_NET_DSA_MV88E6060=y | 225 | CONFIG_NET_DSA_MV88E6060=y |
360 | CONFIG_NET_DSA_MV88E6131=y | 226 | CONFIG_NET_DSA_MV88E6131=y |
361 | CONFIG_NET_DSA_MV88E6123_61_65=y | 227 | CONFIG_NET_DSA_MV88E6123_61_65=y |
362 | # CONFIG_NET_VENDOR_3COM is not set | 228 | CONFIG_SKY2=y |
363 | # CONFIG_NET_VENDOR_ADAPTEC is not set | 229 | CONFIG_PTP_1588_CLOCK_TILEGX=y |
364 | # CONFIG_NET_VENDOR_ALTEON is not set | ||
365 | # CONFIG_NET_VENDOR_AMD is not set | ||
366 | # CONFIG_NET_VENDOR_ATHEROS is not set | ||
367 | # CONFIG_NET_VENDOR_BROADCOM is not set | ||
368 | # CONFIG_NET_VENDOR_BROCADE is not set | ||
369 | # CONFIG_NET_VENDOR_CHELSIO is not set | ||
370 | # CONFIG_NET_VENDOR_CISCO is not set | ||
371 | # CONFIG_NET_VENDOR_DEC is not set | ||
372 | # CONFIG_NET_VENDOR_DLINK is not set | ||
373 | # CONFIG_NET_VENDOR_EMULEX is not set | ||
374 | # CONFIG_NET_VENDOR_EXAR is not set | ||
375 | # CONFIG_NET_VENDOR_HP is not set | ||
376 | # CONFIG_NET_VENDOR_INTEL is not set | ||
377 | # CONFIG_NET_VENDOR_MARVELL is not set | ||
378 | # CONFIG_NET_VENDOR_MELLANOX is not set | ||
379 | # CONFIG_NET_VENDOR_MICREL is not set | ||
380 | # CONFIG_NET_VENDOR_MYRI is not set | ||
381 | # CONFIG_NET_VENDOR_NATSEMI is not set | ||
382 | # CONFIG_NET_VENDOR_NVIDIA is not set | ||
383 | # CONFIG_NET_VENDOR_OKI is not set | ||
384 | # CONFIG_NET_PACKET_ENGINE is not set | ||
385 | # CONFIG_NET_VENDOR_QLOGIC is not set | ||
386 | # CONFIG_NET_VENDOR_REALTEK is not set | ||
387 | # CONFIG_NET_VENDOR_RDC is not set | ||
388 | # CONFIG_NET_VENDOR_SEEQ is not set | ||
389 | # CONFIG_NET_VENDOR_SILAN is not set | ||
390 | # CONFIG_NET_VENDOR_SIS is not set | ||
391 | # CONFIG_NET_VENDOR_SMSC is not set | ||
392 | # CONFIG_NET_VENDOR_STMICRO is not set | ||
393 | # CONFIG_NET_VENDOR_SUN is not set | ||
394 | # CONFIG_NET_VENDOR_TEHUTI is not set | ||
395 | # CONFIG_NET_VENDOR_TI is not set | ||
396 | # CONFIG_TILE_NET is not set | ||
397 | # CONFIG_NET_VENDOR_VIA is not set | ||
398 | # CONFIG_WLAN is not set | 230 | # CONFIG_WLAN is not set |
399 | # CONFIG_INPUT_MOUSEDEV is not set | 231 | # CONFIG_INPUT_MOUSEDEV is not set |
400 | # CONFIG_INPUT_KEYBOARD is not set | 232 | # CONFIG_INPUT_KEYBOARD is not set |
@@ -402,6 +234,7 @@ CONFIG_NET_DSA_MV88E6123_61_65=y | |||
402 | # CONFIG_SERIO is not set | 234 | # CONFIG_SERIO is not set |
403 | # CONFIG_VT is not set | 235 | # CONFIG_VT is not set |
404 | # CONFIG_LEGACY_PTYS is not set | 236 | # CONFIG_LEGACY_PTYS is not set |
237 | CONFIG_SERIAL_TILEGX=y | ||
405 | CONFIG_HW_RANDOM=y | 238 | CONFIG_HW_RANDOM=y |
406 | CONFIG_HW_RANDOM_TIMERIOMEM=m | 239 | CONFIG_HW_RANDOM_TIMERIOMEM=m |
407 | CONFIG_I2C=y | 240 | CONFIG_I2C=y |
@@ -410,13 +243,16 @@ CONFIG_I2C_CHARDEV=y | |||
410 | CONFIG_WATCHDOG=y | 243 | CONFIG_WATCHDOG=y |
411 | CONFIG_WATCHDOG_NOWAYOUT=y | 244 | CONFIG_WATCHDOG_NOWAYOUT=y |
412 | # CONFIG_VGA_ARB is not set | 245 | # CONFIG_VGA_ARB is not set |
413 | # CONFIG_HID_SUPPORT is not set | 246 | CONFIG_DRM=m |
247 | CONFIG_DRM_TDFX=m | ||
248 | CONFIG_DRM_R128=m | ||
249 | CONFIG_DRM_MGA=m | ||
250 | CONFIG_DRM_VIA=m | ||
251 | CONFIG_DRM_SAVAGE=m | ||
414 | CONFIG_USB=y | 252 | CONFIG_USB=y |
415 | # CONFIG_USB_DEVICE_CLASS is not set | ||
416 | CONFIG_USB_EHCI_HCD=y | 253 | CONFIG_USB_EHCI_HCD=y |
417 | CONFIG_USB_OHCI_HCD=y | 254 | CONFIG_USB_OHCI_HCD=y |
418 | CONFIG_USB_STORAGE=y | 255 | CONFIG_USB_STORAGE=y |
419 | CONFIG_USB_LIBUSUAL=y | ||
420 | CONFIG_EDAC=y | 256 | CONFIG_EDAC=y |
421 | CONFIG_EDAC_MM_EDAC=y | 257 | CONFIG_EDAC_MM_EDAC=y |
422 | CONFIG_RTC_CLASS=y | 258 | CONFIG_RTC_CLASS=y |
@@ -464,9 +300,8 @@ CONFIG_ECRYPT_FS=m | |||
464 | CONFIG_CRAMFS=m | 300 | CONFIG_CRAMFS=m |
465 | CONFIG_SQUASHFS=m | 301 | CONFIG_SQUASHFS=m |
466 | CONFIG_NFS_FS=m | 302 | CONFIG_NFS_FS=m |
467 | CONFIG_NFS_V3=y | ||
468 | CONFIG_NFS_V3_ACL=y | 303 | CONFIG_NFS_V3_ACL=y |
469 | CONFIG_NFS_V4=y | 304 | CONFIG_NFS_V4=m |
470 | CONFIG_NFS_V4_1=y | 305 | CONFIG_NFS_V4_1=y |
471 | CONFIG_NFS_FSCACHE=y | 306 | CONFIG_NFS_FSCACHE=y |
472 | CONFIG_NFSD=m | 307 | CONFIG_NFSD=m |
@@ -519,25 +354,28 @@ CONFIG_NLS_ISO8859_15=m | |||
519 | CONFIG_NLS_KOI8_R=m | 354 | CONFIG_NLS_KOI8_R=m |
520 | CONFIG_NLS_KOI8_U=m | 355 | CONFIG_NLS_KOI8_U=m |
521 | CONFIG_NLS_UTF8=m | 356 | CONFIG_NLS_UTF8=m |
357 | CONFIG_DLM=m | ||
522 | CONFIG_DLM_DEBUG=y | 358 | CONFIG_DLM_DEBUG=y |
359 | CONFIG_DYNAMIC_DEBUG=y | ||
360 | CONFIG_DEBUG_INFO=y | ||
361 | CONFIG_DEBUG_INFO_REDUCED=y | ||
523 | # CONFIG_ENABLE_WARN_DEPRECATED is not set | 362 | # CONFIG_ENABLE_WARN_DEPRECATED is not set |
524 | CONFIG_MAGIC_SYSRQ=y | ||
525 | CONFIG_STRIP_ASM_SYMS=y | 363 | CONFIG_STRIP_ASM_SYMS=y |
526 | CONFIG_DEBUG_FS=y | 364 | CONFIG_DEBUG_FS=y |
527 | CONFIG_HEADERS_CHECK=y | 365 | CONFIG_HEADERS_CHECK=y |
366 | # CONFIG_FRAME_POINTER is not set | ||
367 | CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y | ||
368 | CONFIG_DEBUG_VM=y | ||
369 | CONFIG_DEBUG_MEMORY_INIT=y | ||
370 | CONFIG_DEBUG_STACKOVERFLOW=y | ||
528 | CONFIG_LOCKUP_DETECTOR=y | 371 | CONFIG_LOCKUP_DETECTOR=y |
529 | CONFIG_SCHEDSTATS=y | 372 | CONFIG_SCHEDSTATS=y |
530 | CONFIG_TIMER_STATS=y | 373 | CONFIG_TIMER_STATS=y |
531 | CONFIG_DEBUG_INFO=y | ||
532 | CONFIG_DEBUG_INFO_REDUCED=y | ||
533 | CONFIG_DEBUG_VM=y | ||
534 | CONFIG_DEBUG_MEMORY_INIT=y | ||
535 | CONFIG_DEBUG_LIST=y | 374 | CONFIG_DEBUG_LIST=y |
536 | CONFIG_DEBUG_CREDENTIALS=y | 375 | CONFIG_DEBUG_CREDENTIALS=y |
537 | CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y | 376 | CONFIG_RCU_CPU_STALL_TIMEOUT=60 |
538 | CONFIG_DYNAMIC_DEBUG=y | ||
539 | CONFIG_ASYNC_RAID6_TEST=m | 377 | CONFIG_ASYNC_RAID6_TEST=m |
540 | CONFIG_DEBUG_STACKOVERFLOW=y | 378 | CONFIG_KGDB=y |
541 | CONFIG_KEYS_DEBUG_PROC_KEYS=y | 379 | CONFIG_KEYS_DEBUG_PROC_KEYS=y |
542 | CONFIG_SECURITY=y | 380 | CONFIG_SECURITY=y |
543 | CONFIG_SECURITYFS=y | 381 | CONFIG_SECURITYFS=y |
@@ -546,7 +384,6 @@ CONFIG_SECURITY_NETWORK_XFRM=y | |||
546 | CONFIG_SECURITY_SELINUX=y | 384 | CONFIG_SECURITY_SELINUX=y |
547 | CONFIG_SECURITY_SELINUX_BOOTPARAM=y | 385 | CONFIG_SECURITY_SELINUX_BOOTPARAM=y |
548 | CONFIG_SECURITY_SELINUX_DISABLE=y | 386 | CONFIG_SECURITY_SELINUX_DISABLE=y |
549 | CONFIG_CRYPTO_NULL=m | ||
550 | CONFIG_CRYPTO_PCRYPT=m | 387 | CONFIG_CRYPTO_PCRYPT=m |
551 | CONFIG_CRYPTO_CRYPTD=m | 388 | CONFIG_CRYPTO_CRYPTD=m |
552 | CONFIG_CRYPTO_TEST=m | 389 | CONFIG_CRYPTO_TEST=m |
@@ -559,14 +396,12 @@ CONFIG_CRYPTO_XTS=m | |||
559 | CONFIG_CRYPTO_HMAC=y | 396 | CONFIG_CRYPTO_HMAC=y |
560 | CONFIG_CRYPTO_XCBC=m | 397 | CONFIG_CRYPTO_XCBC=m |
561 | CONFIG_CRYPTO_VMAC=m | 398 | CONFIG_CRYPTO_VMAC=m |
562 | CONFIG_CRYPTO_CRC32C=y | ||
563 | CONFIG_CRYPTO_MICHAEL_MIC=m | 399 | CONFIG_CRYPTO_MICHAEL_MIC=m |
564 | CONFIG_CRYPTO_RMD128=m | 400 | CONFIG_CRYPTO_RMD128=m |
565 | CONFIG_CRYPTO_RMD160=m | 401 | CONFIG_CRYPTO_RMD160=m |
566 | CONFIG_CRYPTO_RMD256=m | 402 | CONFIG_CRYPTO_RMD256=m |
567 | CONFIG_CRYPTO_RMD320=m | 403 | CONFIG_CRYPTO_RMD320=m |
568 | CONFIG_CRYPTO_SHA1=y | 404 | CONFIG_CRYPTO_SHA1=y |
569 | CONFIG_CRYPTO_SHA256=m | ||
570 | CONFIG_CRYPTO_SHA512=m | 405 | CONFIG_CRYPTO_SHA512=m |
571 | CONFIG_CRYPTO_TGR192=m | 406 | CONFIG_CRYPTO_TGR192=m |
572 | CONFIG_CRYPTO_WP512=m | 407 | CONFIG_CRYPTO_WP512=m |
diff --git a/arch/tile/configs/tilepro_defconfig b/arch/tile/configs/tilepro_defconfig index dd2b8f0c631f..80fc32ed0491 100644 --- a/arch/tile/configs/tilepro_defconfig +++ b/arch/tile/configs/tilepro_defconfig | |||
@@ -1,15 +1,14 @@ | |||
1 | CONFIG_EXPERIMENTAL=y | ||
2 | # CONFIG_LOCALVERSION_AUTO is not set | ||
3 | CONFIG_SYSVIPC=y | 1 | CONFIG_SYSVIPC=y |
4 | CONFIG_POSIX_MQUEUE=y | 2 | CONFIG_POSIX_MQUEUE=y |
3 | CONFIG_AUDIT=y | ||
4 | CONFIG_NO_HZ=y | ||
5 | CONFIG_HIGH_RES_TIMERS=y | ||
5 | CONFIG_BSD_PROCESS_ACCT=y | 6 | CONFIG_BSD_PROCESS_ACCT=y |
6 | CONFIG_BSD_PROCESS_ACCT_V3=y | 7 | CONFIG_BSD_PROCESS_ACCT_V3=y |
7 | CONFIG_FHANDLE=y | ||
8 | CONFIG_TASKSTATS=y | 8 | CONFIG_TASKSTATS=y |
9 | CONFIG_TASK_DELAY_ACCT=y | 9 | CONFIG_TASK_DELAY_ACCT=y |
10 | CONFIG_TASK_XACCT=y | 10 | CONFIG_TASK_XACCT=y |
11 | CONFIG_TASK_IO_ACCOUNTING=y | 11 | CONFIG_TASK_IO_ACCOUNTING=y |
12 | CONFIG_AUDIT=y | ||
13 | CONFIG_LOG_BUF_SHIFT=19 | 12 | CONFIG_LOG_BUF_SHIFT=19 |
14 | CONFIG_CGROUPS=y | 13 | CONFIG_CGROUPS=y |
15 | CONFIG_CGROUP_DEBUG=y | 14 | CONFIG_CGROUP_DEBUG=y |
@@ -17,14 +16,13 @@ CONFIG_CGROUP_DEVICE=y | |||
17 | CONFIG_CPUSETS=y | 16 | CONFIG_CPUSETS=y |
18 | CONFIG_CGROUP_CPUACCT=y | 17 | CONFIG_CGROUP_CPUACCT=y |
19 | CONFIG_RESOURCE_COUNTERS=y | 18 | CONFIG_RESOURCE_COUNTERS=y |
20 | CONFIG_CGROUP_MEMCG=y | ||
21 | CONFIG_CGROUP_MEMCG_SWAP=y | ||
22 | CONFIG_CGROUP_SCHED=y | 19 | CONFIG_CGROUP_SCHED=y |
23 | CONFIG_RT_GROUP_SCHED=y | 20 | CONFIG_RT_GROUP_SCHED=y |
24 | CONFIG_BLK_CGROUP=y | 21 | CONFIG_BLK_CGROUP=y |
25 | CONFIG_NAMESPACES=y | 22 | CONFIG_NAMESPACES=y |
26 | CONFIG_RELAY=y | 23 | CONFIG_RELAY=y |
27 | CONFIG_BLK_DEV_INITRD=y | 24 | CONFIG_BLK_DEV_INITRD=y |
25 | CONFIG_RD_XZ=y | ||
28 | CONFIG_SYSCTL_SYSCALL=y | 26 | CONFIG_SYSCTL_SYSCALL=y |
29 | CONFIG_EMBEDDED=y | 27 | CONFIG_EMBEDDED=y |
30 | # CONFIG_COMPAT_BRK is not set | 28 | # CONFIG_COMPAT_BRK is not set |
@@ -44,11 +42,10 @@ CONFIG_UNIXWARE_DISKLABEL=y | |||
44 | CONFIG_SGI_PARTITION=y | 42 | CONFIG_SGI_PARTITION=y |
45 | CONFIG_SUN_PARTITION=y | 43 | CONFIG_SUN_PARTITION=y |
46 | CONFIG_KARMA_PARTITION=y | 44 | CONFIG_KARMA_PARTITION=y |
47 | CONFIG_EFI_PARTITION=y | ||
48 | CONFIG_CFQ_GROUP_IOSCHED=y | 45 | CONFIG_CFQ_GROUP_IOSCHED=y |
49 | CONFIG_NO_HZ=y | ||
50 | CONFIG_HIGH_RES_TIMERS=y | ||
51 | CONFIG_HZ_100=y | 46 | CONFIG_HZ_100=y |
47 | # CONFIG_COMPACTION is not set | ||
48 | CONFIG_PREEMPT_VOLUNTARY=y | ||
52 | CONFIG_PCI_DEBUG=y | 49 | CONFIG_PCI_DEBUG=y |
53 | # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set | 50 | # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set |
54 | CONFIG_BINFMT_MISC=y | 51 | CONFIG_BINFMT_MISC=y |
@@ -122,16 +119,15 @@ CONFIG_NF_CONNTRACK_PPTP=m | |||
122 | CONFIG_NF_CONNTRACK_SANE=m | 119 | CONFIG_NF_CONNTRACK_SANE=m |
123 | CONFIG_NF_CONNTRACK_SIP=m | 120 | CONFIG_NF_CONNTRACK_SIP=m |
124 | CONFIG_NF_CONNTRACK_TFTP=m | 121 | CONFIG_NF_CONNTRACK_TFTP=m |
125 | CONFIG_NETFILTER_TPROXY=m | ||
126 | CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m | 122 | CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m |
127 | CONFIG_NETFILTER_XT_TARGET_CONNMARK=m | 123 | CONFIG_NETFILTER_XT_TARGET_CONNMARK=m |
128 | CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m | 124 | CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m |
129 | CONFIG_NETFILTER_XT_TARGET_CT=m | ||
130 | CONFIG_NETFILTER_XT_TARGET_DSCP=m | 125 | CONFIG_NETFILTER_XT_TARGET_DSCP=m |
131 | CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m | 126 | CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m |
132 | CONFIG_NETFILTER_XT_TARGET_MARK=m | 127 | CONFIG_NETFILTER_XT_TARGET_MARK=m |
133 | CONFIG_NETFILTER_XT_TARGET_NFLOG=m | 128 | CONFIG_NETFILTER_XT_TARGET_NFLOG=m |
134 | CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m | 129 | CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m |
130 | CONFIG_NETFILTER_XT_TARGET_NOTRACK=m | ||
135 | CONFIG_NETFILTER_XT_TARGET_TEE=m | 131 | CONFIG_NETFILTER_XT_TARGET_TEE=m |
136 | CONFIG_NETFILTER_XT_TARGET_TPROXY=m | 132 | CONFIG_NETFILTER_XT_TARGET_TPROXY=m |
137 | CONFIG_NETFILTER_XT_TARGET_TRACE=m | 133 | CONFIG_NETFILTER_XT_TARGET_TRACE=m |
@@ -189,14 +185,12 @@ CONFIG_IP_VS_SED=m | |||
189 | CONFIG_IP_VS_NQ=m | 185 | CONFIG_IP_VS_NQ=m |
190 | CONFIG_NF_CONNTRACK_IPV4=m | 186 | CONFIG_NF_CONNTRACK_IPV4=m |
191 | # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set | 187 | # CONFIG_NF_CONNTRACK_PROC_COMPAT is not set |
192 | CONFIG_IP_NF_QUEUE=m | ||
193 | CONFIG_IP_NF_IPTABLES=y | 188 | CONFIG_IP_NF_IPTABLES=y |
194 | CONFIG_IP_NF_MATCH_AH=m | 189 | CONFIG_IP_NF_MATCH_AH=m |
195 | CONFIG_IP_NF_MATCH_ECN=m | 190 | CONFIG_IP_NF_MATCH_ECN=m |
196 | CONFIG_IP_NF_MATCH_TTL=m | 191 | CONFIG_IP_NF_MATCH_TTL=m |
197 | CONFIG_IP_NF_FILTER=y | 192 | CONFIG_IP_NF_FILTER=y |
198 | CONFIG_IP_NF_TARGET_REJECT=y | 193 | CONFIG_IP_NF_TARGET_REJECT=y |
199 | CONFIG_IP_NF_TARGET_LOG=m | ||
200 | CONFIG_IP_NF_TARGET_ULOG=m | 194 | CONFIG_IP_NF_TARGET_ULOG=m |
201 | CONFIG_IP_NF_MANGLE=m | 195 | CONFIG_IP_NF_MANGLE=m |
202 | CONFIG_IP_NF_TARGET_ECN=m | 196 | CONFIG_IP_NF_TARGET_ECN=m |
@@ -207,8 +201,6 @@ CONFIG_IP_NF_ARPTABLES=m | |||
207 | CONFIG_IP_NF_ARPFILTER=m | 201 | CONFIG_IP_NF_ARPFILTER=m |
208 | CONFIG_IP_NF_ARP_MANGLE=m | 202 | CONFIG_IP_NF_ARP_MANGLE=m |
209 | CONFIG_NF_CONNTRACK_IPV6=m | 203 | CONFIG_NF_CONNTRACK_IPV6=m |
210 | CONFIG_IP6_NF_QUEUE=m | ||
211 | CONFIG_IP6_NF_IPTABLES=m | ||
212 | CONFIG_IP6_NF_MATCH_AH=m | 204 | CONFIG_IP6_NF_MATCH_AH=m |
213 | CONFIG_IP6_NF_MATCH_EUI64=m | 205 | CONFIG_IP6_NF_MATCH_EUI64=m |
214 | CONFIG_IP6_NF_MATCH_FRAG=m | 206 | CONFIG_IP6_NF_MATCH_FRAG=m |
@@ -218,7 +210,6 @@ CONFIG_IP6_NF_MATCH_IPV6HEADER=m | |||
218 | CONFIG_IP6_NF_MATCH_MH=m | 210 | CONFIG_IP6_NF_MATCH_MH=m |
219 | CONFIG_IP6_NF_MATCH_RT=m | 211 | CONFIG_IP6_NF_MATCH_RT=m |
220 | CONFIG_IP6_NF_TARGET_HL=m | 212 | CONFIG_IP6_NF_TARGET_HL=m |
221 | CONFIG_IP6_NF_TARGET_LOG=m | ||
222 | CONFIG_IP6_NF_FILTER=m | 213 | CONFIG_IP6_NF_FILTER=m |
223 | CONFIG_IP6_NF_TARGET_REJECT=m | 214 | CONFIG_IP6_NF_TARGET_REJECT=m |
224 | CONFIG_IP6_NF_MANGLE=m | 215 | CONFIG_IP6_NF_MANGLE=m |
@@ -249,7 +240,6 @@ CONFIG_BRIDGE_EBT_NFLOG=m | |||
249 | CONFIG_RDS=m | 240 | CONFIG_RDS=m |
250 | CONFIG_RDS_TCP=m | 241 | CONFIG_RDS_TCP=m |
251 | CONFIG_BRIDGE=m | 242 | CONFIG_BRIDGE=m |
252 | CONFIG_NET_DSA=y | ||
253 | CONFIG_VLAN_8021Q=m | 243 | CONFIG_VLAN_8021Q=m |
254 | CONFIG_VLAN_8021Q_GVRP=y | 244 | CONFIG_VLAN_8021Q_GVRP=y |
255 | CONFIG_PHONET=m | 245 | CONFIG_PHONET=m |
@@ -297,6 +287,7 @@ CONFIG_NET_ACT_SIMP=m | |||
297 | CONFIG_NET_ACT_SKBEDIT=m | 287 | CONFIG_NET_ACT_SKBEDIT=m |
298 | CONFIG_NET_CLS_IND=y | 288 | CONFIG_NET_CLS_IND=y |
299 | CONFIG_DCB=y | 289 | CONFIG_DCB=y |
290 | CONFIG_DNS_RESOLVER=y | ||
300 | # CONFIG_WIRELESS is not set | 291 | # CONFIG_WIRELESS is not set |
301 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" | 292 | CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" |
302 | CONFIG_DEVTMPFS=y | 293 | CONFIG_DEVTMPFS=y |
@@ -354,40 +345,7 @@ CONFIG_NET_DSA_MV88E6060=y | |||
354 | CONFIG_NET_DSA_MV88E6131=y | 345 | CONFIG_NET_DSA_MV88E6131=y |
355 | CONFIG_NET_DSA_MV88E6123_61_65=y | 346 | CONFIG_NET_DSA_MV88E6123_61_65=y |
356 | # CONFIG_NET_VENDOR_3COM is not set | 347 | # CONFIG_NET_VENDOR_3COM is not set |
357 | # CONFIG_NET_VENDOR_ADAPTEC is not set | 348 | CONFIG_E1000E=y |
358 | # CONFIG_NET_VENDOR_ALTEON is not set | ||
359 | # CONFIG_NET_VENDOR_AMD is not set | ||
360 | # CONFIG_NET_VENDOR_ATHEROS is not set | ||
361 | # CONFIG_NET_VENDOR_BROADCOM is not set | ||
362 | # CONFIG_NET_VENDOR_BROCADE is not set | ||
363 | # CONFIG_NET_VENDOR_CHELSIO is not set | ||
364 | # CONFIG_NET_VENDOR_CISCO is not set | ||
365 | # CONFIG_NET_VENDOR_DEC is not set | ||
366 | # CONFIG_NET_VENDOR_DLINK is not set | ||
367 | # CONFIG_NET_VENDOR_EMULEX is not set | ||
368 | # CONFIG_NET_VENDOR_EXAR is not set | ||
369 | # CONFIG_NET_VENDOR_HP is not set | ||
370 | # CONFIG_NET_VENDOR_INTEL is not set | ||
371 | # CONFIG_NET_VENDOR_MARVELL is not set | ||
372 | # CONFIG_NET_VENDOR_MELLANOX is not set | ||
373 | # CONFIG_NET_VENDOR_MICREL is not set | ||
374 | # CONFIG_NET_VENDOR_MYRI is not set | ||
375 | # CONFIG_NET_VENDOR_NATSEMI is not set | ||
376 | # CONFIG_NET_VENDOR_NVIDIA is not set | ||
377 | # CONFIG_NET_VENDOR_OKI is not set | ||
378 | # CONFIG_NET_PACKET_ENGINE is not set | ||
379 | # CONFIG_NET_VENDOR_QLOGIC is not set | ||
380 | # CONFIG_NET_VENDOR_REALTEK is not set | ||
381 | # CONFIG_NET_VENDOR_RDC is not set | ||
382 | # CONFIG_NET_VENDOR_SEEQ is not set | ||
383 | # CONFIG_NET_VENDOR_SILAN is not set | ||
384 | # CONFIG_NET_VENDOR_SIS is not set | ||
385 | # CONFIG_NET_VENDOR_SMSC is not set | ||
386 | # CONFIG_NET_VENDOR_STMICRO is not set | ||
387 | # CONFIG_NET_VENDOR_SUN is not set | ||
388 | # CONFIG_NET_VENDOR_TEHUTI is not set | ||
389 | # CONFIG_NET_VENDOR_TI is not set | ||
390 | # CONFIG_NET_VENDOR_VIA is not set | ||
391 | # CONFIG_WLAN is not set | 349 | # CONFIG_WLAN is not set |
392 | # CONFIG_INPUT_MOUSEDEV is not set | 350 | # CONFIG_INPUT_MOUSEDEV is not set |
393 | # CONFIG_INPUT_KEYBOARD is not set | 351 | # CONFIG_INPUT_KEYBOARD is not set |
@@ -403,7 +361,6 @@ CONFIG_I2C_CHARDEV=y | |||
403 | CONFIG_WATCHDOG=y | 361 | CONFIG_WATCHDOG=y |
404 | CONFIG_WATCHDOG_NOWAYOUT=y | 362 | CONFIG_WATCHDOG_NOWAYOUT=y |
405 | # CONFIG_VGA_ARB is not set | 363 | # CONFIG_VGA_ARB is not set |
406 | # CONFIG_HID_SUPPORT is not set | ||
407 | # CONFIG_USB_SUPPORT is not set | 364 | # CONFIG_USB_SUPPORT is not set |
408 | CONFIG_EDAC=y | 365 | CONFIG_EDAC=y |
409 | CONFIG_EDAC_MM_EDAC=y | 366 | CONFIG_EDAC_MM_EDAC=y |
@@ -448,13 +405,13 @@ CONFIG_PROC_KCORE=y | |||
448 | CONFIG_TMPFS=y | 405 | CONFIG_TMPFS=y |
449 | CONFIG_TMPFS_POSIX_ACL=y | 406 | CONFIG_TMPFS_POSIX_ACL=y |
450 | CONFIG_HUGETLBFS=y | 407 | CONFIG_HUGETLBFS=y |
408 | CONFIG_CONFIGFS_FS=m | ||
451 | CONFIG_ECRYPT_FS=m | 409 | CONFIG_ECRYPT_FS=m |
452 | CONFIG_CRAMFS=m | 410 | CONFIG_CRAMFS=m |
453 | CONFIG_SQUASHFS=m | 411 | CONFIG_SQUASHFS=m |
454 | CONFIG_NFS_FS=m | 412 | CONFIG_NFS_FS=m |
455 | CONFIG_NFS_V3=y | ||
456 | CONFIG_NFS_V3_ACL=y | 413 | CONFIG_NFS_V3_ACL=y |
457 | CONFIG_NFS_V4=y | 414 | CONFIG_NFS_V4=m |
458 | CONFIG_NFS_V4_1=y | 415 | CONFIG_NFS_V4_1=y |
459 | CONFIG_NFS_FSCACHE=y | 416 | CONFIG_NFS_FSCACHE=y |
460 | CONFIG_NFSD=m | 417 | CONFIG_NFSD=m |
@@ -508,26 +465,29 @@ CONFIG_NLS_ISO8859_15=m | |||
508 | CONFIG_NLS_KOI8_R=m | 465 | CONFIG_NLS_KOI8_R=m |
509 | CONFIG_NLS_KOI8_U=m | 466 | CONFIG_NLS_KOI8_U=m |
510 | CONFIG_NLS_UTF8=m | 467 | CONFIG_NLS_UTF8=m |
468 | CONFIG_DLM=m | ||
511 | CONFIG_DLM_DEBUG=y | 469 | CONFIG_DLM_DEBUG=y |
470 | CONFIG_DYNAMIC_DEBUG=y | ||
471 | CONFIG_DEBUG_INFO=y | ||
472 | CONFIG_DEBUG_INFO_REDUCED=y | ||
512 | # CONFIG_ENABLE_WARN_DEPRECATED is not set | 473 | # CONFIG_ENABLE_WARN_DEPRECATED is not set |
513 | CONFIG_FRAME_WARN=2048 | 474 | CONFIG_FRAME_WARN=2048 |
514 | CONFIG_MAGIC_SYSRQ=y | ||
515 | CONFIG_STRIP_ASM_SYMS=y | 475 | CONFIG_STRIP_ASM_SYMS=y |
516 | CONFIG_DEBUG_FS=y | 476 | CONFIG_DEBUG_FS=y |
517 | CONFIG_HEADERS_CHECK=y | 477 | CONFIG_HEADERS_CHECK=y |
478 | # CONFIG_FRAME_POINTER is not set | ||
479 | CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y | ||
480 | CONFIG_MAGIC_SYSRQ=y | ||
481 | CONFIG_DEBUG_VM=y | ||
482 | CONFIG_DEBUG_MEMORY_INIT=y | ||
483 | CONFIG_DEBUG_STACKOVERFLOW=y | ||
518 | CONFIG_LOCKUP_DETECTOR=y | 484 | CONFIG_LOCKUP_DETECTOR=y |
519 | CONFIG_SCHEDSTATS=y | 485 | CONFIG_SCHEDSTATS=y |
520 | CONFIG_TIMER_STATS=y | 486 | CONFIG_TIMER_STATS=y |
521 | CONFIG_DEBUG_INFO=y | ||
522 | CONFIG_DEBUG_INFO_REDUCED=y | ||
523 | CONFIG_DEBUG_VM=y | ||
524 | CONFIG_DEBUG_MEMORY_INIT=y | ||
525 | CONFIG_DEBUG_LIST=y | 487 | CONFIG_DEBUG_LIST=y |
526 | CONFIG_DEBUG_CREDENTIALS=y | 488 | CONFIG_DEBUG_CREDENTIALS=y |
527 | CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y | 489 | CONFIG_RCU_CPU_STALL_TIMEOUT=60 |
528 | CONFIG_DYNAMIC_DEBUG=y | ||
529 | CONFIG_ASYNC_RAID6_TEST=m | 490 | CONFIG_ASYNC_RAID6_TEST=m |
530 | CONFIG_DEBUG_STACKOVERFLOW=y | ||
531 | CONFIG_KEYS_DEBUG_PROC_KEYS=y | 491 | CONFIG_KEYS_DEBUG_PROC_KEYS=y |
532 | CONFIG_SECURITY=y | 492 | CONFIG_SECURITY=y |
533 | CONFIG_SECURITYFS=y | 493 | CONFIG_SECURITYFS=y |
@@ -536,7 +496,6 @@ CONFIG_SECURITY_NETWORK_XFRM=y | |||
536 | CONFIG_SECURITY_SELINUX=y | 496 | CONFIG_SECURITY_SELINUX=y |
537 | CONFIG_SECURITY_SELINUX_BOOTPARAM=y | 497 | CONFIG_SECURITY_SELINUX_BOOTPARAM=y |
538 | CONFIG_SECURITY_SELINUX_DISABLE=y | 498 | CONFIG_SECURITY_SELINUX_DISABLE=y |
539 | CONFIG_CRYPTO_NULL=m | ||
540 | CONFIG_CRYPTO_PCRYPT=m | 499 | CONFIG_CRYPTO_PCRYPT=m |
541 | CONFIG_CRYPTO_CRYPTD=m | 500 | CONFIG_CRYPTO_CRYPTD=m |
542 | CONFIG_CRYPTO_TEST=m | 501 | CONFIG_CRYPTO_TEST=m |
@@ -549,14 +508,12 @@ CONFIG_CRYPTO_XTS=m | |||
549 | CONFIG_CRYPTO_HMAC=y | 508 | CONFIG_CRYPTO_HMAC=y |
550 | CONFIG_CRYPTO_XCBC=m | 509 | CONFIG_CRYPTO_XCBC=m |
551 | CONFIG_CRYPTO_VMAC=m | 510 | CONFIG_CRYPTO_VMAC=m |
552 | CONFIG_CRYPTO_CRC32C=y | ||
553 | CONFIG_CRYPTO_MICHAEL_MIC=m | 511 | CONFIG_CRYPTO_MICHAEL_MIC=m |
554 | CONFIG_CRYPTO_RMD128=m | 512 | CONFIG_CRYPTO_RMD128=m |
555 | CONFIG_CRYPTO_RMD160=m | 513 | CONFIG_CRYPTO_RMD160=m |
556 | CONFIG_CRYPTO_RMD256=m | 514 | CONFIG_CRYPTO_RMD256=m |
557 | CONFIG_CRYPTO_RMD320=m | 515 | CONFIG_CRYPTO_RMD320=m |
558 | CONFIG_CRYPTO_SHA1=y | 516 | CONFIG_CRYPTO_SHA1=y |
559 | CONFIG_CRYPTO_SHA256=m | ||
560 | CONFIG_CRYPTO_SHA512=m | 517 | CONFIG_CRYPTO_SHA512=m |
561 | CONFIG_CRYPTO_TGR192=m | 518 | CONFIG_CRYPTO_TGR192=m |
562 | CONFIG_CRYPTO_WP512=m | 519 | CONFIG_CRYPTO_WP512=m |
diff --git a/arch/tile/gxio/Kconfig b/arch/tile/gxio/Kconfig index d221f8d6de8b..d4e10d58071b 100644 --- a/arch/tile/gxio/Kconfig +++ b/arch/tile/gxio/Kconfig | |||
@@ -26,3 +26,8 @@ config TILE_GXIO_TRIO | |||
26 | config TILE_GXIO_USB_HOST | 26 | config TILE_GXIO_USB_HOST |
27 | bool | 27 | bool |
28 | select TILE_GXIO | 28 | select TILE_GXIO |
29 | |||
30 | # Support direct access to the TILE-Gx UART hardware from kernel space. | ||
31 | config TILE_GXIO_UART | ||
32 | bool | ||
33 | select TILE_GXIO | ||
diff --git a/arch/tile/gxio/Makefile b/arch/tile/gxio/Makefile index 8684bcaa74ea..26ae2c727467 100644 --- a/arch/tile/gxio/Makefile +++ b/arch/tile/gxio/Makefile | |||
@@ -6,4 +6,5 @@ obj-$(CONFIG_TILE_GXIO) += iorpc_globals.o kiorpc.o | |||
6 | obj-$(CONFIG_TILE_GXIO_DMA) += dma_queue.o | 6 | obj-$(CONFIG_TILE_GXIO_DMA) += dma_queue.o |
7 | obj-$(CONFIG_TILE_GXIO_MPIPE) += mpipe.o iorpc_mpipe.o iorpc_mpipe_info.o | 7 | obj-$(CONFIG_TILE_GXIO_MPIPE) += mpipe.o iorpc_mpipe.o iorpc_mpipe_info.o |
8 | obj-$(CONFIG_TILE_GXIO_TRIO) += trio.o iorpc_trio.o | 8 | obj-$(CONFIG_TILE_GXIO_TRIO) += trio.o iorpc_trio.o |
9 | obj-$(CONFIG_TILE_GXIO_UART) += uart.o iorpc_uart.o | ||
9 | obj-$(CONFIG_TILE_GXIO_USB_HOST) += usb_host.o iorpc_usb_host.o | 10 | obj-$(CONFIG_TILE_GXIO_USB_HOST) += usb_host.o iorpc_usb_host.o |
diff --git a/arch/tile/gxio/iorpc_trio.c b/arch/tile/gxio/iorpc_trio.c index cef4b2209cda..da6e18e049c3 100644 --- a/arch/tile/gxio/iorpc_trio.c +++ b/arch/tile/gxio/iorpc_trio.c | |||
@@ -61,6 +61,29 @@ int gxio_trio_alloc_memory_maps(gxio_trio_context_t * context, | |||
61 | 61 | ||
62 | EXPORT_SYMBOL(gxio_trio_alloc_memory_maps); | 62 | EXPORT_SYMBOL(gxio_trio_alloc_memory_maps); |
63 | 63 | ||
64 | struct alloc_scatter_queues_param { | ||
65 | unsigned int count; | ||
66 | unsigned int first; | ||
67 | unsigned int flags; | ||
68 | }; | ||
69 | |||
70 | int gxio_trio_alloc_scatter_queues(gxio_trio_context_t * context, | ||
71 | unsigned int count, unsigned int first, | ||
72 | unsigned int flags) | ||
73 | { | ||
74 | struct alloc_scatter_queues_param temp; | ||
75 | struct alloc_scatter_queues_param *params = &temp; | ||
76 | |||
77 | params->count = count; | ||
78 | params->first = first; | ||
79 | params->flags = flags; | ||
80 | |||
81 | return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, | ||
82 | sizeof(*params), | ||
83 | GXIO_TRIO_OP_ALLOC_SCATTER_QUEUES); | ||
84 | } | ||
85 | |||
86 | EXPORT_SYMBOL(gxio_trio_alloc_scatter_queues); | ||
64 | 87 | ||
65 | struct alloc_pio_regions_param { | 88 | struct alloc_pio_regions_param { |
66 | unsigned int count; | 89 | unsigned int count; |
diff --git a/arch/tile/gxio/iorpc_uart.c b/arch/tile/gxio/iorpc_uart.c new file mode 100644 index 000000000000..b9a6d6193d73 --- /dev/null +++ b/arch/tile/gxio/iorpc_uart.c | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | /* This file is machine-generated; DO NOT EDIT! */ | ||
16 | #include "gxio/iorpc_uart.h" | ||
17 | |||
18 | struct cfg_interrupt_param { | ||
19 | union iorpc_interrupt interrupt; | ||
20 | }; | ||
21 | |||
22 | int gxio_uart_cfg_interrupt(gxio_uart_context_t *context, int inter_x, | ||
23 | int inter_y, int inter_ipi, int inter_event) | ||
24 | { | ||
25 | struct cfg_interrupt_param temp; | ||
26 | struct cfg_interrupt_param *params = &temp; | ||
27 | |||
28 | params->interrupt.kernel.x = inter_x; | ||
29 | params->interrupt.kernel.y = inter_y; | ||
30 | params->interrupt.kernel.ipi = inter_ipi; | ||
31 | params->interrupt.kernel.event = inter_event; | ||
32 | |||
33 | return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, | ||
34 | sizeof(*params), GXIO_UART_OP_CFG_INTERRUPT); | ||
35 | } | ||
36 | |||
37 | EXPORT_SYMBOL(gxio_uart_cfg_interrupt); | ||
38 | |||
39 | struct get_mmio_base_param { | ||
40 | HV_PTE base; | ||
41 | }; | ||
42 | |||
43 | int gxio_uart_get_mmio_base(gxio_uart_context_t *context, HV_PTE *base) | ||
44 | { | ||
45 | int __result; | ||
46 | struct get_mmio_base_param temp; | ||
47 | struct get_mmio_base_param *params = &temp; | ||
48 | |||
49 | __result = | ||
50 | hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params), | ||
51 | GXIO_UART_OP_GET_MMIO_BASE); | ||
52 | *base = params->base; | ||
53 | |||
54 | return __result; | ||
55 | } | ||
56 | |||
57 | EXPORT_SYMBOL(gxio_uart_get_mmio_base); | ||
58 | |||
59 | struct check_mmio_offset_param { | ||
60 | unsigned long offset; | ||
61 | unsigned long size; | ||
62 | }; | ||
63 | |||
64 | int gxio_uart_check_mmio_offset(gxio_uart_context_t *context, | ||
65 | unsigned long offset, unsigned long size) | ||
66 | { | ||
67 | struct check_mmio_offset_param temp; | ||
68 | struct check_mmio_offset_param *params = &temp; | ||
69 | |||
70 | params->offset = offset; | ||
71 | params->size = size; | ||
72 | |||
73 | return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, | ||
74 | sizeof(*params), GXIO_UART_OP_CHECK_MMIO_OFFSET); | ||
75 | } | ||
76 | |||
77 | EXPORT_SYMBOL(gxio_uart_check_mmio_offset); | ||
diff --git a/arch/tile/gxio/uart.c b/arch/tile/gxio/uart.c new file mode 100644 index 000000000000..ba585175ef88 --- /dev/null +++ b/arch/tile/gxio/uart.c | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * Implementation of UART gxio calls. | ||
17 | */ | ||
18 | |||
19 | #include <linux/io.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/module.h> | ||
22 | |||
23 | #include <gxio/uart.h> | ||
24 | #include <gxio/iorpc_globals.h> | ||
25 | #include <gxio/iorpc_uart.h> | ||
26 | #include <gxio/kiorpc.h> | ||
27 | |||
28 | int gxio_uart_init(gxio_uart_context_t *context, int uart_index) | ||
29 | { | ||
30 | char file[32]; | ||
31 | int fd; | ||
32 | |||
33 | snprintf(file, sizeof(file), "uart/%d/iorpc", uart_index); | ||
34 | fd = hv_dev_open((HV_VirtAddr) file, 0); | ||
35 | if (fd < 0) { | ||
36 | if (fd >= GXIO_ERR_MIN && fd <= GXIO_ERR_MAX) | ||
37 | return fd; | ||
38 | else | ||
39 | return -ENODEV; | ||
40 | } | ||
41 | |||
42 | context->fd = fd; | ||
43 | |||
44 | /* Map in the MMIO space. */ | ||
45 | context->mmio_base = (void __force *) | ||
46 | iorpc_ioremap(fd, HV_UART_MMIO_OFFSET, HV_UART_MMIO_SIZE); | ||
47 | |||
48 | if (context->mmio_base == NULL) { | ||
49 | hv_dev_close(context->fd); | ||
50 | context->fd = -1; | ||
51 | return -ENODEV; | ||
52 | } | ||
53 | |||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | EXPORT_SYMBOL_GPL(gxio_uart_init); | ||
58 | |||
59 | int gxio_uart_destroy(gxio_uart_context_t *context) | ||
60 | { | ||
61 | iounmap((void __force __iomem *)(context->mmio_base)); | ||
62 | hv_dev_close(context->fd); | ||
63 | |||
64 | context->mmio_base = NULL; | ||
65 | context->fd = -1; | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | EXPORT_SYMBOL_GPL(gxio_uart_destroy); | ||
71 | |||
72 | /* UART register write wrapper. */ | ||
73 | void gxio_uart_write(gxio_uart_context_t *context, uint64_t offset, | ||
74 | uint64_t word) | ||
75 | { | ||
76 | __gxio_mmio_write(context->mmio_base + offset, word); | ||
77 | } | ||
78 | |||
79 | EXPORT_SYMBOL_GPL(gxio_uart_write); | ||
80 | |||
81 | /* UART register read wrapper. */ | ||
82 | uint64_t gxio_uart_read(gxio_uart_context_t *context, uint64_t offset) | ||
83 | { | ||
84 | return __gxio_mmio_read(context->mmio_base + offset); | ||
85 | } | ||
86 | |||
87 | EXPORT_SYMBOL_GPL(gxio_uart_read); | ||
diff --git a/arch/tile/include/arch/trio.h b/arch/tile/include/arch/trio.h index d3000a871a21..c0ddedcae085 100644 --- a/arch/tile/include/arch/trio.h +++ b/arch/tile/include/arch/trio.h | |||
@@ -23,6 +23,45 @@ | |||
23 | #ifndef __ASSEMBLER__ | 23 | #ifndef __ASSEMBLER__ |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * Map SQ Doorbell Format. | ||
27 | * This describes the format of the write-only doorbell register that exists | ||
28 | * in the last 8-bytes of the MAP_SQ_BASE/LIM range. This register is only | ||
29 | * writable from PCIe space. Writes to this register will not be written to | ||
30 | * Tile memory space and thus no IO VA translation is required if the last | ||
31 | * page of the BASE/LIM range is not otherwise written. | ||
32 | */ | ||
33 | |||
34 | __extension__ | ||
35 | typedef union | ||
36 | { | ||
37 | struct | ||
38 | { | ||
39 | #ifndef __BIG_ENDIAN__ | ||
40 | /* | ||
41 | * When written with a 1, the associated MAP_SQ region's doorbell | ||
42 | * interrupt will be triggered once all previous writes are visible to | ||
43 | * Tile software. | ||
44 | */ | ||
45 | uint_reg_t doorbell : 1; | ||
46 | /* | ||
47 | * When written with a 1, the descriptor at the head of the associated | ||
48 | * MAP_SQ's FIFO will be dequeued. | ||
49 | */ | ||
50 | uint_reg_t pop : 1; | ||
51 | /* Reserved. */ | ||
52 | uint_reg_t __reserved : 62; | ||
53 | #else /* __BIG_ENDIAN__ */ | ||
54 | uint_reg_t __reserved : 62; | ||
55 | uint_reg_t pop : 1; | ||
56 | uint_reg_t doorbell : 1; | ||
57 | #endif | ||
58 | }; | ||
59 | |||
60 | uint_reg_t word; | ||
61 | } TRIO_MAP_SQ_DOORBELL_FMT_t; | ||
62 | |||
63 | |||
64 | /* | ||
26 | * Tile PIO Region Configuration - CFG Address Format. | 65 | * Tile PIO Region Configuration - CFG Address Format. |
27 | * This register describes the address format for PIO accesses when the | 66 | * This register describes the address format for PIO accesses when the |
28 | * associated region is setup with TYPE=CFG. | 67 | * associated region is setup with TYPE=CFG. |
diff --git a/arch/tile/include/arch/uart.h b/arch/tile/include/arch/uart.h new file mode 100644 index 000000000000..07966970adad --- /dev/null +++ b/arch/tile/include/arch/uart.h | |||
@@ -0,0 +1,300 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | /* Machine-generated file; do not edit. */ | ||
16 | |||
17 | #ifndef __ARCH_UART_H__ | ||
18 | #define __ARCH_UART_H__ | ||
19 | |||
20 | #include <arch/abi.h> | ||
21 | #include <arch/uart_def.h> | ||
22 | |||
23 | #ifndef __ASSEMBLER__ | ||
24 | |||
25 | /* Divisor. */ | ||
26 | |||
27 | __extension__ | ||
28 | typedef union | ||
29 | { | ||
30 | struct | ||
31 | { | ||
32 | #ifndef __BIG_ENDIAN__ | ||
33 | /* | ||
34 | * Baud Rate Divisor. Desired_baud_rate = REF_CLK frequency / (baud * | ||
35 | * 16). | ||
36 | * Note: REF_CLK is always 125 MHz, the default | ||
37 | * divisor = 68, baud rate = 125M/(68*16) = 115200 baud. | ||
38 | */ | ||
39 | uint_reg_t divisor : 12; | ||
40 | /* Reserved. */ | ||
41 | uint_reg_t __reserved : 52; | ||
42 | #else /* __BIG_ENDIAN__ */ | ||
43 | uint_reg_t __reserved : 52; | ||
44 | uint_reg_t divisor : 12; | ||
45 | #endif | ||
46 | }; | ||
47 | |||
48 | uint_reg_t word; | ||
49 | } UART_DIVISOR_t; | ||
50 | |||
51 | /* FIFO Count. */ | ||
52 | |||
53 | __extension__ | ||
54 | typedef union | ||
55 | { | ||
56 | struct | ||
57 | { | ||
58 | #ifndef __BIG_ENDIAN__ | ||
59 | /* | ||
60 | * n: n active entries in the receive FIFO (max is 2**8). Each entry has | ||
61 | * 8 bits. | ||
62 | * 0: no active entry in the receive FIFO (that is empty). | ||
63 | */ | ||
64 | uint_reg_t rfifo_count : 9; | ||
65 | /* Reserved. */ | ||
66 | uint_reg_t __reserved_0 : 7; | ||
67 | /* | ||
68 | * n: n active entries in the transmit FIFO (max is 2**8). Each entry has | ||
69 | * 8 bits. | ||
70 | * 0: no active entry in the transmit FIFO (that is empty). | ||
71 | */ | ||
72 | uint_reg_t tfifo_count : 9; | ||
73 | /* Reserved. */ | ||
74 | uint_reg_t __reserved_1 : 7; | ||
75 | /* | ||
76 | * n: n active entries in the write FIFO (max is 2**2). Each entry has 8 | ||
77 | * bits. | ||
78 | * 0: no active entry in the write FIFO (that is empty). | ||
79 | */ | ||
80 | uint_reg_t wfifo_count : 3; | ||
81 | /* Reserved. */ | ||
82 | uint_reg_t __reserved_2 : 29; | ||
83 | #else /* __BIG_ENDIAN__ */ | ||
84 | uint_reg_t __reserved_2 : 29; | ||
85 | uint_reg_t wfifo_count : 3; | ||
86 | uint_reg_t __reserved_1 : 7; | ||
87 | uint_reg_t tfifo_count : 9; | ||
88 | uint_reg_t __reserved_0 : 7; | ||
89 | uint_reg_t rfifo_count : 9; | ||
90 | #endif | ||
91 | }; | ||
92 | |||
93 | uint_reg_t word; | ||
94 | } UART_FIFO_COUNT_t; | ||
95 | |||
96 | /* FLAG. */ | ||
97 | |||
98 | __extension__ | ||
99 | typedef union | ||
100 | { | ||
101 | struct | ||
102 | { | ||
103 | #ifndef __BIG_ENDIAN__ | ||
104 | /* Reserved. */ | ||
105 | uint_reg_t __reserved_0 : 1; | ||
106 | /* 1: receive FIFO is empty */ | ||
107 | uint_reg_t rfifo_empty : 1; | ||
108 | /* 1: write FIFO is empty. */ | ||
109 | uint_reg_t wfifo_empty : 1; | ||
110 | /* 1: transmit FIFO is empty. */ | ||
111 | uint_reg_t tfifo_empty : 1; | ||
112 | /* 1: receive FIFO is full. */ | ||
113 | uint_reg_t rfifo_full : 1; | ||
114 | /* 1: write FIFO is full. */ | ||
115 | uint_reg_t wfifo_full : 1; | ||
116 | /* 1: transmit FIFO is full. */ | ||
117 | uint_reg_t tfifo_full : 1; | ||
118 | /* Reserved. */ | ||
119 | uint_reg_t __reserved_1 : 57; | ||
120 | #else /* __BIG_ENDIAN__ */ | ||
121 | uint_reg_t __reserved_1 : 57; | ||
122 | uint_reg_t tfifo_full : 1; | ||
123 | uint_reg_t wfifo_full : 1; | ||
124 | uint_reg_t rfifo_full : 1; | ||
125 | uint_reg_t tfifo_empty : 1; | ||
126 | uint_reg_t wfifo_empty : 1; | ||
127 | uint_reg_t rfifo_empty : 1; | ||
128 | uint_reg_t __reserved_0 : 1; | ||
129 | #endif | ||
130 | }; | ||
131 | |||
132 | uint_reg_t word; | ||
133 | } UART_FLAG_t; | ||
134 | |||
135 | /* | ||
136 | * Interrupt Vector Mask. | ||
137 | * Each bit in this register corresponds to a specific interrupt. When set, | ||
138 | * the associated interrupt will not be dispatched. | ||
139 | */ | ||
140 | |||
141 | __extension__ | ||
142 | typedef union | ||
143 | { | ||
144 | struct | ||
145 | { | ||
146 | #ifndef __BIG_ENDIAN__ | ||
147 | /* Read data FIFO read and no data available */ | ||
148 | uint_reg_t rdat_err : 1; | ||
149 | /* Write FIFO was written but it was full */ | ||
150 | uint_reg_t wdat_err : 1; | ||
151 | /* Stop bit not found when current data was received */ | ||
152 | uint_reg_t frame_err : 1; | ||
153 | /* Parity error was detected when current data was received */ | ||
154 | uint_reg_t parity_err : 1; | ||
155 | /* Data was received but the receive FIFO was full */ | ||
156 | uint_reg_t rfifo_overflow : 1; | ||
157 | /* | ||
158 | * An almost full event is reached when data is to be written to the | ||
159 | * receive FIFO, and the receive FIFO has more than or equal to | ||
160 | * BUFFER_THRESHOLD.RFIFO_AFULL bytes. | ||
161 | */ | ||
162 | uint_reg_t rfifo_afull : 1; | ||
163 | /* Reserved. */ | ||
164 | uint_reg_t __reserved_0 : 1; | ||
165 | /* An entry in the transmit FIFO was popped */ | ||
166 | uint_reg_t tfifo_re : 1; | ||
167 | /* An entry has been pushed into the receive FIFO */ | ||
168 | uint_reg_t rfifo_we : 1; | ||
169 | /* An entry of the write FIFO has been popped */ | ||
170 | uint_reg_t wfifo_re : 1; | ||
171 | /* Rshim read receive FIFO in protocol mode */ | ||
172 | uint_reg_t rfifo_err : 1; | ||
173 | /* | ||
174 | * An almost empty event is reached when data is to be read from the | ||
175 | * transmit FIFO, and the transmit FIFO has less than or equal to | ||
176 | * BUFFER_THRESHOLD.TFIFO_AEMPTY bytes. | ||
177 | */ | ||
178 | uint_reg_t tfifo_aempty : 1; | ||
179 | /* Reserved. */ | ||
180 | uint_reg_t __reserved_1 : 52; | ||
181 | #else /* __BIG_ENDIAN__ */ | ||
182 | uint_reg_t __reserved_1 : 52; | ||
183 | uint_reg_t tfifo_aempty : 1; | ||
184 | uint_reg_t rfifo_err : 1; | ||
185 | uint_reg_t wfifo_re : 1; | ||
186 | uint_reg_t rfifo_we : 1; | ||
187 | uint_reg_t tfifo_re : 1; | ||
188 | uint_reg_t __reserved_0 : 1; | ||
189 | uint_reg_t rfifo_afull : 1; | ||
190 | uint_reg_t rfifo_overflow : 1; | ||
191 | uint_reg_t parity_err : 1; | ||
192 | uint_reg_t frame_err : 1; | ||
193 | uint_reg_t wdat_err : 1; | ||
194 | uint_reg_t rdat_err : 1; | ||
195 | #endif | ||
196 | }; | ||
197 | |||
198 | uint_reg_t word; | ||
199 | } UART_INTERRUPT_MASK_t; | ||
200 | |||
201 | /* | ||
202 | * Interrupt vector, write-one-to-clear. | ||
203 | * Each bit in this register corresponds to a specific interrupt. Hardware | ||
204 | * sets the bit when the associated condition has occurred. Writing a 1 | ||
205 | * clears the status bit. | ||
206 | */ | ||
207 | |||
208 | __extension__ | ||
209 | typedef union | ||
210 | { | ||
211 | struct | ||
212 | { | ||
213 | #ifndef __BIG_ENDIAN__ | ||
214 | /* Read data FIFO read and no data available */ | ||
215 | uint_reg_t rdat_err : 1; | ||
216 | /* Write FIFO was written but it was full */ | ||
217 | uint_reg_t wdat_err : 1; | ||
218 | /* Stop bit not found when current data was received */ | ||
219 | uint_reg_t frame_err : 1; | ||
220 | /* Parity error was detected when current data was received */ | ||
221 | uint_reg_t parity_err : 1; | ||
222 | /* Data was received but the receive FIFO was full */ | ||
223 | uint_reg_t rfifo_overflow : 1; | ||
224 | /* | ||
225 | * Data was received and the receive FIFO is now almost full (more than | ||
226 | * BUFFER_THRESHOLD.RFIFO_AFULL bytes in it) | ||
227 | */ | ||
228 | uint_reg_t rfifo_afull : 1; | ||
229 | /* Reserved. */ | ||
230 | uint_reg_t __reserved_0 : 1; | ||
231 | /* An entry in the transmit FIFO was popped */ | ||
232 | uint_reg_t tfifo_re : 1; | ||
233 | /* An entry has been pushed into the receive FIFO */ | ||
234 | uint_reg_t rfifo_we : 1; | ||
235 | /* An entry of the write FIFO has been popped */ | ||
236 | uint_reg_t wfifo_re : 1; | ||
237 | /* Rshim read receive FIFO in protocol mode */ | ||
238 | uint_reg_t rfifo_err : 1; | ||
239 | /* | ||
240 | * Data was read from the transmit FIFO and now it is almost empty (less | ||
241 | * than or equal to BUFFER_THRESHOLD.TFIFO_AEMPTY bytes in it). | ||
242 | */ | ||
243 | uint_reg_t tfifo_aempty : 1; | ||
244 | /* Reserved. */ | ||
245 | uint_reg_t __reserved_1 : 52; | ||
246 | #else /* __BIG_ENDIAN__ */ | ||
247 | uint_reg_t __reserved_1 : 52; | ||
248 | uint_reg_t tfifo_aempty : 1; | ||
249 | uint_reg_t rfifo_err : 1; | ||
250 | uint_reg_t wfifo_re : 1; | ||
251 | uint_reg_t rfifo_we : 1; | ||
252 | uint_reg_t tfifo_re : 1; | ||
253 | uint_reg_t __reserved_0 : 1; | ||
254 | uint_reg_t rfifo_afull : 1; | ||
255 | uint_reg_t rfifo_overflow : 1; | ||
256 | uint_reg_t parity_err : 1; | ||
257 | uint_reg_t frame_err : 1; | ||
258 | uint_reg_t wdat_err : 1; | ||
259 | uint_reg_t rdat_err : 1; | ||
260 | #endif | ||
261 | }; | ||
262 | |||
263 | uint_reg_t word; | ||
264 | } UART_INTERRUPT_STATUS_t; | ||
265 | |||
266 | /* Type. */ | ||
267 | |||
268 | __extension__ | ||
269 | typedef union | ||
270 | { | ||
271 | struct | ||
272 | { | ||
273 | #ifndef __BIG_ENDIAN__ | ||
274 | /* Number of stop bits, rx and tx */ | ||
275 | uint_reg_t sbits : 1; | ||
276 | /* Reserved. */ | ||
277 | uint_reg_t __reserved_0 : 1; | ||
278 | /* Data word size, rx and tx */ | ||
279 | uint_reg_t dbits : 1; | ||
280 | /* Reserved. */ | ||
281 | uint_reg_t __reserved_1 : 1; | ||
282 | /* Parity selection, rx and tx */ | ||
283 | uint_reg_t ptype : 3; | ||
284 | /* Reserved. */ | ||
285 | uint_reg_t __reserved_2 : 57; | ||
286 | #else /* __BIG_ENDIAN__ */ | ||
287 | uint_reg_t __reserved_2 : 57; | ||
288 | uint_reg_t ptype : 3; | ||
289 | uint_reg_t __reserved_1 : 1; | ||
290 | uint_reg_t dbits : 1; | ||
291 | uint_reg_t __reserved_0 : 1; | ||
292 | uint_reg_t sbits : 1; | ||
293 | #endif | ||
294 | }; | ||
295 | |||
296 | uint_reg_t word; | ||
297 | } UART_TYPE_t; | ||
298 | #endif /* !defined(__ASSEMBLER__) */ | ||
299 | |||
300 | #endif /* !defined(__ARCH_UART_H__) */ | ||
diff --git a/arch/tile/include/arch/uart_def.h b/arch/tile/include/arch/uart_def.h new file mode 100644 index 000000000000..42bcaf535379 --- /dev/null +++ b/arch/tile/include/arch/uart_def.h | |||
@@ -0,0 +1,120 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | /* Machine-generated file; do not edit. */ | ||
16 | |||
17 | #ifndef __ARCH_UART_DEF_H__ | ||
18 | #define __ARCH_UART_DEF_H__ | ||
19 | #define UART_DIVISOR 0x0158 | ||
20 | #define UART_FIFO_COUNT 0x0110 | ||
21 | #define UART_FLAG 0x0108 | ||
22 | #define UART_INTERRUPT_MASK 0x0208 | ||
23 | #define UART_INTERRUPT_MASK__RDAT_ERR_SHIFT 0 | ||
24 | #define UART_INTERRUPT_MASK__RDAT_ERR_WIDTH 1 | ||
25 | #define UART_INTERRUPT_MASK__RDAT_ERR_RESET_VAL 1 | ||
26 | #define UART_INTERRUPT_MASK__RDAT_ERR_RMASK 0x1 | ||
27 | #define UART_INTERRUPT_MASK__RDAT_ERR_MASK 0x1 | ||
28 | #define UART_INTERRUPT_MASK__RDAT_ERR_FIELD 0,0 | ||
29 | #define UART_INTERRUPT_MASK__WDAT_ERR_SHIFT 1 | ||
30 | #define UART_INTERRUPT_MASK__WDAT_ERR_WIDTH 1 | ||
31 | #define UART_INTERRUPT_MASK__WDAT_ERR_RESET_VAL 1 | ||
32 | #define UART_INTERRUPT_MASK__WDAT_ERR_RMASK 0x1 | ||
33 | #define UART_INTERRUPT_MASK__WDAT_ERR_MASK 0x2 | ||
34 | #define UART_INTERRUPT_MASK__WDAT_ERR_FIELD 1,1 | ||
35 | #define UART_INTERRUPT_MASK__FRAME_ERR_SHIFT 2 | ||
36 | #define UART_INTERRUPT_MASK__FRAME_ERR_WIDTH 1 | ||
37 | #define UART_INTERRUPT_MASK__FRAME_ERR_RESET_VAL 1 | ||
38 | #define UART_INTERRUPT_MASK__FRAME_ERR_RMASK 0x1 | ||
39 | #define UART_INTERRUPT_MASK__FRAME_ERR_MASK 0x4 | ||
40 | #define UART_INTERRUPT_MASK__FRAME_ERR_FIELD 2,2 | ||
41 | #define UART_INTERRUPT_MASK__PARITY_ERR_SHIFT 3 | ||
42 | #define UART_INTERRUPT_MASK__PARITY_ERR_WIDTH 1 | ||
43 | #define UART_INTERRUPT_MASK__PARITY_ERR_RESET_VAL 1 | ||
44 | #define UART_INTERRUPT_MASK__PARITY_ERR_RMASK 0x1 | ||
45 | #define UART_INTERRUPT_MASK__PARITY_ERR_MASK 0x8 | ||
46 | #define UART_INTERRUPT_MASK__PARITY_ERR_FIELD 3,3 | ||
47 | #define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_SHIFT 4 | ||
48 | #define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_WIDTH 1 | ||
49 | #define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_RESET_VAL 1 | ||
50 | #define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_RMASK 0x1 | ||
51 | #define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_MASK 0x10 | ||
52 | #define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_FIELD 4,4 | ||
53 | #define UART_INTERRUPT_MASK__RFIFO_AFULL_SHIFT 5 | ||
54 | #define UART_INTERRUPT_MASK__RFIFO_AFULL_WIDTH 1 | ||
55 | #define UART_INTERRUPT_MASK__RFIFO_AFULL_RESET_VAL 1 | ||
56 | #define UART_INTERRUPT_MASK__RFIFO_AFULL_RMASK 0x1 | ||
57 | #define UART_INTERRUPT_MASK__RFIFO_AFULL_MASK 0x20 | ||
58 | #define UART_INTERRUPT_MASK__RFIFO_AFULL_FIELD 5,5 | ||
59 | #define UART_INTERRUPT_MASK__TFIFO_RE_SHIFT 7 | ||
60 | #define UART_INTERRUPT_MASK__TFIFO_RE_WIDTH 1 | ||
61 | #define UART_INTERRUPT_MASK__TFIFO_RE_RESET_VAL 1 | ||
62 | #define UART_INTERRUPT_MASK__TFIFO_RE_RMASK 0x1 | ||
63 | #define UART_INTERRUPT_MASK__TFIFO_RE_MASK 0x80 | ||
64 | #define UART_INTERRUPT_MASK__TFIFO_RE_FIELD 7,7 | ||
65 | #define UART_INTERRUPT_MASK__RFIFO_WE_SHIFT 8 | ||
66 | #define UART_INTERRUPT_MASK__RFIFO_WE_WIDTH 1 | ||
67 | #define UART_INTERRUPT_MASK__RFIFO_WE_RESET_VAL 1 | ||
68 | #define UART_INTERRUPT_MASK__RFIFO_WE_RMASK 0x1 | ||
69 | #define UART_INTERRUPT_MASK__RFIFO_WE_MASK 0x100 | ||
70 | #define UART_INTERRUPT_MASK__RFIFO_WE_FIELD 8,8 | ||
71 | #define UART_INTERRUPT_MASK__WFIFO_RE_SHIFT 9 | ||
72 | #define UART_INTERRUPT_MASK__WFIFO_RE_WIDTH 1 | ||
73 | #define UART_INTERRUPT_MASK__WFIFO_RE_RESET_VAL 1 | ||
74 | #define UART_INTERRUPT_MASK__WFIFO_RE_RMASK 0x1 | ||
75 | #define UART_INTERRUPT_MASK__WFIFO_RE_MASK 0x200 | ||
76 | #define UART_INTERRUPT_MASK__WFIFO_RE_FIELD 9,9 | ||
77 | #define UART_INTERRUPT_MASK__RFIFO_ERR_SHIFT 10 | ||
78 | #define UART_INTERRUPT_MASK__RFIFO_ERR_WIDTH 1 | ||
79 | #define UART_INTERRUPT_MASK__RFIFO_ERR_RESET_VAL 1 | ||
80 | #define UART_INTERRUPT_MASK__RFIFO_ERR_RMASK 0x1 | ||
81 | #define UART_INTERRUPT_MASK__RFIFO_ERR_MASK 0x400 | ||
82 | #define UART_INTERRUPT_MASK__RFIFO_ERR_FIELD 10,10 | ||
83 | #define UART_INTERRUPT_MASK__TFIFO_AEMPTY_SHIFT 11 | ||
84 | #define UART_INTERRUPT_MASK__TFIFO_AEMPTY_WIDTH 1 | ||
85 | #define UART_INTERRUPT_MASK__TFIFO_AEMPTY_RESET_VAL 1 | ||
86 | #define UART_INTERRUPT_MASK__TFIFO_AEMPTY_RMASK 0x1 | ||
87 | #define UART_INTERRUPT_MASK__TFIFO_AEMPTY_MASK 0x800 | ||
88 | #define UART_INTERRUPT_MASK__TFIFO_AEMPTY_FIELD 11,11 | ||
89 | #define UART_INTERRUPT_STATUS 0x0200 | ||
90 | #define UART_RECEIVE_DATA 0x0148 | ||
91 | #define UART_TRANSMIT_DATA 0x0140 | ||
92 | #define UART_TYPE 0x0160 | ||
93 | #define UART_TYPE__SBITS_SHIFT 0 | ||
94 | #define UART_TYPE__SBITS_WIDTH 1 | ||
95 | #define UART_TYPE__SBITS_RESET_VAL 1 | ||
96 | #define UART_TYPE__SBITS_RMASK 0x1 | ||
97 | #define UART_TYPE__SBITS_MASK 0x1 | ||
98 | #define UART_TYPE__SBITS_FIELD 0,0 | ||
99 | #define UART_TYPE__SBITS_VAL_ONE_SBITS 0x0 | ||
100 | #define UART_TYPE__SBITS_VAL_TWO_SBITS 0x1 | ||
101 | #define UART_TYPE__DBITS_SHIFT 2 | ||
102 | #define UART_TYPE__DBITS_WIDTH 1 | ||
103 | #define UART_TYPE__DBITS_RESET_VAL 0 | ||
104 | #define UART_TYPE__DBITS_RMASK 0x1 | ||
105 | #define UART_TYPE__DBITS_MASK 0x4 | ||
106 | #define UART_TYPE__DBITS_FIELD 2,2 | ||
107 | #define UART_TYPE__DBITS_VAL_EIGHT_DBITS 0x0 | ||
108 | #define UART_TYPE__DBITS_VAL_SEVEN_DBITS 0x1 | ||
109 | #define UART_TYPE__PTYPE_SHIFT 4 | ||
110 | #define UART_TYPE__PTYPE_WIDTH 3 | ||
111 | #define UART_TYPE__PTYPE_RESET_VAL 3 | ||
112 | #define UART_TYPE__PTYPE_RMASK 0x7 | ||
113 | #define UART_TYPE__PTYPE_MASK 0x70 | ||
114 | #define UART_TYPE__PTYPE_FIELD 4,6 | ||
115 | #define UART_TYPE__PTYPE_VAL_NONE 0x0 | ||
116 | #define UART_TYPE__PTYPE_VAL_MARK 0x1 | ||
117 | #define UART_TYPE__PTYPE_VAL_SPACE 0x2 | ||
118 | #define UART_TYPE__PTYPE_VAL_EVEN 0x3 | ||
119 | #define UART_TYPE__PTYPE_VAL_ODD 0x4 | ||
120 | #endif /* !defined(__ARCH_UART_DEF_H__) */ | ||
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild index b17b9b8e53cd..664d6ad23f80 100644 --- a/arch/tile/include/asm/Kbuild +++ b/arch/tile/include/asm/Kbuild | |||
@@ -11,12 +11,13 @@ generic-y += errno.h | |||
11 | generic-y += exec.h | 11 | generic-y += exec.h |
12 | generic-y += fb.h | 12 | generic-y += fb.h |
13 | generic-y += fcntl.h | 13 | generic-y += fcntl.h |
14 | generic-y += hw_irq.h | ||
14 | generic-y += ioctl.h | 15 | generic-y += ioctl.h |
15 | generic-y += ioctls.h | 16 | generic-y += ioctls.h |
16 | generic-y += ipcbuf.h | 17 | generic-y += ipcbuf.h |
17 | generic-y += irq_regs.h | 18 | generic-y += irq_regs.h |
18 | generic-y += kdebug.h | ||
19 | generic-y += local.h | 19 | generic-y += local.h |
20 | generic-y += local64.h | ||
20 | generic-y += msgbuf.h | 21 | generic-y += msgbuf.h |
21 | generic-y += mutex.h | 22 | generic-y += mutex.h |
22 | generic-y += param.h | 23 | generic-y += param.h |
diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h index e71387ab20ca..d385eaadece7 100644 --- a/arch/tile/include/asm/atomic.h +++ b/arch/tile/include/asm/atomic.h | |||
@@ -114,6 +114,32 @@ static inline int atomic_read(const atomic_t *v) | |||
114 | #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) | 114 | #define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) |
115 | 115 | ||
116 | /** | 116 | /** |
117 | * atomic_xchg - atomically exchange contents of memory with a new value | ||
118 | * @v: pointer of type atomic_t | ||
119 | * @i: integer value to store in memory | ||
120 | * | ||
121 | * Atomically sets @v to @i and returns old @v | ||
122 | */ | ||
123 | static inline int atomic_xchg(atomic_t *v, int n) | ||
124 | { | ||
125 | return xchg(&v->counter, n); | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * atomic_cmpxchg - atomically exchange contents of memory if it matches | ||
130 | * @v: pointer of type atomic_t | ||
131 | * @o: old value that memory should have | ||
132 | * @n: new value to write to memory if it matches | ||
133 | * | ||
134 | * Atomically checks if @v holds @o and replaces it with @n if so. | ||
135 | * Returns the old value at @v. | ||
136 | */ | ||
137 | static inline int atomic_cmpxchg(atomic_t *v, int o, int n) | ||
138 | { | ||
139 | return cmpxchg(&v->counter, o, n); | ||
140 | } | ||
141 | |||
142 | /** | ||
117 | * atomic_add_negative - add and test if negative | 143 | * atomic_add_negative - add and test if negative |
118 | * @v: pointer of type atomic_t | 144 | * @v: pointer of type atomic_t |
119 | * @i: integer value to add | 145 | * @i: integer value to add |
@@ -133,6 +159,32 @@ static inline int atomic_read(const atomic_t *v) | |||
133 | 159 | ||
134 | #ifndef __ASSEMBLY__ | 160 | #ifndef __ASSEMBLY__ |
135 | 161 | ||
162 | /** | ||
163 | * atomic64_xchg - atomically exchange contents of memory with a new value | ||
164 | * @v: pointer of type atomic64_t | ||
165 | * @i: integer value to store in memory | ||
166 | * | ||
167 | * Atomically sets @v to @i and returns old @v | ||
168 | */ | ||
169 | static inline u64 atomic64_xchg(atomic64_t *v, u64 n) | ||
170 | { | ||
171 | return xchg64(&v->counter, n); | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * atomic64_cmpxchg - atomically exchange contents of memory if it matches | ||
176 | * @v: pointer of type atomic64_t | ||
177 | * @o: old value that memory should have | ||
178 | * @n: new value to write to memory if it matches | ||
179 | * | ||
180 | * Atomically checks if @v holds @o and replaces it with @n if so. | ||
181 | * Returns the old value at @v. | ||
182 | */ | ||
183 | static inline u64 atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n) | ||
184 | { | ||
185 | return cmpxchg64(&v->counter, o, n); | ||
186 | } | ||
187 | |||
136 | static inline long long atomic64_dec_if_positive(atomic64_t *v) | 188 | static inline long long atomic64_dec_if_positive(atomic64_t *v) |
137 | { | 189 | { |
138 | long long c, old, dec; | 190 | long long c, old, dec; |
diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h index e7fb5cfb9597..0d0395b1b152 100644 --- a/arch/tile/include/asm/atomic_32.h +++ b/arch/tile/include/asm/atomic_32.h | |||
@@ -22,40 +22,6 @@ | |||
22 | 22 | ||
23 | #ifndef __ASSEMBLY__ | 23 | #ifndef __ASSEMBLY__ |
24 | 24 | ||
25 | /* Tile-specific routines to support <linux/atomic.h>. */ | ||
26 | int _atomic_xchg(atomic_t *v, int n); | ||
27 | int _atomic_xchg_add(atomic_t *v, int i); | ||
28 | int _atomic_xchg_add_unless(atomic_t *v, int a, int u); | ||
29 | int _atomic_cmpxchg(atomic_t *v, int o, int n); | ||
30 | |||
31 | /** | ||
32 | * atomic_xchg - atomically exchange contents of memory with a new value | ||
33 | * @v: pointer of type atomic_t | ||
34 | * @i: integer value to store in memory | ||
35 | * | ||
36 | * Atomically sets @v to @i and returns old @v | ||
37 | */ | ||
38 | static inline int atomic_xchg(atomic_t *v, int n) | ||
39 | { | ||
40 | smp_mb(); /* barrier for proper semantics */ | ||
41 | return _atomic_xchg(v, n); | ||
42 | } | ||
43 | |||
44 | /** | ||
45 | * atomic_cmpxchg - atomically exchange contents of memory if it matches | ||
46 | * @v: pointer of type atomic_t | ||
47 | * @o: old value that memory should have | ||
48 | * @n: new value to write to memory if it matches | ||
49 | * | ||
50 | * Atomically checks if @v holds @o and replaces it with @n if so. | ||
51 | * Returns the old value at @v. | ||
52 | */ | ||
53 | static inline int atomic_cmpxchg(atomic_t *v, int o, int n) | ||
54 | { | ||
55 | smp_mb(); /* barrier for proper semantics */ | ||
56 | return _atomic_cmpxchg(v, o, n); | ||
57 | } | ||
58 | |||
59 | /** | 25 | /** |
60 | * atomic_add - add integer to atomic variable | 26 | * atomic_add - add integer to atomic variable |
61 | * @i: integer value to add | 27 | * @i: integer value to add |
@@ -65,7 +31,7 @@ static inline int atomic_cmpxchg(atomic_t *v, int o, int n) | |||
65 | */ | 31 | */ |
66 | static inline void atomic_add(int i, atomic_t *v) | 32 | static inline void atomic_add(int i, atomic_t *v) |
67 | { | 33 | { |
68 | _atomic_xchg_add(v, i); | 34 | _atomic_xchg_add(&v->counter, i); |
69 | } | 35 | } |
70 | 36 | ||
71 | /** | 37 | /** |
@@ -78,7 +44,7 @@ static inline void atomic_add(int i, atomic_t *v) | |||
78 | static inline int atomic_add_return(int i, atomic_t *v) | 44 | static inline int atomic_add_return(int i, atomic_t *v) |
79 | { | 45 | { |
80 | smp_mb(); /* barrier for proper semantics */ | 46 | smp_mb(); /* barrier for proper semantics */ |
81 | return _atomic_xchg_add(v, i) + i; | 47 | return _atomic_xchg_add(&v->counter, i) + i; |
82 | } | 48 | } |
83 | 49 | ||
84 | /** | 50 | /** |
@@ -93,7 +59,7 @@ static inline int atomic_add_return(int i, atomic_t *v) | |||
93 | static inline int __atomic_add_unless(atomic_t *v, int a, int u) | 59 | static inline int __atomic_add_unless(atomic_t *v, int a, int u) |
94 | { | 60 | { |
95 | smp_mb(); /* barrier for proper semantics */ | 61 | smp_mb(); /* barrier for proper semantics */ |
96 | return _atomic_xchg_add_unless(v, a, u); | 62 | return _atomic_xchg_add_unless(&v->counter, a, u); |
97 | } | 63 | } |
98 | 64 | ||
99 | /** | 65 | /** |
@@ -108,7 +74,7 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
108 | */ | 74 | */ |
109 | static inline void atomic_set(atomic_t *v, int n) | 75 | static inline void atomic_set(atomic_t *v, int n) |
110 | { | 76 | { |
111 | _atomic_xchg(v, n); | 77 | _atomic_xchg(&v->counter, n); |
112 | } | 78 | } |
113 | 79 | ||
114 | /* A 64bit atomic type */ | 80 | /* A 64bit atomic type */ |
@@ -119,11 +85,6 @@ typedef struct { | |||
119 | 85 | ||
120 | #define ATOMIC64_INIT(val) { (val) } | 86 | #define ATOMIC64_INIT(val) { (val) } |
121 | 87 | ||
122 | u64 _atomic64_xchg(atomic64_t *v, u64 n); | ||
123 | u64 _atomic64_xchg_add(atomic64_t *v, u64 i); | ||
124 | u64 _atomic64_xchg_add_unless(atomic64_t *v, u64 a, u64 u); | ||
125 | u64 _atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n); | ||
126 | |||
127 | /** | 88 | /** |
128 | * atomic64_read - read atomic variable | 89 | * atomic64_read - read atomic variable |
129 | * @v: pointer of type atomic64_t | 90 | * @v: pointer of type atomic64_t |
@@ -137,35 +98,7 @@ static inline u64 atomic64_read(const atomic64_t *v) | |||
137 | * Casting away const is safe since the atomic support routines | 98 | * Casting away const is safe since the atomic support routines |
138 | * do not write to memory if the value has not been modified. | 99 | * do not write to memory if the value has not been modified. |
139 | */ | 100 | */ |
140 | return _atomic64_xchg_add((atomic64_t *)v, 0); | 101 | return _atomic64_xchg_add((u64 *)&v->counter, 0); |
141 | } | ||
142 | |||
143 | /** | ||
144 | * atomic64_xchg - atomically exchange contents of memory with a new value | ||
145 | * @v: pointer of type atomic64_t | ||
146 | * @i: integer value to store in memory | ||
147 | * | ||
148 | * Atomically sets @v to @i and returns old @v | ||
149 | */ | ||
150 | static inline u64 atomic64_xchg(atomic64_t *v, u64 n) | ||
151 | { | ||
152 | smp_mb(); /* barrier for proper semantics */ | ||
153 | return _atomic64_xchg(v, n); | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * atomic64_cmpxchg - atomically exchange contents of memory if it matches | ||
158 | * @v: pointer of type atomic64_t | ||
159 | * @o: old value that memory should have | ||
160 | * @n: new value to write to memory if it matches | ||
161 | * | ||
162 | * Atomically checks if @v holds @o and replaces it with @n if so. | ||
163 | * Returns the old value at @v. | ||
164 | */ | ||
165 | static inline u64 atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n) | ||
166 | { | ||
167 | smp_mb(); /* barrier for proper semantics */ | ||
168 | return _atomic64_cmpxchg(v, o, n); | ||
169 | } | 102 | } |
170 | 103 | ||
171 | /** | 104 | /** |
@@ -177,7 +110,7 @@ static inline u64 atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n) | |||
177 | */ | 110 | */ |
178 | static inline void atomic64_add(u64 i, atomic64_t *v) | 111 | static inline void atomic64_add(u64 i, atomic64_t *v) |
179 | { | 112 | { |
180 | _atomic64_xchg_add(v, i); | 113 | _atomic64_xchg_add(&v->counter, i); |
181 | } | 114 | } |
182 | 115 | ||
183 | /** | 116 | /** |
@@ -190,7 +123,7 @@ static inline void atomic64_add(u64 i, atomic64_t *v) | |||
190 | static inline u64 atomic64_add_return(u64 i, atomic64_t *v) | 123 | static inline u64 atomic64_add_return(u64 i, atomic64_t *v) |
191 | { | 124 | { |
192 | smp_mb(); /* barrier for proper semantics */ | 125 | smp_mb(); /* barrier for proper semantics */ |
193 | return _atomic64_xchg_add(v, i) + i; | 126 | return _atomic64_xchg_add(&v->counter, i) + i; |
194 | } | 127 | } |
195 | 128 | ||
196 | /** | 129 | /** |
@@ -205,7 +138,7 @@ static inline u64 atomic64_add_return(u64 i, atomic64_t *v) | |||
205 | static inline u64 atomic64_add_unless(atomic64_t *v, u64 a, u64 u) | 138 | static inline u64 atomic64_add_unless(atomic64_t *v, u64 a, u64 u) |
206 | { | 139 | { |
207 | smp_mb(); /* barrier for proper semantics */ | 140 | smp_mb(); /* barrier for proper semantics */ |
208 | return _atomic64_xchg_add_unless(v, a, u) != u; | 141 | return _atomic64_xchg_add_unless(&v->counter, a, u) != u; |
209 | } | 142 | } |
210 | 143 | ||
211 | /** | 144 | /** |
@@ -220,7 +153,7 @@ static inline u64 atomic64_add_unless(atomic64_t *v, u64 a, u64 u) | |||
220 | */ | 153 | */ |
221 | static inline void atomic64_set(atomic64_t *v, u64 n) | 154 | static inline void atomic64_set(atomic64_t *v, u64 n) |
222 | { | 155 | { |
223 | _atomic64_xchg(v, n); | 156 | _atomic64_xchg(&v->counter, n); |
224 | } | 157 | } |
225 | 158 | ||
226 | #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) | 159 | #define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) |
@@ -252,21 +185,6 @@ static inline void atomic64_set(atomic64_t *v, u64 n) | |||
252 | * Internal definitions only beyond this point. | 185 | * Internal definitions only beyond this point. |
253 | */ | 186 | */ |
254 | 187 | ||
255 | #define ATOMIC_LOCKS_FOUND_VIA_TABLE() \ | ||
256 | (!CHIP_HAS_CBOX_HOME_MAP() && defined(CONFIG_SMP)) | ||
257 | |||
258 | #if ATOMIC_LOCKS_FOUND_VIA_TABLE() | ||
259 | |||
260 | /* Number of entries in atomic_lock_ptr[]. */ | ||
261 | #define ATOMIC_HASH_L1_SHIFT 6 | ||
262 | #define ATOMIC_HASH_L1_SIZE (1 << ATOMIC_HASH_L1_SHIFT) | ||
263 | |||
264 | /* Number of locks in each struct pointed to by atomic_lock_ptr[]. */ | ||
265 | #define ATOMIC_HASH_L2_SHIFT (CHIP_L2_LOG_LINE_SIZE() - 2) | ||
266 | #define ATOMIC_HASH_L2_SIZE (1 << ATOMIC_HASH_L2_SHIFT) | ||
267 | |||
268 | #else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */ | ||
269 | |||
270 | /* | 188 | /* |
271 | * Number of atomic locks in atomic_locks[]. Must be a power of two. | 189 | * Number of atomic locks in atomic_locks[]. Must be a power of two. |
272 | * There is no reason for more than PAGE_SIZE / 8 entries, since that | 190 | * There is no reason for more than PAGE_SIZE / 8 entries, since that |
@@ -281,8 +199,6 @@ static inline void atomic64_set(atomic64_t *v, u64 n) | |||
281 | extern int atomic_locks[]; | 199 | extern int atomic_locks[]; |
282 | #endif | 200 | #endif |
283 | 201 | ||
284 | #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */ | ||
285 | |||
286 | /* | 202 | /* |
287 | * All the code that may fault while holding an atomic lock must | 203 | * All the code that may fault while holding an atomic lock must |
288 | * place the pointer to the lock in ATOMIC_LOCK_REG so the fault code | 204 | * place the pointer to the lock in ATOMIC_LOCK_REG so the fault code |
diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h index f4500c688ffa..ad220eed05fc 100644 --- a/arch/tile/include/asm/atomic_64.h +++ b/arch/tile/include/asm/atomic_64.h | |||
@@ -32,25 +32,6 @@ | |||
32 | * on any routine which updates memory and returns a value. | 32 | * on any routine which updates memory and returns a value. |
33 | */ | 33 | */ |
34 | 34 | ||
35 | static inline int atomic_cmpxchg(atomic_t *v, int o, int n) | ||
36 | { | ||
37 | int val; | ||
38 | __insn_mtspr(SPR_CMPEXCH_VALUE, o); | ||
39 | smp_mb(); /* barrier for proper semantics */ | ||
40 | val = __insn_cmpexch4((void *)&v->counter, n); | ||
41 | smp_mb(); /* barrier for proper semantics */ | ||
42 | return val; | ||
43 | } | ||
44 | |||
45 | static inline int atomic_xchg(atomic_t *v, int n) | ||
46 | { | ||
47 | int val; | ||
48 | smp_mb(); /* barrier for proper semantics */ | ||
49 | val = __insn_exch4((void *)&v->counter, n); | ||
50 | smp_mb(); /* barrier for proper semantics */ | ||
51 | return val; | ||
52 | } | ||
53 | |||
54 | static inline void atomic_add(int i, atomic_t *v) | 35 | static inline void atomic_add(int i, atomic_t *v) |
55 | { | 36 | { |
56 | __insn_fetchadd4((void *)&v->counter, i); | 37 | __insn_fetchadd4((void *)&v->counter, i); |
@@ -72,7 +53,7 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
72 | if (oldval == u) | 53 | if (oldval == u) |
73 | break; | 54 | break; |
74 | guess = oldval; | 55 | guess = oldval; |
75 | oldval = atomic_cmpxchg(v, guess, guess + a); | 56 | oldval = cmpxchg(&v->counter, guess, guess + a); |
76 | } while (guess != oldval); | 57 | } while (guess != oldval); |
77 | return oldval; | 58 | return oldval; |
78 | } | 59 | } |
@@ -84,25 +65,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) | |||
84 | #define atomic64_read(v) ((v)->counter) | 65 | #define atomic64_read(v) ((v)->counter) |
85 | #define atomic64_set(v, i) ((v)->counter = (i)) | 66 | #define atomic64_set(v, i) ((v)->counter = (i)) |
86 | 67 | ||
87 | static inline long atomic64_cmpxchg(atomic64_t *v, long o, long n) | ||
88 | { | ||
89 | long val; | ||
90 | smp_mb(); /* barrier for proper semantics */ | ||
91 | __insn_mtspr(SPR_CMPEXCH_VALUE, o); | ||
92 | val = __insn_cmpexch((void *)&v->counter, n); | ||
93 | smp_mb(); /* barrier for proper semantics */ | ||
94 | return val; | ||
95 | } | ||
96 | |||
97 | static inline long atomic64_xchg(atomic64_t *v, long n) | ||
98 | { | ||
99 | long val; | ||
100 | smp_mb(); /* barrier for proper semantics */ | ||
101 | val = __insn_exch((void *)&v->counter, n); | ||
102 | smp_mb(); /* barrier for proper semantics */ | ||
103 | return val; | ||
104 | } | ||
105 | |||
106 | static inline void atomic64_add(long i, atomic64_t *v) | 68 | static inline void atomic64_add(long i, atomic64_t *v) |
107 | { | 69 | { |
108 | __insn_fetchadd((void *)&v->counter, i); | 70 | __insn_fetchadd((void *)&v->counter, i); |
@@ -124,7 +86,7 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u) | |||
124 | if (oldval == u) | 86 | if (oldval == u) |
125 | break; | 87 | break; |
126 | guess = oldval; | 88 | guess = oldval; |
127 | oldval = atomic64_cmpxchg(v, guess, guess + a); | 89 | oldval = cmpxchg(&v->counter, guess, guess + a); |
128 | } while (guess != oldval); | 90 | } while (guess != oldval); |
129 | return oldval != u; | 91 | return oldval != u; |
130 | } | 92 | } |
diff --git a/arch/tile/include/asm/barrier.h b/arch/tile/include/asm/barrier.h index 990a217a0b72..a9a73da5865d 100644 --- a/arch/tile/include/asm/barrier.h +++ b/arch/tile/include/asm/barrier.h | |||
@@ -77,7 +77,6 @@ | |||
77 | 77 | ||
78 | #define __sync() __insn_mf() | 78 | #define __sync() __insn_mf() |
79 | 79 | ||
80 | #if !CHIP_HAS_MF_WAITS_FOR_VICTIMS() | ||
81 | #include <hv/syscall_public.h> | 80 | #include <hv/syscall_public.h> |
82 | /* | 81 | /* |
83 | * Issue an uncacheable load to each memory controller, then | 82 | * Issue an uncacheable load to each memory controller, then |
@@ -96,7 +95,6 @@ static inline void __mb_incoherent(void) | |||
96 | "r20", "r21", "r22", "r23", "r24", | 95 | "r20", "r21", "r22", "r23", "r24", |
97 | "r25", "r26", "r27", "r28", "r29"); | 96 | "r25", "r26", "r27", "r28", "r29"); |
98 | } | 97 | } |
99 | #endif | ||
100 | 98 | ||
101 | /* Fence to guarantee visibility of stores to incoherent memory. */ | 99 | /* Fence to guarantee visibility of stores to incoherent memory. */ |
102 | static inline void | 100 | static inline void |
@@ -104,7 +102,6 @@ mb_incoherent(void) | |||
104 | { | 102 | { |
105 | __insn_mf(); | 103 | __insn_mf(); |
106 | 104 | ||
107 | #if !CHIP_HAS_MF_WAITS_FOR_VICTIMS() | ||
108 | { | 105 | { |
109 | #if CHIP_HAS_TILE_WRITE_PENDING() | 106 | #if CHIP_HAS_TILE_WRITE_PENDING() |
110 | const unsigned long WRITE_TIMEOUT_CYCLES = 400; | 107 | const unsigned long WRITE_TIMEOUT_CYCLES = 400; |
@@ -116,7 +113,6 @@ mb_incoherent(void) | |||
116 | #endif /* CHIP_HAS_TILE_WRITE_PENDING() */ | 113 | #endif /* CHIP_HAS_TILE_WRITE_PENDING() */ |
117 | (void) __mb_incoherent(); | 114 | (void) __mb_incoherent(); |
118 | } | 115 | } |
119 | #endif /* CHIP_HAS_MF_WAITS_FOR_VICTIMS() */ | ||
120 | } | 116 | } |
121 | 117 | ||
122 | #define fast_wmb() __sync() | 118 | #define fast_wmb() __sync() |
diff --git a/arch/tile/include/asm/bitops.h b/arch/tile/include/asm/bitops.h index bd186c4eaa50..d5a206865036 100644 --- a/arch/tile/include/asm/bitops.h +++ b/arch/tile/include/asm/bitops.h | |||
@@ -29,17 +29,6 @@ | |||
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | /** | 31 | /** |
32 | * __ffs - find first set bit in word | ||
33 | * @word: The word to search | ||
34 | * | ||
35 | * Undefined if no set bit exists, so code should check against 0 first. | ||
36 | */ | ||
37 | static inline unsigned long __ffs(unsigned long word) | ||
38 | { | ||
39 | return __builtin_ctzl(word); | ||
40 | } | ||
41 | |||
42 | /** | ||
43 | * ffz - find first zero bit in word | 32 | * ffz - find first zero bit in word |
44 | * @word: The word to search | 33 | * @word: The word to search |
45 | * | 34 | * |
@@ -50,33 +39,6 @@ static inline unsigned long ffz(unsigned long word) | |||
50 | return __builtin_ctzl(~word); | 39 | return __builtin_ctzl(~word); |
51 | } | 40 | } |
52 | 41 | ||
53 | /** | ||
54 | * __fls - find last set bit in word | ||
55 | * @word: The word to search | ||
56 | * | ||
57 | * Undefined if no set bit exists, so code should check against 0 first. | ||
58 | */ | ||
59 | static inline unsigned long __fls(unsigned long word) | ||
60 | { | ||
61 | return (sizeof(word) * 8) - 1 - __builtin_clzl(word); | ||
62 | } | ||
63 | |||
64 | /** | ||
65 | * ffs - find first set bit in word | ||
66 | * @x: the word to search | ||
67 | * | ||
68 | * This is defined the same way as the libc and compiler builtin ffs | ||
69 | * routines, therefore differs in spirit from the other bitops. | ||
70 | * | ||
71 | * ffs(value) returns 0 if value is 0 or the position of the first | ||
72 | * set bit if value is nonzero. The first (least significant) bit | ||
73 | * is at position 1. | ||
74 | */ | ||
75 | static inline int ffs(int x) | ||
76 | { | ||
77 | return __builtin_ffs(x); | ||
78 | } | ||
79 | |||
80 | static inline int fls64(__u64 w) | 42 | static inline int fls64(__u64 w) |
81 | { | 43 | { |
82 | return (sizeof(__u64) * 8) - __builtin_clzll(w); | 44 | return (sizeof(__u64) * 8) - __builtin_clzll(w); |
@@ -118,6 +80,9 @@ static inline unsigned long __arch_hweight64(__u64 w) | |||
118 | return __builtin_popcountll(w); | 80 | return __builtin_popcountll(w); |
119 | } | 81 | } |
120 | 82 | ||
83 | #include <asm-generic/bitops/builtin-__ffs.h> | ||
84 | #include <asm-generic/bitops/builtin-__fls.h> | ||
85 | #include <asm-generic/bitops/builtin-ffs.h> | ||
121 | #include <asm-generic/bitops/const_hweight.h> | 86 | #include <asm-generic/bitops/const_hweight.h> |
122 | #include <asm-generic/bitops/lock.h> | 87 | #include <asm-generic/bitops/lock.h> |
123 | #include <asm-generic/bitops/find.h> | 88 | #include <asm-generic/bitops/find.h> |
diff --git a/arch/tile/include/asm/bitops_32.h b/arch/tile/include/asm/bitops_32.h index ddc4c1efde43..386865ad2f55 100644 --- a/arch/tile/include/asm/bitops_32.h +++ b/arch/tile/include/asm/bitops_32.h | |||
@@ -16,7 +16,7 @@ | |||
16 | #define _ASM_TILE_BITOPS_32_H | 16 | #define _ASM_TILE_BITOPS_32_H |
17 | 17 | ||
18 | #include <linux/compiler.h> | 18 | #include <linux/compiler.h> |
19 | #include <linux/atomic.h> | 19 | #include <asm/barrier.h> |
20 | 20 | ||
21 | /* Tile-specific routines to support <asm/bitops.h>. */ | 21 | /* Tile-specific routines to support <asm/bitops.h>. */ |
22 | unsigned long _atomic_or(volatile unsigned long *p, unsigned long mask); | 22 | unsigned long _atomic_or(volatile unsigned long *p, unsigned long mask); |
diff --git a/arch/tile/include/asm/bitops_64.h b/arch/tile/include/asm/bitops_64.h index 60b87ee54fb8..ad34cd056085 100644 --- a/arch/tile/include/asm/bitops_64.h +++ b/arch/tile/include/asm/bitops_64.h | |||
@@ -16,7 +16,7 @@ | |||
16 | #define _ASM_TILE_BITOPS_64_H | 16 | #define _ASM_TILE_BITOPS_64_H |
17 | 17 | ||
18 | #include <linux/compiler.h> | 18 | #include <linux/compiler.h> |
19 | #include <linux/atomic.h> | 19 | #include <asm/cmpxchg.h> |
20 | 20 | ||
21 | /* See <asm/bitops.h> for API comments. */ | 21 | /* See <asm/bitops.h> for API comments. */ |
22 | 22 | ||
@@ -44,8 +44,7 @@ static inline void change_bit(unsigned nr, volatile unsigned long *addr) | |||
44 | oldval = *addr; | 44 | oldval = *addr; |
45 | do { | 45 | do { |
46 | guess = oldval; | 46 | guess = oldval; |
47 | oldval = atomic64_cmpxchg((atomic64_t *)addr, | 47 | oldval = cmpxchg(addr, guess, guess ^ mask); |
48 | guess, guess ^ mask); | ||
49 | } while (guess != oldval); | 48 | } while (guess != oldval); |
50 | } | 49 | } |
51 | 50 | ||
@@ -90,8 +89,7 @@ static inline int test_and_change_bit(unsigned nr, | |||
90 | oldval = *addr; | 89 | oldval = *addr; |
91 | do { | 90 | do { |
92 | guess = oldval; | 91 | guess = oldval; |
93 | oldval = atomic64_cmpxchg((atomic64_t *)addr, | 92 | oldval = cmpxchg(addr, guess, guess ^ mask); |
94 | guess, guess ^ mask); | ||
95 | } while (guess != oldval); | 93 | } while (guess != oldval); |
96 | return (oldval & mask) != 0; | 94 | return (oldval & mask) != 0; |
97 | } | 95 | } |
diff --git a/arch/tile/include/asm/cache.h b/arch/tile/include/asm/cache.h index a9a529964e07..6160761d5f61 100644 --- a/arch/tile/include/asm/cache.h +++ b/arch/tile/include/asm/cache.h | |||
@@ -49,9 +49,16 @@ | |||
49 | #define __read_mostly __attribute__((__section__(".data..read_mostly"))) | 49 | #define __read_mostly __attribute__((__section__(".data..read_mostly"))) |
50 | 50 | ||
51 | /* | 51 | /* |
52 | * Attribute for data that is kept read/write coherent until the end of | 52 | * Originally we used small TLB pages for kernel data and grouped some |
53 | * initialization, then bumped to read/only incoherent for performance. | 53 | * things together as "write once", enforcing the property at the end |
54 | * of initialization by making those pages read-only and non-coherent. | ||
55 | * This allowed better cache utilization since cache inclusion did not | ||
56 | * need to be maintained. However, to do this requires an extra TLB | ||
57 | * entry, which on balance is more of a performance hit than the | ||
58 | * non-coherence is a performance gain, so we now just make "read | ||
59 | * mostly" and "write once" be synonyms. We keep the attribute | ||
60 | * separate in case we change our minds at a future date. | ||
54 | */ | 61 | */ |
55 | #define __write_once __attribute__((__section__(".w1data"))) | 62 | #define __write_once __read_mostly |
56 | 63 | ||
57 | #endif /* _ASM_TILE_CACHE_H */ | 64 | #endif /* _ASM_TILE_CACHE_H */ |
diff --git a/arch/tile/include/asm/cacheflush.h b/arch/tile/include/asm/cacheflush.h index 0fc63c488edf..92ee4c8a4f76 100644 --- a/arch/tile/include/asm/cacheflush.h +++ b/arch/tile/include/asm/cacheflush.h | |||
@@ -75,23 +75,6 @@ static inline void copy_to_user_page(struct vm_area_struct *vma, | |||
75 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ | 75 | #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ |
76 | memcpy((dst), (src), (len)) | 76 | memcpy((dst), (src), (len)) |
77 | 77 | ||
78 | /* | ||
79 | * Invalidate a VA range; pads to L2 cacheline boundaries. | ||
80 | * | ||
81 | * Note that on TILE64, __inv_buffer() actually flushes modified | ||
82 | * cache lines in addition to invalidating them, i.e., it's the | ||
83 | * same as __finv_buffer(). | ||
84 | */ | ||
85 | static inline void __inv_buffer(void *buffer, size_t size) | ||
86 | { | ||
87 | char *next = (char *)((long)buffer & -L2_CACHE_BYTES); | ||
88 | char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size); | ||
89 | while (next < finish) { | ||
90 | __insn_inv(next); | ||
91 | next += CHIP_INV_STRIDE(); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | /* Flush a VA range; pads to L2 cacheline boundaries. */ | 78 | /* Flush a VA range; pads to L2 cacheline boundaries. */ |
96 | static inline void __flush_buffer(void *buffer, size_t size) | 79 | static inline void __flush_buffer(void *buffer, size_t size) |
97 | { | 80 | { |
@@ -115,13 +98,6 @@ static inline void __finv_buffer(void *buffer, size_t size) | |||
115 | } | 98 | } |
116 | 99 | ||
117 | 100 | ||
118 | /* Invalidate a VA range and wait for it to be complete. */ | ||
119 | static inline void inv_buffer(void *buffer, size_t size) | ||
120 | { | ||
121 | __inv_buffer(buffer, size); | ||
122 | mb(); | ||
123 | } | ||
124 | |||
125 | /* | 101 | /* |
126 | * Flush a locally-homecached VA range and wait for the evicted | 102 | * Flush a locally-homecached VA range and wait for the evicted |
127 | * cachelines to hit memory. | 103 | * cachelines to hit memory. |
@@ -142,6 +118,26 @@ static inline void finv_buffer_local(void *buffer, size_t size) | |||
142 | mb_incoherent(); | 118 | mb_incoherent(); |
143 | } | 119 | } |
144 | 120 | ||
121 | #ifdef __tilepro__ | ||
122 | /* Invalidate a VA range; pads to L2 cacheline boundaries. */ | ||
123 | static inline void __inv_buffer(void *buffer, size_t size) | ||
124 | { | ||
125 | char *next = (char *)((long)buffer & -L2_CACHE_BYTES); | ||
126 | char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size); | ||
127 | while (next < finish) { | ||
128 | __insn_inv(next); | ||
129 | next += CHIP_INV_STRIDE(); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | /* Invalidate a VA range and wait for it to be complete. */ | ||
134 | static inline void inv_buffer(void *buffer, size_t size) | ||
135 | { | ||
136 | __inv_buffer(buffer, size); | ||
137 | mb(); | ||
138 | } | ||
139 | #endif | ||
140 | |||
145 | /* | 141 | /* |
146 | * Flush and invalidate a VA range that is homed remotely, waiting | 142 | * Flush and invalidate a VA range that is homed remotely, waiting |
147 | * until the memory controller holds the flushed values. If "hfh" is | 143 | * until the memory controller holds the flushed values. If "hfh" is |
diff --git a/arch/tile/include/asm/cmpxchg.h b/arch/tile/include/asm/cmpxchg.h index 276f067e3640..4001d5eab4bb 100644 --- a/arch/tile/include/asm/cmpxchg.h +++ b/arch/tile/include/asm/cmpxchg.h | |||
@@ -20,53 +20,108 @@ | |||
20 | 20 | ||
21 | #ifndef __ASSEMBLY__ | 21 | #ifndef __ASSEMBLY__ |
22 | 22 | ||
23 | /* Nonexistent functions intended to cause link errors. */ | 23 | #include <asm/barrier.h> |
24 | extern unsigned long __xchg_called_with_bad_pointer(void); | ||
25 | extern unsigned long __cmpxchg_called_with_bad_pointer(void); | ||
26 | 24 | ||
27 | #define xchg(ptr, x) \ | 25 | /* Nonexistent functions intended to cause compile errors. */ |
26 | extern void __xchg_called_with_bad_pointer(void) | ||
27 | __compiletime_error("Bad argument size for xchg"); | ||
28 | extern void __cmpxchg_called_with_bad_pointer(void) | ||
29 | __compiletime_error("Bad argument size for cmpxchg"); | ||
30 | |||
31 | #ifndef __tilegx__ | ||
32 | |||
33 | /* Note the _atomic_xxx() routines include a final mb(). */ | ||
34 | int _atomic_xchg(int *ptr, int n); | ||
35 | int _atomic_xchg_add(int *v, int i); | ||
36 | int _atomic_xchg_add_unless(int *v, int a, int u); | ||
37 | int _atomic_cmpxchg(int *ptr, int o, int n); | ||
38 | u64 _atomic64_xchg(u64 *v, u64 n); | ||
39 | u64 _atomic64_xchg_add(u64 *v, u64 i); | ||
40 | u64 _atomic64_xchg_add_unless(u64 *v, u64 a, u64 u); | ||
41 | u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n); | ||
42 | |||
43 | #define xchg(ptr, n) \ | ||
44 | ({ \ | ||
45 | if (sizeof(*(ptr)) != 4) \ | ||
46 | __xchg_called_with_bad_pointer(); \ | ||
47 | smp_mb(); \ | ||
48 | (typeof(*(ptr)))_atomic_xchg((int *)(ptr), (int)(n)); \ | ||
49 | }) | ||
50 | |||
51 | #define cmpxchg(ptr, o, n) \ | ||
52 | ({ \ | ||
53 | if (sizeof(*(ptr)) != 4) \ | ||
54 | __cmpxchg_called_with_bad_pointer(); \ | ||
55 | smp_mb(); \ | ||
56 | (typeof(*(ptr)))_atomic_cmpxchg((int *)ptr, (int)o, (int)n); \ | ||
57 | }) | ||
58 | |||
59 | #define xchg64(ptr, n) \ | ||
60 | ({ \ | ||
61 | if (sizeof(*(ptr)) != 8) \ | ||
62 | __xchg_called_with_bad_pointer(); \ | ||
63 | smp_mb(); \ | ||
64 | (typeof(*(ptr)))_atomic64_xchg((u64 *)(ptr), (u64)(n)); \ | ||
65 | }) | ||
66 | |||
67 | #define cmpxchg64(ptr, o, n) \ | ||
68 | ({ \ | ||
69 | if (sizeof(*(ptr)) != 8) \ | ||
70 | __cmpxchg_called_with_bad_pointer(); \ | ||
71 | smp_mb(); \ | ||
72 | (typeof(*(ptr)))_atomic64_cmpxchg((u64 *)ptr, (u64)o, (u64)n); \ | ||
73 | }) | ||
74 | |||
75 | #else | ||
76 | |||
77 | #define xchg(ptr, n) \ | ||
28 | ({ \ | 78 | ({ \ |
29 | typeof(*(ptr)) __x; \ | 79 | typeof(*(ptr)) __x; \ |
80 | smp_mb(); \ | ||
30 | switch (sizeof(*(ptr))) { \ | 81 | switch (sizeof(*(ptr))) { \ |
31 | case 4: \ | 82 | case 4: \ |
32 | __x = (typeof(__x))(typeof(__x-__x))atomic_xchg( \ | 83 | __x = (typeof(__x))(unsigned long) \ |
33 | (atomic_t *)(ptr), \ | 84 | __insn_exch4((ptr), (u32)(unsigned long)(n)); \ |
34 | (u32)(typeof((x)-(x)))(x)); \ | ||
35 | break; \ | 85 | break; \ |
36 | case 8: \ | 86 | case 8: \ |
37 | __x = (typeof(__x))(typeof(__x-__x))atomic64_xchg( \ | 87 | __x = (typeof(__x)) \ |
38 | (atomic64_t *)(ptr), \ | 88 | __insn_exch((ptr), (unsigned long)(n)); \ |
39 | (u64)(typeof((x)-(x)))(x)); \ | ||
40 | break; \ | 89 | break; \ |
41 | default: \ | 90 | default: \ |
42 | __xchg_called_with_bad_pointer(); \ | 91 | __xchg_called_with_bad_pointer(); \ |
92 | break; \ | ||
43 | } \ | 93 | } \ |
94 | smp_mb(); \ | ||
44 | __x; \ | 95 | __x; \ |
45 | }) | 96 | }) |
46 | 97 | ||
47 | #define cmpxchg(ptr, o, n) \ | 98 | #define cmpxchg(ptr, o, n) \ |
48 | ({ \ | 99 | ({ \ |
49 | typeof(*(ptr)) __x; \ | 100 | typeof(*(ptr)) __x; \ |
101 | __insn_mtspr(SPR_CMPEXCH_VALUE, (unsigned long)(o)); \ | ||
102 | smp_mb(); \ | ||
50 | switch (sizeof(*(ptr))) { \ | 103 | switch (sizeof(*(ptr))) { \ |
51 | case 4: \ | 104 | case 4: \ |
52 | __x = (typeof(__x))(typeof(__x-__x))atomic_cmpxchg( \ | 105 | __x = (typeof(__x))(unsigned long) \ |
53 | (atomic_t *)(ptr), \ | 106 | __insn_cmpexch4((ptr), (u32)(unsigned long)(n)); \ |
54 | (u32)(typeof((o)-(o)))(o), \ | ||
55 | (u32)(typeof((n)-(n)))(n)); \ | ||
56 | break; \ | 107 | break; \ |
57 | case 8: \ | 108 | case 8: \ |
58 | __x = (typeof(__x))(typeof(__x-__x))atomic64_cmpxchg( \ | 109 | __x = (typeof(__x))__insn_cmpexch((ptr), (u64)(n)); \ |
59 | (atomic64_t *)(ptr), \ | ||
60 | (u64)(typeof((o)-(o)))(o), \ | ||
61 | (u64)(typeof((n)-(n)))(n)); \ | ||
62 | break; \ | 110 | break; \ |
63 | default: \ | 111 | default: \ |
64 | __cmpxchg_called_with_bad_pointer(); \ | 112 | __cmpxchg_called_with_bad_pointer(); \ |
113 | break; \ | ||
65 | } \ | 114 | } \ |
115 | smp_mb(); \ | ||
66 | __x; \ | 116 | __x; \ |
67 | }) | 117 | }) |
68 | 118 | ||
69 | #define tas(ptr) (xchg((ptr), 1)) | 119 | #define xchg64 xchg |
120 | #define cmpxchg64 cmpxchg | ||
121 | |||
122 | #endif | ||
123 | |||
124 | #define tas(ptr) xchg((ptr), 1) | ||
70 | 125 | ||
71 | #endif /* __ASSEMBLY__ */ | 126 | #endif /* __ASSEMBLY__ */ |
72 | 127 | ||
diff --git a/arch/tile/include/asm/device.h b/arch/tile/include/asm/device.h index 5182705bd056..6ab8bf146d4c 100644 --- a/arch/tile/include/asm/device.h +++ b/arch/tile/include/asm/device.h | |||
@@ -23,7 +23,10 @@ struct dev_archdata { | |||
23 | /* Offset of the DMA address from the PA. */ | 23 | /* Offset of the DMA address from the PA. */ |
24 | dma_addr_t dma_offset; | 24 | dma_addr_t dma_offset; |
25 | 25 | ||
26 | /* Highest DMA address that can be generated by this device. */ | 26 | /* |
27 | * Highest DMA address that can be generated by devices that | ||
28 | * have limited DMA capability, i.e. non 64-bit capable. | ||
29 | */ | ||
27 | dma_addr_t max_direct_dma_addr; | 30 | dma_addr_t max_direct_dma_addr; |
28 | }; | 31 | }; |
29 | 32 | ||
diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h index f2ff191376b4..1eae359d8315 100644 --- a/arch/tile/include/asm/dma-mapping.h +++ b/arch/tile/include/asm/dma-mapping.h | |||
@@ -20,9 +20,14 @@ | |||
20 | #include <linux/cache.h> | 20 | #include <linux/cache.h> |
21 | #include <linux/io.h> | 21 | #include <linux/io.h> |
22 | 22 | ||
23 | #ifdef __tilegx__ | ||
24 | #define ARCH_HAS_DMA_GET_REQUIRED_MASK | ||
25 | #endif | ||
26 | |||
23 | extern struct dma_map_ops *tile_dma_map_ops; | 27 | extern struct dma_map_ops *tile_dma_map_ops; |
24 | extern struct dma_map_ops *gx_pci_dma_map_ops; | 28 | extern struct dma_map_ops *gx_pci_dma_map_ops; |
25 | extern struct dma_map_ops *gx_legacy_pci_dma_map_ops; | 29 | extern struct dma_map_ops *gx_legacy_pci_dma_map_ops; |
30 | extern struct dma_map_ops *gx_hybrid_pci_dma_map_ops; | ||
26 | 31 | ||
27 | static inline struct dma_map_ops *get_dma_ops(struct device *dev) | 32 | static inline struct dma_map_ops *get_dma_ops(struct device *dev) |
28 | { | 33 | { |
@@ -44,12 +49,12 @@ static inline void set_dma_offset(struct device *dev, dma_addr_t off) | |||
44 | 49 | ||
45 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) | 50 | static inline dma_addr_t phys_to_dma(struct device *dev, phys_addr_t paddr) |
46 | { | 51 | { |
47 | return paddr + get_dma_offset(dev); | 52 | return paddr; |
48 | } | 53 | } |
49 | 54 | ||
50 | static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) | 55 | static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) |
51 | { | 56 | { |
52 | return daddr - get_dma_offset(dev); | 57 | return daddr; |
53 | } | 58 | } |
54 | 59 | ||
55 | static inline void dma_mark_clean(void *addr, size_t size) {} | 60 | static inline void dma_mark_clean(void *addr, size_t size) {} |
@@ -87,11 +92,19 @@ dma_set_mask(struct device *dev, u64 mask) | |||
87 | { | 92 | { |
88 | struct dma_map_ops *dma_ops = get_dma_ops(dev); | 93 | struct dma_map_ops *dma_ops = get_dma_ops(dev); |
89 | 94 | ||
90 | /* Handle legacy PCI devices with limited memory addressability. */ | 95 | /* |
91 | if ((dma_ops == gx_pci_dma_map_ops) && (mask <= DMA_BIT_MASK(32))) { | 96 | * For PCI devices with 64-bit DMA addressing capability, promote |
92 | set_dma_ops(dev, gx_legacy_pci_dma_map_ops); | 97 | * the dma_ops to hybrid, with the consistent memory DMA space limited |
93 | set_dma_offset(dev, 0); | 98 | * to 32-bit. For 32-bit capable devices, limit the streaming DMA |
94 | if (mask > dev->archdata.max_direct_dma_addr) | 99 | * address range to max_direct_dma_addr. |
100 | */ | ||
101 | if (dma_ops == gx_pci_dma_map_ops || | ||
102 | dma_ops == gx_hybrid_pci_dma_map_ops || | ||
103 | dma_ops == gx_legacy_pci_dma_map_ops) { | ||
104 | if (mask == DMA_BIT_MASK(64) && | ||
105 | dma_ops == gx_legacy_pci_dma_map_ops) | ||
106 | set_dma_ops(dev, gx_hybrid_pci_dma_map_ops); | ||
107 | else if (mask > dev->archdata.max_direct_dma_addr) | ||
95 | mask = dev->archdata.max_direct_dma_addr; | 108 | mask = dev->archdata.max_direct_dma_addr; |
96 | } | 109 | } |
97 | 110 | ||
diff --git a/arch/tile/include/asm/elf.h b/arch/tile/include/asm/elf.h index ff8a93408823..41d9878a9686 100644 --- a/arch/tile/include/asm/elf.h +++ b/arch/tile/include/asm/elf.h | |||
@@ -30,7 +30,6 @@ typedef unsigned long elf_greg_t; | |||
30 | #define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t)) | 30 | #define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t)) |
31 | typedef elf_greg_t elf_gregset_t[ELF_NGREG]; | 31 | typedef elf_greg_t elf_gregset_t[ELF_NGREG]; |
32 | 32 | ||
33 | #define EM_TILE64 187 | ||
34 | #define EM_TILEPRO 188 | 33 | #define EM_TILEPRO 188 |
35 | #define EM_TILEGX 191 | 34 | #define EM_TILEGX 191 |
36 | 35 | ||
@@ -132,6 +131,15 @@ extern int dump_task_regs(struct task_struct *, elf_gregset_t *); | |||
132 | struct linux_binprm; | 131 | struct linux_binprm; |
133 | extern int arch_setup_additional_pages(struct linux_binprm *bprm, | 132 | extern int arch_setup_additional_pages(struct linux_binprm *bprm, |
134 | int executable_stack); | 133 | int executable_stack); |
134 | #define ARCH_DLINFO \ | ||
135 | do { \ | ||
136 | NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \ | ||
137 | } while (0) | ||
138 | |||
139 | struct mm_struct; | ||
140 | extern unsigned long arch_randomize_brk(struct mm_struct *mm); | ||
141 | #define arch_randomize_brk arch_randomize_brk | ||
142 | |||
135 | #ifdef CONFIG_COMPAT | 143 | #ifdef CONFIG_COMPAT |
136 | 144 | ||
137 | #define COMPAT_ELF_PLATFORM "tilegx-m32" | 145 | #define COMPAT_ELF_PLATFORM "tilegx-m32" |
diff --git a/arch/tile/include/asm/fixmap.h b/arch/tile/include/asm/fixmap.h index e16dbf929cb5..c6b9c1b38fd1 100644 --- a/arch/tile/include/asm/fixmap.h +++ b/arch/tile/include/asm/fixmap.h | |||
@@ -78,14 +78,6 @@ enum fixed_addresses { | |||
78 | #endif | 78 | #endif |
79 | }; | 79 | }; |
80 | 80 | ||
81 | extern void __set_fixmap(enum fixed_addresses idx, | ||
82 | unsigned long phys, pgprot_t flags); | ||
83 | |||
84 | #define set_fixmap(idx, phys) \ | ||
85 | __set_fixmap(idx, phys, PAGE_KERNEL) | ||
86 | #define clear_fixmap(idx) \ | ||
87 | __set_fixmap(idx, 0, __pgprot(0)) | ||
88 | |||
89 | #define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) | 81 | #define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) |
90 | #define __FIXADDR_BOOT_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) | 82 | #define __FIXADDR_BOOT_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) |
91 | #define FIXADDR_START (FIXADDR_TOP + PAGE_SIZE - __FIXADDR_SIZE) | 83 | #define FIXADDR_START (FIXADDR_TOP + PAGE_SIZE - __FIXADDR_SIZE) |
diff --git a/arch/tile/include/asm/ftrace.h b/arch/tile/include/asm/ftrace.h index 461459b06d98..13a9bb81a8ab 100644 --- a/arch/tile/include/asm/ftrace.h +++ b/arch/tile/include/asm/ftrace.h | |||
@@ -15,6 +15,26 @@ | |||
15 | #ifndef _ASM_TILE_FTRACE_H | 15 | #ifndef _ASM_TILE_FTRACE_H |
16 | #define _ASM_TILE_FTRACE_H | 16 | #define _ASM_TILE_FTRACE_H |
17 | 17 | ||
18 | /* empty */ | 18 | #ifdef CONFIG_FUNCTION_TRACER |
19 | |||
20 | #define MCOUNT_ADDR ((unsigned long)(__mcount)) | ||
21 | #define MCOUNT_INSN_SIZE 8 /* sizeof mcount call */ | ||
22 | |||
23 | #ifndef __ASSEMBLY__ | ||
24 | extern void __mcount(void); | ||
25 | |||
26 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
27 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | ||
28 | { | ||
29 | return addr; | ||
30 | } | ||
31 | |||
32 | struct dyn_arch_ftrace { | ||
33 | }; | ||
34 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
35 | |||
36 | #endif /* __ASSEMBLY__ */ | ||
37 | |||
38 | #endif /* CONFIG_FUNCTION_TRACER */ | ||
19 | 39 | ||
20 | #endif /* _ASM_TILE_FTRACE_H */ | 40 | #endif /* _ASM_TILE_FTRACE_H */ |
diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h index 5909ac3d7218..1a6ef1b69cb1 100644 --- a/arch/tile/include/asm/futex.h +++ b/arch/tile/include/asm/futex.h | |||
@@ -43,6 +43,7 @@ | |||
43 | ".pushsection .fixup,\"ax\"\n" \ | 43 | ".pushsection .fixup,\"ax\"\n" \ |
44 | "0: { movei %0, %5; j 9f }\n" \ | 44 | "0: { movei %0, %5; j 9f }\n" \ |
45 | ".section __ex_table,\"a\"\n" \ | 45 | ".section __ex_table,\"a\"\n" \ |
46 | ".align 8\n" \ | ||
46 | ".quad 1b, 0b\n" \ | 47 | ".quad 1b, 0b\n" \ |
47 | ".popsection\n" \ | 48 | ".popsection\n" \ |
48 | "9:" \ | 49 | "9:" \ |
diff --git a/arch/tile/include/asm/homecache.h b/arch/tile/include/asm/homecache.h index 7b7771328642..7ddd1b8d6910 100644 --- a/arch/tile/include/asm/homecache.h +++ b/arch/tile/include/asm/homecache.h | |||
@@ -33,8 +33,7 @@ struct zone; | |||
33 | 33 | ||
34 | /* | 34 | /* |
35 | * Is this page immutable (unwritable) and thus able to be cached more | 35 | * Is this page immutable (unwritable) and thus able to be cached more |
36 | * widely than would otherwise be possible? On tile64 this means we | 36 | * widely than would otherwise be possible? This means we have "nc" set. |
37 | * mark the PTE to cache locally; on tilepro it means we have "nc" set. | ||
38 | */ | 37 | */ |
39 | #define PAGE_HOME_IMMUTABLE -2 | 38 | #define PAGE_HOME_IMMUTABLE -2 |
40 | 39 | ||
@@ -44,16 +43,8 @@ struct zone; | |||
44 | */ | 43 | */ |
45 | #define PAGE_HOME_INCOHERENT -3 | 44 | #define PAGE_HOME_INCOHERENT -3 |
46 | 45 | ||
47 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
48 | /* Home for the page is distributed via hash-for-home. */ | 46 | /* Home for the page is distributed via hash-for-home. */ |
49 | #define PAGE_HOME_HASH -4 | 47 | #define PAGE_HOME_HASH -4 |
50 | #endif | ||
51 | |||
52 | /* Homing is unknown or unspecified. Not valid for page_home(). */ | ||
53 | #define PAGE_HOME_UNKNOWN -5 | ||
54 | |||
55 | /* Home on the current cpu. Not valid for page_home(). */ | ||
56 | #define PAGE_HOME_HERE -6 | ||
57 | 48 | ||
58 | /* Support wrapper to use instead of explicit hv_flush_remote(). */ | 49 | /* Support wrapper to use instead of explicit hv_flush_remote(). */ |
59 | extern void flush_remote(unsigned long cache_pfn, unsigned long cache_length, | 50 | extern void flush_remote(unsigned long cache_pfn, unsigned long cache_length, |
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h index 31672918064c..9fe434969fab 100644 --- a/arch/tile/include/asm/io.h +++ b/arch/tile/include/asm/io.h | |||
@@ -19,7 +19,8 @@ | |||
19 | #include <linux/bug.h> | 19 | #include <linux/bug.h> |
20 | #include <asm/page.h> | 20 | #include <asm/page.h> |
21 | 21 | ||
22 | #define IO_SPACE_LIMIT 0xfffffffful | 22 | /* Maximum PCI I/O space address supported. */ |
23 | #define IO_SPACE_LIMIT 0xffffffff | ||
23 | 24 | ||
24 | /* | 25 | /* |
25 | * Convert a physical pointer to a virtual kernel pointer for /dev/mem | 26 | * Convert a physical pointer to a virtual kernel pointer for /dev/mem |
@@ -254,7 +255,7 @@ static inline void writeq(u64 val, unsigned long addr) | |||
254 | 255 | ||
255 | static inline void memset_io(volatile void *dst, int val, size_t len) | 256 | static inline void memset_io(volatile void *dst, int val, size_t len) |
256 | { | 257 | { |
257 | int x; | 258 | size_t x; |
258 | BUG_ON((unsigned long)dst & 0x3); | 259 | BUG_ON((unsigned long)dst & 0x3); |
259 | val = (val & 0xff) * 0x01010101; | 260 | val = (val & 0xff) * 0x01010101; |
260 | for (x = 0; x < len; x += 4) | 261 | for (x = 0; x < len; x += 4) |
@@ -264,7 +265,7 @@ static inline void memset_io(volatile void *dst, int val, size_t len) | |||
264 | static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, | 265 | static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, |
265 | size_t len) | 266 | size_t len) |
266 | { | 267 | { |
267 | int x; | 268 | size_t x; |
268 | BUG_ON((unsigned long)src & 0x3); | 269 | BUG_ON((unsigned long)src & 0x3); |
269 | for (x = 0; x < len; x += 4) | 270 | for (x = 0; x < len; x += 4) |
270 | *(u32 *)(dst + x) = readl(src + x); | 271 | *(u32 *)(dst + x) = readl(src + x); |
@@ -273,7 +274,7 @@ static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, | |||
273 | static inline void memcpy_toio(volatile void __iomem *dst, const void *src, | 274 | static inline void memcpy_toio(volatile void __iomem *dst, const void *src, |
274 | size_t len) | 275 | size_t len) |
275 | { | 276 | { |
276 | int x; | 277 | size_t x; |
277 | BUG_ON((unsigned long)dst & 0x3); | 278 | BUG_ON((unsigned long)dst & 0x3); |
278 | for (x = 0; x < len; x += 4) | 279 | for (x = 0; x < len; x += 4) |
279 | writel(*(u32 *)(src + x), dst + x); | 280 | writel(*(u32 *)(src + x), dst + x); |
@@ -281,8 +282,108 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, | |||
281 | 282 | ||
282 | #endif | 283 | #endif |
283 | 284 | ||
285 | #if CHIP_HAS_MMIO() && defined(CONFIG_TILE_PCI_IO) | ||
286 | |||
287 | static inline u8 inb(unsigned long addr) | ||
288 | { | ||
289 | return readb((volatile void __iomem *) addr); | ||
290 | } | ||
291 | |||
292 | static inline u16 inw(unsigned long addr) | ||
293 | { | ||
294 | return readw((volatile void __iomem *) addr); | ||
295 | } | ||
296 | |||
297 | static inline u32 inl(unsigned long addr) | ||
298 | { | ||
299 | return readl((volatile void __iomem *) addr); | ||
300 | } | ||
301 | |||
302 | static inline void outb(u8 b, unsigned long addr) | ||
303 | { | ||
304 | writeb(b, (volatile void __iomem *) addr); | ||
305 | } | ||
306 | |||
307 | static inline void outw(u16 b, unsigned long addr) | ||
308 | { | ||
309 | writew(b, (volatile void __iomem *) addr); | ||
310 | } | ||
311 | |||
312 | static inline void outl(u32 b, unsigned long addr) | ||
313 | { | ||
314 | writel(b, (volatile void __iomem *) addr); | ||
315 | } | ||
316 | |||
317 | static inline void insb(unsigned long addr, void *buffer, int count) | ||
318 | { | ||
319 | if (count) { | ||
320 | u8 *buf = buffer; | ||
321 | do { | ||
322 | u8 x = inb(addr); | ||
323 | *buf++ = x; | ||
324 | } while (--count); | ||
325 | } | ||
326 | } | ||
327 | |||
328 | static inline void insw(unsigned long addr, void *buffer, int count) | ||
329 | { | ||
330 | if (count) { | ||
331 | u16 *buf = buffer; | ||
332 | do { | ||
333 | u16 x = inw(addr); | ||
334 | *buf++ = x; | ||
335 | } while (--count); | ||
336 | } | ||
337 | } | ||
338 | |||
339 | static inline void insl(unsigned long addr, void *buffer, int count) | ||
340 | { | ||
341 | if (count) { | ||
342 | u32 *buf = buffer; | ||
343 | do { | ||
344 | u32 x = inl(addr); | ||
345 | *buf++ = x; | ||
346 | } while (--count); | ||
347 | } | ||
348 | } | ||
349 | |||
350 | static inline void outsb(unsigned long addr, const void *buffer, int count) | ||
351 | { | ||
352 | if (count) { | ||
353 | const u8 *buf = buffer; | ||
354 | do { | ||
355 | outb(*buf++, addr); | ||
356 | } while (--count); | ||
357 | } | ||
358 | } | ||
359 | |||
360 | static inline void outsw(unsigned long addr, const void *buffer, int count) | ||
361 | { | ||
362 | if (count) { | ||
363 | const u16 *buf = buffer; | ||
364 | do { | ||
365 | outw(*buf++, addr); | ||
366 | } while (--count); | ||
367 | } | ||
368 | } | ||
369 | |||
370 | static inline void outsl(unsigned long addr, const void *buffer, int count) | ||
371 | { | ||
372 | if (count) { | ||
373 | const u32 *buf = buffer; | ||
374 | do { | ||
375 | outl(*buf++, addr); | ||
376 | } while (--count); | ||
377 | } | ||
378 | } | ||
379 | |||
380 | extern void __iomem *ioport_map(unsigned long port, unsigned int len); | ||
381 | extern void ioport_unmap(void __iomem *addr); | ||
382 | |||
383 | #else | ||
384 | |||
284 | /* | 385 | /* |
285 | * The Tile architecture does not support IOPORT, even with PCI. | 386 | * The TilePro architecture does not support IOPORT, even with PCI. |
286 | * Unfortunately we can't yet simply not declare these methods, | 387 | * Unfortunately we can't yet simply not declare these methods, |
287 | * since some generic code that compiles into the kernel, but | 388 | * since some generic code that compiles into the kernel, but |
288 | * we never run, uses them unconditionally. | 389 | * we never run, uses them unconditionally. |
@@ -290,7 +391,12 @@ static inline void memcpy_toio(volatile void __iomem *dst, const void *src, | |||
290 | 391 | ||
291 | static inline long ioport_panic(void) | 392 | static inline long ioport_panic(void) |
292 | { | 393 | { |
394 | #ifdef __tilegx__ | ||
395 | panic("PCI IO space support is disabled. Configure the kernel with" | ||
396 | " CONFIG_TILE_PCI_IO to enable it"); | ||
397 | #else | ||
293 | panic("inb/outb and friends do not exist on tile"); | 398 | panic("inb/outb and friends do not exist on tile"); |
399 | #endif | ||
294 | return 0; | 400 | return 0; |
295 | } | 401 | } |
296 | 402 | ||
@@ -335,13 +441,6 @@ static inline void outl(u32 b, unsigned long addr) | |||
335 | ioport_panic(); | 441 | ioport_panic(); |
336 | } | 442 | } |
337 | 443 | ||
338 | #define inb_p(addr) inb(addr) | ||
339 | #define inw_p(addr) inw(addr) | ||
340 | #define inl_p(addr) inl(addr) | ||
341 | #define outb_p(x, addr) outb((x), (addr)) | ||
342 | #define outw_p(x, addr) outw((x), (addr)) | ||
343 | #define outl_p(x, addr) outl((x), (addr)) | ||
344 | |||
345 | static inline void insb(unsigned long addr, void *buffer, int count) | 444 | static inline void insb(unsigned long addr, void *buffer, int count) |
346 | { | 445 | { |
347 | ioport_panic(); | 446 | ioport_panic(); |
@@ -372,6 +471,15 @@ static inline void outsl(unsigned long addr, const void *buffer, int count) | |||
372 | ioport_panic(); | 471 | ioport_panic(); |
373 | } | 472 | } |
374 | 473 | ||
474 | #endif /* CHIP_HAS_MMIO() && defined(CONFIG_TILE_PCI_IO) */ | ||
475 | |||
476 | #define inb_p(addr) inb(addr) | ||
477 | #define inw_p(addr) inw(addr) | ||
478 | #define inl_p(addr) inl(addr) | ||
479 | #define outb_p(x, addr) outb((x), (addr)) | ||
480 | #define outw_p(x, addr) outw((x), (addr)) | ||
481 | #define outl_p(x, addr) outl((x), (addr)) | ||
482 | |||
375 | #define ioread16be(addr) be16_to_cpu(ioread16(addr)) | 483 | #define ioread16be(addr) be16_to_cpu(ioread16(addr)) |
376 | #define ioread32be(addr) be32_to_cpu(ioread32(addr)) | 484 | #define ioread32be(addr) be32_to_cpu(ioread32(addr)) |
377 | #define iowrite16be(v, addr) iowrite16(be16_to_cpu(v), (addr)) | 485 | #define iowrite16be(v, addr) iowrite16(be16_to_cpu(v), (addr)) |
diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h index c96f9bbb760d..71af5747874d 100644 --- a/arch/tile/include/asm/irqflags.h +++ b/arch/tile/include/asm/irqflags.h | |||
@@ -124,6 +124,12 @@ | |||
124 | DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); | 124 | DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); |
125 | #define INITIAL_INTERRUPTS_ENABLED (1ULL << INT_MEM_ERROR) | 125 | #define INITIAL_INTERRUPTS_ENABLED (1ULL << INT_MEM_ERROR) |
126 | 126 | ||
127 | #ifdef CONFIG_DEBUG_PREEMPT | ||
128 | /* Due to inclusion issues, we can't rely on <linux/smp.h> here. */ | ||
129 | extern unsigned int debug_smp_processor_id(void); | ||
130 | # define smp_processor_id() debug_smp_processor_id() | ||
131 | #endif | ||
132 | |||
127 | /* Disable interrupts. */ | 133 | /* Disable interrupts. */ |
128 | #define arch_local_irq_disable() \ | 134 | #define arch_local_irq_disable() \ |
129 | interrupt_mask_set_mask(LINUX_MASKABLE_INTERRUPTS) | 135 | interrupt_mask_set_mask(LINUX_MASKABLE_INTERRUPTS) |
@@ -132,9 +138,18 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); | |||
132 | #define arch_local_irq_disable_all() \ | 138 | #define arch_local_irq_disable_all() \ |
133 | interrupt_mask_set_mask(-1ULL) | 139 | interrupt_mask_set_mask(-1ULL) |
134 | 140 | ||
141 | /* | ||
142 | * Read the set of maskable interrupts. | ||
143 | * We avoid the preemption warning here via __this_cpu_ptr since even | ||
144 | * if irqs are already enabled, it's harmless to read the wrong cpu's | ||
145 | * enabled mask. | ||
146 | */ | ||
147 | #define arch_local_irqs_enabled() \ | ||
148 | (*__this_cpu_ptr(&interrupts_enabled_mask)) | ||
149 | |||
135 | /* Re-enable all maskable interrupts. */ | 150 | /* Re-enable all maskable interrupts. */ |
136 | #define arch_local_irq_enable() \ | 151 | #define arch_local_irq_enable() \ |
137 | interrupt_mask_reset_mask(__get_cpu_var(interrupts_enabled_mask)) | 152 | interrupt_mask_reset_mask(arch_local_irqs_enabled()) |
138 | 153 | ||
139 | /* Disable or enable interrupts based on flag argument. */ | 154 | /* Disable or enable interrupts based on flag argument. */ |
140 | #define arch_local_irq_restore(disabled) do { \ | 155 | #define arch_local_irq_restore(disabled) do { \ |
@@ -161,7 +176,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); | |||
161 | 176 | ||
162 | /* Prevent the given interrupt from being enabled next time we enable irqs. */ | 177 | /* Prevent the given interrupt from being enabled next time we enable irqs. */ |
163 | #define arch_local_irq_mask(interrupt) \ | 178 | #define arch_local_irq_mask(interrupt) \ |
164 | (__get_cpu_var(interrupts_enabled_mask) &= ~(1ULL << (interrupt))) | 179 | this_cpu_and(interrupts_enabled_mask, ~(1ULL << (interrupt))) |
165 | 180 | ||
166 | /* Prevent the given interrupt from being enabled immediately. */ | 181 | /* Prevent the given interrupt from being enabled immediately. */ |
167 | #define arch_local_irq_mask_now(interrupt) do { \ | 182 | #define arch_local_irq_mask_now(interrupt) do { \ |
@@ -171,7 +186,7 @@ DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); | |||
171 | 186 | ||
172 | /* Allow the given interrupt to be enabled next time we enable irqs. */ | 187 | /* Allow the given interrupt to be enabled next time we enable irqs. */ |
173 | #define arch_local_irq_unmask(interrupt) \ | 188 | #define arch_local_irq_unmask(interrupt) \ |
174 | (__get_cpu_var(interrupts_enabled_mask) |= (1ULL << (interrupt))) | 189 | this_cpu_or(interrupts_enabled_mask, (1ULL << (interrupt))) |
175 | 190 | ||
176 | /* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */ | 191 | /* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */ |
177 | #define arch_local_irq_unmask_now(interrupt) do { \ | 192 | #define arch_local_irq_unmask_now(interrupt) do { \ |
diff --git a/arch/tile/include/asm/hw_irq.h b/arch/tile/include/asm/kdebug.h index 4fac5fbf333e..5bbbfa904c2d 100644 --- a/arch/tile/include/asm/hw_irq.h +++ b/arch/tile/include/asm/kdebug.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2010 Tilera Corporation. All Rights Reserved. | 2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License | 5 | * modify it under the terms of the GNU General Public License |
@@ -12,7 +12,17 @@ | |||
12 | * more details. | 12 | * more details. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #ifndef _ASM_TILE_HW_IRQ_H | 15 | #ifndef _ASM_TILE_KDEBUG_H |
16 | #define _ASM_TILE_HW_IRQ_H | 16 | #define _ASM_TILE_KDEBUG_H |
17 | 17 | ||
18 | #endif /* _ASM_TILE_HW_IRQ_H */ | 18 | #include <linux/notifier.h> |
19 | |||
20 | enum die_val { | ||
21 | DIE_OOPS = 1, | ||
22 | DIE_BREAK, | ||
23 | DIE_SSTEPBP, | ||
24 | DIE_PAGE_FAULT, | ||
25 | DIE_COMPILED_BPT | ||
26 | }; | ||
27 | |||
28 | #endif /* _ASM_TILE_KDEBUG_H */ | ||
diff --git a/arch/tile/include/asm/kgdb.h b/arch/tile/include/asm/kgdb.h new file mode 100644 index 000000000000..280c181cf0db --- /dev/null +++ b/arch/tile/include/asm/kgdb.h | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * TILE-Gx KGDB support. | ||
15 | */ | ||
16 | |||
17 | #ifndef __TILE_KGDB_H__ | ||
18 | #define __TILE_KGDB_H__ | ||
19 | |||
20 | #include <linux/kdebug.h> | ||
21 | #include <arch/opcode.h> | ||
22 | |||
23 | #define GDB_SIZEOF_REG sizeof(unsigned long) | ||
24 | |||
25 | /* | ||
26 | * TILE-Gx gdb is expecting the following register layout: | ||
27 | * 56 GPRs(R0 - R52, TP, SP, LR), 8 special GPRs(networks and ZERO), | ||
28 | * plus the PC and the faultnum. | ||
29 | * | ||
30 | * Even though kernel not use the 8 special GPRs, they need to be present | ||
31 | * in the registers sent for correct processing in the host-side gdb. | ||
32 | * | ||
33 | */ | ||
34 | #define DBG_MAX_REG_NUM (56+8+2) | ||
35 | #define NUMREGBYTES (DBG_MAX_REG_NUM * GDB_SIZEOF_REG) | ||
36 | |||
37 | /* | ||
38 | * BUFMAX defines the maximum number of characters in inbound/outbound | ||
39 | * buffers at least NUMREGBYTES*2 are needed for register packets, | ||
40 | * Longer buffer is needed to list all threads. | ||
41 | */ | ||
42 | #define BUFMAX 2048 | ||
43 | |||
44 | #define BREAK_INSTR_SIZE TILEGX_BUNDLE_SIZE_IN_BYTES | ||
45 | |||
46 | /* | ||
47 | * Require cache flush for set/clear a software breakpoint or write memory. | ||
48 | */ | ||
49 | #define CACHE_FLUSH_IS_SAFE 1 | ||
50 | |||
51 | /* | ||
52 | * The compiled-in breakpoint instruction can be used to "break" into | ||
53 | * the debugger via magic system request key (sysrq-G). | ||
54 | */ | ||
55 | static tile_bundle_bits compiled_bpt = TILEGX_BPT_BUNDLE | DIE_COMPILED_BPT; | ||
56 | |||
57 | enum tilegx_regnum { | ||
58 | TILEGX_PC_REGNUM = TREG_LAST_GPR + 9, | ||
59 | TILEGX_FAULTNUM_REGNUM, | ||
60 | }; | ||
61 | |||
62 | /* | ||
63 | * Generate a breakpoint exception to "break" into the debugger. | ||
64 | */ | ||
65 | static inline void arch_kgdb_breakpoint(void) | ||
66 | { | ||
67 | asm volatile (".quad %0\n\t" | ||
68 | ::""(compiled_bpt)); | ||
69 | } | ||
70 | |||
71 | #endif /* __TILE_KGDB_H__ */ | ||
diff --git a/arch/tile/include/asm/kprobes.h b/arch/tile/include/asm/kprobes.h new file mode 100644 index 000000000000..d8f9a83943b1 --- /dev/null +++ b/arch/tile/include/asm/kprobes.h | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * arch/tile/include/asm/kprobes.h | ||
3 | * | ||
4 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU General Public License | ||
8 | * as published by the Free Software Foundation, version 2. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
13 | * NON INFRINGEMENT. See the GNU General Public License for | ||
14 | * more details. | ||
15 | */ | ||
16 | |||
17 | #ifndef _ASM_TILE_KPROBES_H | ||
18 | #define _ASM_TILE_KPROBES_H | ||
19 | |||
20 | #include <linux/types.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <linux/percpu.h> | ||
23 | |||
24 | #include <arch/opcode.h> | ||
25 | |||
26 | #define __ARCH_WANT_KPROBES_INSN_SLOT | ||
27 | #define MAX_INSN_SIZE 2 | ||
28 | |||
29 | #define kretprobe_blacklist_size 0 | ||
30 | |||
31 | typedef tile_bundle_bits kprobe_opcode_t; | ||
32 | |||
33 | #define flush_insn_slot(p) \ | ||
34 | flush_icache_range((unsigned long)p->addr, \ | ||
35 | (unsigned long)p->addr + \ | ||
36 | (MAX_INSN_SIZE * sizeof(kprobe_opcode_t))) | ||
37 | |||
38 | struct kprobe; | ||
39 | |||
40 | /* Architecture specific copy of original instruction. */ | ||
41 | struct arch_specific_insn { | ||
42 | kprobe_opcode_t *insn; | ||
43 | }; | ||
44 | |||
45 | struct prev_kprobe { | ||
46 | struct kprobe *kp; | ||
47 | unsigned long status; | ||
48 | unsigned long saved_pc; | ||
49 | }; | ||
50 | |||
51 | #define MAX_JPROBES_STACK_SIZE 128 | ||
52 | #define MAX_JPROBES_STACK_ADDR \ | ||
53 | (((unsigned long)current_thread_info()) + THREAD_SIZE - 32 \ | ||
54 | - sizeof(struct pt_regs)) | ||
55 | |||
56 | #define MIN_JPROBES_STACK_SIZE(ADDR) \ | ||
57 | ((((ADDR) + MAX_JPROBES_STACK_SIZE) > MAX_JPROBES_STACK_ADDR) \ | ||
58 | ? MAX_JPROBES_STACK_ADDR - (ADDR) \ | ||
59 | : MAX_JPROBES_STACK_SIZE) | ||
60 | |||
61 | /* per-cpu kprobe control block. */ | ||
62 | struct kprobe_ctlblk { | ||
63 | unsigned long kprobe_status; | ||
64 | unsigned long kprobe_saved_pc; | ||
65 | unsigned long jprobe_saved_sp; | ||
66 | struct prev_kprobe prev_kprobe; | ||
67 | struct pt_regs jprobe_saved_regs; | ||
68 | char jprobes_stack[MAX_JPROBES_STACK_SIZE]; | ||
69 | }; | ||
70 | |||
71 | extern tile_bundle_bits breakpoint2_insn; | ||
72 | extern tile_bundle_bits breakpoint_insn; | ||
73 | |||
74 | void arch_remove_kprobe(struct kprobe *); | ||
75 | |||
76 | extern int kprobe_exceptions_notify(struct notifier_block *self, | ||
77 | unsigned long val, void *data); | ||
78 | |||
79 | #endif /* _ASM_TILE_KPROBES_H */ | ||
diff --git a/arch/tile/include/asm/mmu.h b/arch/tile/include/asm/mmu.h index e2c789096795..0cab1182bde1 100644 --- a/arch/tile/include/asm/mmu.h +++ b/arch/tile/include/asm/mmu.h | |||
@@ -22,6 +22,7 @@ struct mm_context { | |||
22 | * semaphore but atomically, but it is conservatively set. | 22 | * semaphore but atomically, but it is conservatively set. |
23 | */ | 23 | */ |
24 | unsigned long priority_cached; | 24 | unsigned long priority_cached; |
25 | unsigned long vdso_base; | ||
25 | }; | 26 | }; |
26 | 27 | ||
27 | typedef struct mm_context mm_context_t; | 28 | typedef struct mm_context mm_context_t; |
diff --git a/arch/tile/include/asm/mmu_context.h b/arch/tile/include/asm/mmu_context.h index 37f0b741dee7..4734215e2ad4 100644 --- a/arch/tile/include/asm/mmu_context.h +++ b/arch/tile/include/asm/mmu_context.h | |||
@@ -45,7 +45,7 @@ static inline void __install_page_table(pgd_t *pgdir, int asid, pgprot_t prot) | |||
45 | 45 | ||
46 | static inline void install_page_table(pgd_t *pgdir, int asid) | 46 | static inline void install_page_table(pgd_t *pgdir, int asid) |
47 | { | 47 | { |
48 | pte_t *ptep = virt_to_pte(NULL, (unsigned long)pgdir); | 48 | pte_t *ptep = virt_to_kpte((unsigned long)pgdir); |
49 | __install_page_table(pgdir, asid, *ptep); | 49 | __install_page_table(pgdir, asid, *ptep); |
50 | } | 50 | } |
51 | 51 | ||
diff --git a/arch/tile/include/asm/mmzone.h b/arch/tile/include/asm/mmzone.h index 9d3dbce8f953..804f1098b6cd 100644 --- a/arch/tile/include/asm/mmzone.h +++ b/arch/tile/include/asm/mmzone.h | |||
@@ -42,7 +42,7 @@ static inline int pfn_to_nid(unsigned long pfn) | |||
42 | 42 | ||
43 | #define kern_addr_valid(kaddr) virt_addr_valid((void *)kaddr) | 43 | #define kern_addr_valid(kaddr) virt_addr_valid((void *)kaddr) |
44 | 44 | ||
45 | static inline int pfn_valid(int pfn) | 45 | static inline int pfn_valid(unsigned long pfn) |
46 | { | 46 | { |
47 | int nid = pfn_to_nid(pfn); | 47 | int nid = pfn_to_nid(pfn); |
48 | 48 | ||
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h index dd033a4fd627..6346888f7bdc 100644 --- a/arch/tile/include/asm/page.h +++ b/arch/tile/include/asm/page.h | |||
@@ -39,6 +39,12 @@ | |||
39 | #define HPAGE_MASK (~(HPAGE_SIZE - 1)) | 39 | #define HPAGE_MASK (~(HPAGE_SIZE - 1)) |
40 | 40 | ||
41 | /* | 41 | /* |
42 | * We do define AT_SYSINFO_EHDR to support vDSO, | ||
43 | * but don't use the gate mechanism. | ||
44 | */ | ||
45 | #define __HAVE_ARCH_GATE_AREA 1 | ||
46 | |||
47 | /* | ||
42 | * If the Kconfig doesn't specify, set a maximum zone order that | 48 | * If the Kconfig doesn't specify, set a maximum zone order that |
43 | * is enough so that we can create huge pages from small pages given | 49 | * is enough so that we can create huge pages from small pages given |
44 | * the respective sizes of the two page types. See <linux/mmzone.h>. | 50 | * the respective sizes of the two page types. See <linux/mmzone.h>. |
@@ -142,8 +148,12 @@ static inline __attribute_const__ int get_order(unsigned long size) | |||
142 | #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA | 148 | #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA |
143 | #endif | 149 | #endif |
144 | 150 | ||
151 | /* Allow overriding how much VA or PA the kernel will use. */ | ||
152 | #define MAX_PA_WIDTH CHIP_PA_WIDTH() | ||
153 | #define MAX_VA_WIDTH CHIP_VA_WIDTH() | ||
154 | |||
145 | /* Each memory controller has PAs distinct in their high bits. */ | 155 | /* Each memory controller has PAs distinct in their high bits. */ |
146 | #define NR_PA_HIGHBIT_SHIFT (CHIP_PA_WIDTH() - CHIP_LOG_NUM_MSHIMS()) | 156 | #define NR_PA_HIGHBIT_SHIFT (MAX_PA_WIDTH - CHIP_LOG_NUM_MSHIMS()) |
147 | #define NR_PA_HIGHBIT_VALUES (1 << CHIP_LOG_NUM_MSHIMS()) | 157 | #define NR_PA_HIGHBIT_VALUES (1 << CHIP_LOG_NUM_MSHIMS()) |
148 | #define __pa_to_highbits(pa) ((phys_addr_t)(pa) >> NR_PA_HIGHBIT_SHIFT) | 158 | #define __pa_to_highbits(pa) ((phys_addr_t)(pa) >> NR_PA_HIGHBIT_SHIFT) |
149 | #define __pfn_to_highbits(pfn) ((pfn) >> (NR_PA_HIGHBIT_SHIFT - PAGE_SHIFT)) | 159 | #define __pfn_to_highbits(pfn) ((pfn) >> (NR_PA_HIGHBIT_SHIFT - PAGE_SHIFT)) |
@@ -154,7 +164,7 @@ static inline __attribute_const__ int get_order(unsigned long size) | |||
154 | * We reserve the lower half of memory for user-space programs, and the | 164 | * We reserve the lower half of memory for user-space programs, and the |
155 | * upper half for system code. We re-map all of physical memory in the | 165 | * upper half for system code. We re-map all of physical memory in the |
156 | * upper half, which takes a quarter of our VA space. Then we have | 166 | * upper half, which takes a quarter of our VA space. Then we have |
157 | * the vmalloc regions. The supervisor code lives at 0xfffffff700000000, | 167 | * the vmalloc regions. The supervisor code lives at the highest address, |
158 | * with the hypervisor above that. | 168 | * with the hypervisor above that. |
159 | * | 169 | * |
160 | * Loadable kernel modules are placed immediately after the static | 170 | * Loadable kernel modules are placed immediately after the static |
@@ -166,26 +176,19 @@ static inline __attribute_const__ int get_order(unsigned long size) | |||
166 | * Similarly, for now we don't play any struct page mapping games. | 176 | * Similarly, for now we don't play any struct page mapping games. |
167 | */ | 177 | */ |
168 | 178 | ||
169 | #if CHIP_PA_WIDTH() + 2 > CHIP_VA_WIDTH() | 179 | #if MAX_PA_WIDTH + 2 > MAX_VA_WIDTH |
170 | # error Too much PA to map with the VA available! | 180 | # error Too much PA to map with the VA available! |
171 | #endif | 181 | #endif |
172 | #define HALF_VA_SPACE (_AC(1, UL) << (CHIP_VA_WIDTH() - 1)) | ||
173 | 182 | ||
174 | #define MEM_LOW_END (HALF_VA_SPACE - 1) /* low half */ | 183 | #define PAGE_OFFSET (-(_AC(1, UL) << (MAX_VA_WIDTH - 1))) |
175 | #define MEM_HIGH_START (-HALF_VA_SPACE) /* high half */ | 184 | #define KERNEL_HIGH_VADDR _AC(0xfffffff800000000, UL) /* high 32GB */ |
176 | #define PAGE_OFFSET MEM_HIGH_START | 185 | #define FIXADDR_BASE (KERNEL_HIGH_VADDR - 0x400000000) /* 4 GB */ |
177 | #define FIXADDR_BASE _AC(0xfffffff400000000, UL) /* 4 GB */ | 186 | #define FIXADDR_TOP (KERNEL_HIGH_VADDR - 0x300000000) /* 4 GB */ |
178 | #define FIXADDR_TOP _AC(0xfffffff500000000, UL) /* 4 GB */ | ||
179 | #define _VMALLOC_START FIXADDR_TOP | 187 | #define _VMALLOC_START FIXADDR_TOP |
180 | #define HUGE_VMAP_BASE _AC(0xfffffff600000000, UL) /* 4 GB */ | 188 | #define HUGE_VMAP_BASE (KERNEL_HIGH_VADDR - 0x200000000) /* 4 GB */ |
181 | #define MEM_SV_START _AC(0xfffffff700000000, UL) /* 256 MB */ | 189 | #define MEM_SV_START (KERNEL_HIGH_VADDR - 0x100000000) /* 256 MB */ |
182 | #define MEM_SV_INTRPT MEM_SV_START | 190 | #define MEM_MODULE_START (MEM_SV_START + (256*1024*1024)) /* 256 MB */ |
183 | #define MEM_MODULE_START _AC(0xfffffff710000000, UL) /* 256 MB */ | ||
184 | #define MEM_MODULE_END (MEM_MODULE_START + (256*1024*1024)) | 191 | #define MEM_MODULE_END (MEM_MODULE_START + (256*1024*1024)) |
185 | #define MEM_HV_START _AC(0xfffffff800000000, UL) /* 32 GB */ | ||
186 | |||
187 | /* Highest DTLB address we will use */ | ||
188 | #define KERNEL_HIGH_VADDR MEM_SV_START | ||
189 | 192 | ||
190 | #else /* !__tilegx__ */ | 193 | #else /* !__tilegx__ */ |
191 | 194 | ||
@@ -207,25 +210,18 @@ static inline __attribute_const__ int get_order(unsigned long size) | |||
207 | * values, and after that, we show "typical" values, since the actual | 210 | * values, and after that, we show "typical" values, since the actual |
208 | * addresses depend on kernel #defines. | 211 | * addresses depend on kernel #defines. |
209 | * | 212 | * |
210 | * MEM_HV_INTRPT 0xfe000000 | 213 | * MEM_HV_START 0xfe000000 |
211 | * MEM_SV_INTRPT (kernel code) 0xfd000000 | 214 | * MEM_SV_START (kernel code) 0xfd000000 |
212 | * MEM_USER_INTRPT (user vector) 0xfc000000 | 215 | * MEM_USER_INTRPT (user vector) 0xfc000000 |
213 | * FIX_KMAP_xxx 0xf8000000 (via NR_CPUS * KM_TYPE_NR) | 216 | * FIX_KMAP_xxx 0xfa000000 (via NR_CPUS * KM_TYPE_NR) |
214 | * PKMAP_BASE 0xf7000000 (via LAST_PKMAP) | 217 | * PKMAP_BASE 0xf9000000 (via LAST_PKMAP) |
215 | * HUGE_VMAP 0xf3000000 (via CONFIG_NR_HUGE_VMAPS) | 218 | * VMALLOC_START 0xf7000000 (via VMALLOC_RESERVE) |
216 | * VMALLOC_START 0xf0000000 (via __VMALLOC_RESERVE) | ||
217 | * mapped LOWMEM 0xc0000000 | 219 | * mapped LOWMEM 0xc0000000 |
218 | */ | 220 | */ |
219 | 221 | ||
220 | #define MEM_USER_INTRPT _AC(0xfc000000, UL) | 222 | #define MEM_USER_INTRPT _AC(0xfc000000, UL) |
221 | #if CONFIG_KERNEL_PL == 1 | 223 | #define MEM_SV_START _AC(0xfd000000, UL) |
222 | #define MEM_SV_INTRPT _AC(0xfd000000, UL) | 224 | #define MEM_HV_START _AC(0xfe000000, UL) |
223 | #define MEM_HV_INTRPT _AC(0xfe000000, UL) | ||
224 | #else | ||
225 | #define MEM_GUEST_INTRPT _AC(0xfd000000, UL) | ||
226 | #define MEM_SV_INTRPT _AC(0xfe000000, UL) | ||
227 | #define MEM_HV_INTRPT _AC(0xff000000, UL) | ||
228 | #endif | ||
229 | 225 | ||
230 | #define INTRPT_SIZE 0x4000 | 226 | #define INTRPT_SIZE 0x4000 |
231 | 227 | ||
@@ -246,7 +242,7 @@ static inline __attribute_const__ int get_order(unsigned long size) | |||
246 | 242 | ||
247 | #endif /* __tilegx__ */ | 243 | #endif /* __tilegx__ */ |
248 | 244 | ||
249 | #ifndef __ASSEMBLY__ | 245 | #if !defined(__ASSEMBLY__) && !defined(VDSO_BUILD) |
250 | 246 | ||
251 | #ifdef CONFIG_HIGHMEM | 247 | #ifdef CONFIG_HIGHMEM |
252 | 248 | ||
@@ -332,6 +328,7 @@ static inline int pfn_valid(unsigned long pfn) | |||
332 | 328 | ||
333 | struct mm_struct; | 329 | struct mm_struct; |
334 | extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr); | 330 | extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr); |
331 | extern pte_t *virt_to_kpte(unsigned long kaddr); | ||
335 | 332 | ||
336 | #endif /* !__ASSEMBLY__ */ | 333 | #endif /* !__ASSEMBLY__ */ |
337 | 334 | ||
diff --git a/arch/tile/include/asm/pci.h b/arch/tile/include/asm/pci.h index 54a924208d3c..dfedd7ac7298 100644 --- a/arch/tile/include/asm/pci.h +++ b/arch/tile/include/asm/pci.h | |||
@@ -17,7 +17,6 @@ | |||
17 | 17 | ||
18 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
19 | #include <linux/pci.h> | 19 | #include <linux/pci.h> |
20 | #include <linux/numa.h> | ||
21 | #include <asm-generic/pci_iomap.h> | 20 | #include <asm-generic/pci_iomap.h> |
22 | 21 | ||
23 | #ifndef __tilegx__ | 22 | #ifndef __tilegx__ |
@@ -29,7 +28,6 @@ struct pci_controller { | |||
29 | int index; /* PCI domain number */ | 28 | int index; /* PCI domain number */ |
30 | struct pci_bus *root_bus; | 29 | struct pci_bus *root_bus; |
31 | 30 | ||
32 | int first_busno; | ||
33 | int last_busno; | 31 | int last_busno; |
34 | 32 | ||
35 | int hv_cfg_fd[2]; /* config{0,1} fds for this PCIe controller */ | 33 | int hv_cfg_fd[2]; /* config{0,1} fds for this PCIe controller */ |
@@ -124,6 +122,11 @@ static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {} | |||
124 | * the CPA plus TILE_PCI_MEM_MAP_BASE_OFFSET. To support 32-bit | 122 | * the CPA plus TILE_PCI_MEM_MAP_BASE_OFFSET. To support 32-bit |
125 | * devices, we create a separate map region that handles the low | 123 | * devices, we create a separate map region that handles the low |
126 | * 4GB. | 124 | * 4GB. |
125 | * | ||
126 | * This design lets us avoid the "PCI hole" problem where the host bridge | ||
127 | * won't pass DMA traffic with target addresses that happen to fall within the | ||
128 | * BAR space. This enables us to use all the physical memory for DMA, instead | ||
129 | * of wasting the same amount of physical memory as the BAR window size. | ||
127 | */ | 130 | */ |
128 | #define TILE_PCI_MEM_MAP_BASE_OFFSET (1ULL << CHIP_PA_WIDTH()) | 131 | #define TILE_PCI_MEM_MAP_BASE_OFFSET (1ULL << CHIP_PA_WIDTH()) |
129 | 132 | ||
@@ -145,6 +148,10 @@ struct pci_controller { | |||
145 | 148 | ||
146 | int pio_mem_index; /* PIO region index for memory access */ | 149 | int pio_mem_index; /* PIO region index for memory access */ |
147 | 150 | ||
151 | #ifdef CONFIG_TILE_PCI_IO | ||
152 | int pio_io_index; /* PIO region index for I/O space access */ | ||
153 | #endif | ||
154 | |||
148 | /* | 155 | /* |
149 | * Mem-Map regions for all the memory controllers so that Linux can | 156 | * Mem-Map regions for all the memory controllers so that Linux can |
150 | * map all of its physical memory space to the PCI bus. | 157 | * map all of its physical memory space to the PCI bus. |
@@ -154,6 +161,10 @@ struct pci_controller { | |||
154 | int index; /* PCI domain number */ | 161 | int index; /* PCI domain number */ |
155 | struct pci_bus *root_bus; | 162 | struct pci_bus *root_bus; |
156 | 163 | ||
164 | /* PCI I/O space resource for this controller. */ | ||
165 | struct resource io_space; | ||
166 | char io_space_name[32]; | ||
167 | |||
157 | /* PCI memory space resource for this controller. */ | 168 | /* PCI memory space resource for this controller. */ |
158 | struct resource mem_space; | 169 | struct resource mem_space; |
159 | char mem_space_name[32]; | 170 | char mem_space_name[32]; |
@@ -166,13 +177,11 @@ struct pci_controller { | |||
166 | 177 | ||
167 | /* Table that maps the INTx numbers to Linux irq numbers. */ | 178 | /* Table that maps the INTx numbers to Linux irq numbers. */ |
168 | int irq_intx_table[4]; | 179 | int irq_intx_table[4]; |
169 | |||
170 | /* Address ranges that are routed to this controller/bridge. */ | ||
171 | struct resource mem_resources[3]; | ||
172 | }; | 180 | }; |
173 | 181 | ||
174 | extern struct pci_controller pci_controllers[TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES]; | 182 | extern struct pci_controller pci_controllers[TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES]; |
175 | extern gxio_trio_context_t trio_contexts[TILEGX_NUM_TRIO]; | 183 | extern gxio_trio_context_t trio_contexts[TILEGX_NUM_TRIO]; |
184 | extern int num_trio_shims; | ||
176 | 185 | ||
177 | extern void pci_iounmap(struct pci_dev *dev, void __iomem *); | 186 | extern void pci_iounmap(struct pci_dev *dev, void __iomem *); |
178 | 187 | ||
@@ -211,7 +220,8 @@ static inline int pcibios_assign_all_busses(void) | |||
211 | } | 220 | } |
212 | 221 | ||
213 | #define PCIBIOS_MIN_MEM 0 | 222 | #define PCIBIOS_MIN_MEM 0 |
214 | #define PCIBIOS_MIN_IO 0 | 223 | /* Minimum PCI I/O address, starting at the page boundary. */ |
224 | #define PCIBIOS_MIN_IO PAGE_SIZE | ||
215 | 225 | ||
216 | /* Use any cpu for PCI. */ | 226 | /* Use any cpu for PCI. */ |
217 | #define cpumask_of_pcibus(bus) cpu_online_mask | 227 | #define cpumask_of_pcibus(bus) cpu_online_mask |
diff --git a/arch/tile/include/asm/pgtable_32.h b/arch/tile/include/asm/pgtable_32.h index 4ce4a7a99c24..63142ab3b3dd 100644 --- a/arch/tile/include/asm/pgtable_32.h +++ b/arch/tile/include/asm/pgtable_32.h | |||
@@ -84,10 +84,12 @@ extern unsigned long VMALLOC_RESERVE /* = CONFIG_VMALLOC_RESERVE */; | |||
84 | /* We have no pmd or pud since we are strictly a two-level page table */ | 84 | /* We have no pmd or pud since we are strictly a two-level page table */ |
85 | #include <asm-generic/pgtable-nopmd.h> | 85 | #include <asm-generic/pgtable-nopmd.h> |
86 | 86 | ||
87 | static inline int pud_huge_page(pud_t pud) { return 0; } | ||
88 | |||
87 | /* We don't define any pgds for these addresses. */ | 89 | /* We don't define any pgds for these addresses. */ |
88 | static inline int pgd_addr_invalid(unsigned long addr) | 90 | static inline int pgd_addr_invalid(unsigned long addr) |
89 | { | 91 | { |
90 | return addr >= MEM_HV_INTRPT; | 92 | return addr >= MEM_HV_START; |
91 | } | 93 | } |
92 | 94 | ||
93 | /* | 95 | /* |
diff --git a/arch/tile/include/asm/pgtable_64.h b/arch/tile/include/asm/pgtable_64.h index 2492fa5478e7..3421177f7370 100644 --- a/arch/tile/include/asm/pgtable_64.h +++ b/arch/tile/include/asm/pgtable_64.h | |||
@@ -63,6 +63,15 @@ | |||
63 | /* We have no pud since we are a three-level page table. */ | 63 | /* We have no pud since we are a three-level page table. */ |
64 | #include <asm-generic/pgtable-nopud.h> | 64 | #include <asm-generic/pgtable-nopud.h> |
65 | 65 | ||
66 | /* | ||
67 | * pmds are the same as pgds and ptes, so converting is a no-op. | ||
68 | */ | ||
69 | #define pmd_pte(pmd) (pmd) | ||
70 | #define pmdp_ptep(pmdp) (pmdp) | ||
71 | #define pte_pmd(pte) (pte) | ||
72 | |||
73 | #define pud_pte(pud) ((pud).pgd) | ||
74 | |||
66 | static inline int pud_none(pud_t pud) | 75 | static inline int pud_none(pud_t pud) |
67 | { | 76 | { |
68 | return pud_val(pud) == 0; | 77 | return pud_val(pud) == 0; |
@@ -73,6 +82,11 @@ static inline int pud_present(pud_t pud) | |||
73 | return pud_val(pud) & _PAGE_PRESENT; | 82 | return pud_val(pud) & _PAGE_PRESENT; |
74 | } | 83 | } |
75 | 84 | ||
85 | static inline int pud_huge_page(pud_t pud) | ||
86 | { | ||
87 | return pud_val(pud) & _PAGE_HUGE_PAGE; | ||
88 | } | ||
89 | |||
76 | #define pmd_ERROR(e) \ | 90 | #define pmd_ERROR(e) \ |
77 | pr_err("%s:%d: bad pmd 0x%016llx.\n", __FILE__, __LINE__, pmd_val(e)) | 91 | pr_err("%s:%d: bad pmd 0x%016llx.\n", __FILE__, __LINE__, pmd_val(e)) |
78 | 92 | ||
@@ -89,6 +103,9 @@ static inline int pud_bad(pud_t pud) | |||
89 | /* Return the page-table frame number (ptfn) that a pud_t points at. */ | 103 | /* Return the page-table frame number (ptfn) that a pud_t points at. */ |
90 | #define pud_ptfn(pud) hv_pte_get_ptfn((pud).pgd) | 104 | #define pud_ptfn(pud) hv_pte_get_ptfn((pud).pgd) |
91 | 105 | ||
106 | /* Return the page frame number (pfn) that a pud_t points at. */ | ||
107 | #define pud_pfn(pud) pte_pfn(pud_pte(pud)) | ||
108 | |||
92 | /* | 109 | /* |
93 | * A given kernel pud_t maps to a kernel pmd_t table at a specific | 110 | * A given kernel pud_t maps to a kernel pmd_t table at a specific |
94 | * virtual address. Since kernel pmd_t tables can be aligned at | 111 | * virtual address. Since kernel pmd_t tables can be aligned at |
@@ -123,8 +140,7 @@ static inline unsigned long pgd_addr_normalize(unsigned long addr) | |||
123 | /* We don't define any pgds for these addresses. */ | 140 | /* We don't define any pgds for these addresses. */ |
124 | static inline int pgd_addr_invalid(unsigned long addr) | 141 | static inline int pgd_addr_invalid(unsigned long addr) |
125 | { | 142 | { |
126 | return addr >= MEM_HV_START || | 143 | return addr >= KERNEL_HIGH_VADDR || addr != pgd_addr_normalize(addr); |
127 | (addr > MEM_LOW_END && addr < MEM_HIGH_START); | ||
128 | } | 144 | } |
129 | 145 | ||
130 | /* | 146 | /* |
@@ -152,13 +168,6 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm, | |||
152 | return hv_pte(__insn_exch(&ptep->val, 0UL)); | 168 | return hv_pte(__insn_exch(&ptep->val, 0UL)); |
153 | } | 169 | } |
154 | 170 | ||
155 | /* | ||
156 | * pmds are the same as pgds and ptes, so converting is a no-op. | ||
157 | */ | ||
158 | #define pmd_pte(pmd) (pmd) | ||
159 | #define pmdp_ptep(pmdp) (pmdp) | ||
160 | #define pte_pmd(pte) (pte) | ||
161 | |||
162 | #endif /* __ASSEMBLY__ */ | 171 | #endif /* __ASSEMBLY__ */ |
163 | 172 | ||
164 | #endif /* _ASM_TILE_PGTABLE_64_H */ | 173 | #endif /* _ASM_TILE_PGTABLE_64_H */ |
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h index b3f104953da2..42323636c459 100644 --- a/arch/tile/include/asm/processor.h +++ b/arch/tile/include/asm/processor.h | |||
@@ -15,6 +15,8 @@ | |||
15 | #ifndef _ASM_TILE_PROCESSOR_H | 15 | #ifndef _ASM_TILE_PROCESSOR_H |
16 | #define _ASM_TILE_PROCESSOR_H | 16 | #define _ASM_TILE_PROCESSOR_H |
17 | 17 | ||
18 | #include <arch/chip.h> | ||
19 | |||
18 | #ifndef __ASSEMBLY__ | 20 | #ifndef __ASSEMBLY__ |
19 | 21 | ||
20 | /* | 22 | /* |
@@ -25,7 +27,6 @@ | |||
25 | #include <asm/ptrace.h> | 27 | #include <asm/ptrace.h> |
26 | #include <asm/percpu.h> | 28 | #include <asm/percpu.h> |
27 | 29 | ||
28 | #include <arch/chip.h> | ||
29 | #include <arch/spr_def.h> | 30 | #include <arch/spr_def.h> |
30 | 31 | ||
31 | struct task_struct; | 32 | struct task_struct; |
@@ -110,18 +111,16 @@ struct thread_struct { | |||
110 | unsigned long long interrupt_mask; | 111 | unsigned long long interrupt_mask; |
111 | /* User interrupt-control 0 state */ | 112 | /* User interrupt-control 0 state */ |
112 | unsigned long intctrl_0; | 113 | unsigned long intctrl_0; |
113 | #if CHIP_HAS_PROC_STATUS_SPR() | 114 | /* Is this task currently doing a backtrace? */ |
115 | bool in_backtrace; | ||
114 | /* Any other miscellaneous processor state bits */ | 116 | /* Any other miscellaneous processor state bits */ |
115 | unsigned long proc_status; | 117 | unsigned long proc_status; |
116 | #endif | ||
117 | #if !CHIP_HAS_FIXED_INTVEC_BASE() | 118 | #if !CHIP_HAS_FIXED_INTVEC_BASE() |
118 | /* Interrupt base for PL0 interrupts */ | 119 | /* Interrupt base for PL0 interrupts */ |
119 | unsigned long interrupt_vector_base; | 120 | unsigned long interrupt_vector_base; |
120 | #endif | 121 | #endif |
121 | #if CHIP_HAS_TILE_RTF_HWM() | ||
122 | /* Tile cache retry fifo high-water mark */ | 122 | /* Tile cache retry fifo high-water mark */ |
123 | unsigned long tile_rtf_hwm; | 123 | unsigned long tile_rtf_hwm; |
124 | #endif | ||
125 | #if CHIP_HAS_DSTREAM_PF() | 124 | #if CHIP_HAS_DSTREAM_PF() |
126 | /* Data stream prefetch control */ | 125 | /* Data stream prefetch control */ |
127 | unsigned long dstream_pf; | 126 | unsigned long dstream_pf; |
@@ -134,21 +133,16 @@ struct thread_struct { | |||
134 | /* Async DMA TLB fault information */ | 133 | /* Async DMA TLB fault information */ |
135 | struct async_tlb dma_async_tlb; | 134 | struct async_tlb dma_async_tlb; |
136 | #endif | 135 | #endif |
137 | #if CHIP_HAS_SN_PROC() | ||
138 | /* Was static network processor when we were switched out? */ | ||
139 | int sn_proc_running; | ||
140 | /* Async SNI TLB fault information */ | ||
141 | struct async_tlb sn_async_tlb; | ||
142 | #endif | ||
143 | }; | 136 | }; |
144 | 137 | ||
145 | #endif /* !__ASSEMBLY__ */ | 138 | #endif /* !__ASSEMBLY__ */ |
146 | 139 | ||
147 | /* | 140 | /* |
148 | * Start with "sp" this many bytes below the top of the kernel stack. | 141 | * Start with "sp" this many bytes below the top of the kernel stack. |
149 | * This preserves the invariant that a called function may write to *sp. | 142 | * This allows us to be cache-aware when handling the initial save |
143 | * of the pt_regs value to the stack. | ||
150 | */ | 144 | */ |
151 | #define STACK_TOP_DELTA 8 | 145 | #define STACK_TOP_DELTA 64 |
152 | 146 | ||
153 | /* | 147 | /* |
154 | * When entering the kernel via a fault, start with the top of the | 148 | * When entering the kernel via a fault, start with the top of the |
@@ -164,7 +158,7 @@ struct thread_struct { | |||
164 | #ifndef __ASSEMBLY__ | 158 | #ifndef __ASSEMBLY__ |
165 | 159 | ||
166 | #ifdef __tilegx__ | 160 | #ifdef __tilegx__ |
167 | #define TASK_SIZE_MAX (MEM_LOW_END + 1) | 161 | #define TASK_SIZE_MAX (_AC(1, UL) << (MAX_VA_WIDTH - 1)) |
168 | #else | 162 | #else |
169 | #define TASK_SIZE_MAX PAGE_OFFSET | 163 | #define TASK_SIZE_MAX PAGE_OFFSET |
170 | #endif | 164 | #endif |
@@ -178,10 +172,10 @@ struct thread_struct { | |||
178 | #define TASK_SIZE TASK_SIZE_MAX | 172 | #define TASK_SIZE TASK_SIZE_MAX |
179 | #endif | 173 | #endif |
180 | 174 | ||
181 | /* We provide a minimal "vdso" a la x86; just the sigreturn code for now. */ | 175 | #define VDSO_BASE ((unsigned long)current->active_mm->context.vdso_base) |
182 | #define VDSO_BASE (TASK_SIZE - PAGE_SIZE) | 176 | #define VDSO_SYM(x) (VDSO_BASE + (unsigned long)(x)) |
183 | 177 | ||
184 | #define STACK_TOP VDSO_BASE | 178 | #define STACK_TOP TASK_SIZE |
185 | 179 | ||
186 | /* STACK_TOP_MAX is used temporarily in execve and should not check COMPAT. */ | 180 | /* STACK_TOP_MAX is used temporarily in execve and should not check COMPAT. */ |
187 | #define STACK_TOP_MAX TASK_SIZE_MAX | 181 | #define STACK_TOP_MAX TASK_SIZE_MAX |
@@ -232,21 +226,28 @@ extern int do_work_pending(struct pt_regs *regs, u32 flags); | |||
232 | unsigned long get_wchan(struct task_struct *p); | 226 | unsigned long get_wchan(struct task_struct *p); |
233 | 227 | ||
234 | /* Return initial ksp value for given task. */ | 228 | /* Return initial ksp value for given task. */ |
235 | #define task_ksp0(task) ((unsigned long)(task)->stack + THREAD_SIZE) | 229 | #define task_ksp0(task) \ |
230 | ((unsigned long)(task)->stack + THREAD_SIZE - STACK_TOP_DELTA) | ||
236 | 231 | ||
237 | /* Return some info about the user process TASK. */ | 232 | /* Return some info about the user process TASK. */ |
238 | #define KSTK_TOP(task) (task_ksp0(task) - STACK_TOP_DELTA) | ||
239 | #define task_pt_regs(task) \ | 233 | #define task_pt_regs(task) \ |
240 | ((struct pt_regs *)(task_ksp0(task) - KSTK_PTREGS_GAP) - 1) | 234 | ((struct pt_regs *)(task_ksp0(task) - KSTK_PTREGS_GAP) - 1) |
241 | #define current_pt_regs() \ | 235 | #define current_pt_regs() \ |
242 | ((struct pt_regs *)((stack_pointer | (THREAD_SIZE - 1)) - \ | 236 | ((struct pt_regs *)((stack_pointer | (THREAD_SIZE - 1)) - \ |
243 | (KSTK_PTREGS_GAP - 1)) - 1) | 237 | STACK_TOP_DELTA - (KSTK_PTREGS_GAP - 1)) - 1) |
244 | #define task_sp(task) (task_pt_regs(task)->sp) | 238 | #define task_sp(task) (task_pt_regs(task)->sp) |
245 | #define task_pc(task) (task_pt_regs(task)->pc) | 239 | #define task_pc(task) (task_pt_regs(task)->pc) |
246 | /* Aliases for pc and sp (used in fs/proc/array.c) */ | 240 | /* Aliases for pc and sp (used in fs/proc/array.c) */ |
247 | #define KSTK_EIP(task) task_pc(task) | 241 | #define KSTK_EIP(task) task_pc(task) |
248 | #define KSTK_ESP(task) task_sp(task) | 242 | #define KSTK_ESP(task) task_sp(task) |
249 | 243 | ||
244 | /* Fine-grained unaligned JIT support */ | ||
245 | #define GET_UNALIGN_CTL(tsk, adr) get_unalign_ctl((tsk), (adr)) | ||
246 | #define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val)) | ||
247 | |||
248 | extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr); | ||
249 | extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val); | ||
250 | |||
250 | /* Standard format for printing registers and other word-size data. */ | 251 | /* Standard format for printing registers and other word-size data. */ |
251 | #ifdef __tilegx__ | 252 | #ifdef __tilegx__ |
252 | # define REGFMT "0x%016lx" | 253 | # define REGFMT "0x%016lx" |
@@ -275,7 +276,6 @@ extern char chip_model[64]; | |||
275 | /* Data on which physical memory controller corresponds to which NUMA node. */ | 276 | /* Data on which physical memory controller corresponds to which NUMA node. */ |
276 | extern int node_controller[]; | 277 | extern int node_controller[]; |
277 | 278 | ||
278 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
279 | /* Does the heap allocator return hash-for-home pages by default? */ | 279 | /* Does the heap allocator return hash-for-home pages by default? */ |
280 | extern int hash_default; | 280 | extern int hash_default; |
281 | 281 | ||
@@ -285,11 +285,6 @@ extern int kstack_hash; | |||
285 | /* Does MAP_ANONYMOUS return hash-for-home pages by default? */ | 285 | /* Does MAP_ANONYMOUS return hash-for-home pages by default? */ |
286 | #define uheap_hash hash_default | 286 | #define uheap_hash hash_default |
287 | 287 | ||
288 | #else | ||
289 | #define hash_default 0 | ||
290 | #define kstack_hash 0 | ||
291 | #define uheap_hash 0 | ||
292 | #endif | ||
293 | 288 | ||
294 | /* Are we using huge pages in the TLB for kernel data? */ | 289 | /* Are we using huge pages in the TLB for kernel data? */ |
295 | extern int kdata_huge; | 290 | extern int kdata_huge; |
@@ -337,7 +332,6 @@ extern int kdata_huge; | |||
337 | 332 | ||
338 | /* | 333 | /* |
339 | * Provide symbolic constants for PLs. | 334 | * Provide symbolic constants for PLs. |
340 | * Note that assembly code assumes that USER_PL is zero. | ||
341 | */ | 335 | */ |
342 | #define USER_PL 0 | 336 | #define USER_PL 0 |
343 | #if CONFIG_KERNEL_PL == 2 | 337 | #if CONFIG_KERNEL_PL == 2 |
@@ -346,20 +340,38 @@ extern int kdata_huge; | |||
346 | #define KERNEL_PL CONFIG_KERNEL_PL | 340 | #define KERNEL_PL CONFIG_KERNEL_PL |
347 | 341 | ||
348 | /* SYSTEM_SAVE_K_0 holds the current cpu number ORed with ksp0. */ | 342 | /* SYSTEM_SAVE_K_0 holds the current cpu number ORed with ksp0. */ |
349 | #define CPU_LOG_MASK_VALUE 12 | 343 | #ifdef __tilegx__ |
350 | #define CPU_MASK_VALUE ((1 << CPU_LOG_MASK_VALUE) - 1) | 344 | #define CPU_SHIFT 48 |
351 | #if CONFIG_NR_CPUS > CPU_MASK_VALUE | 345 | #if CHIP_VA_WIDTH() > CPU_SHIFT |
352 | # error Too many cpus! | 346 | # error Too many VA bits! |
353 | #endif | 347 | #endif |
348 | #define MAX_CPU_ID ((1 << (64 - CPU_SHIFT)) - 1) | ||
349 | #define raw_smp_processor_id() \ | ||
350 | ((int)(__insn_mfspr(SPR_SYSTEM_SAVE_K_0) >> CPU_SHIFT)) | ||
351 | #define get_current_ksp0() \ | ||
352 | ((unsigned long)(((long)__insn_mfspr(SPR_SYSTEM_SAVE_K_0) << \ | ||
353 | (64 - CPU_SHIFT)) >> (64 - CPU_SHIFT))) | ||
354 | #define next_current_ksp0(task) ({ \ | ||
355 | unsigned long __ksp0 = task_ksp0(task) & ((1UL << CPU_SHIFT) - 1); \ | ||
356 | unsigned long __cpu = (long)raw_smp_processor_id() << CPU_SHIFT; \ | ||
357 | __ksp0 | __cpu; \ | ||
358 | }) | ||
359 | #else | ||
360 | #define LOG2_NR_CPU_IDS 6 | ||
361 | #define MAX_CPU_ID ((1 << LOG2_NR_CPU_IDS) - 1) | ||
354 | #define raw_smp_processor_id() \ | 362 | #define raw_smp_processor_id() \ |
355 | ((int)__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & CPU_MASK_VALUE) | 363 | ((int)__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & MAX_CPU_ID) |
356 | #define get_current_ksp0() \ | 364 | #define get_current_ksp0() \ |
357 | (__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & ~CPU_MASK_VALUE) | 365 | (__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & ~MAX_CPU_ID) |
358 | #define next_current_ksp0(task) ({ \ | 366 | #define next_current_ksp0(task) ({ \ |
359 | unsigned long __ksp0 = task_ksp0(task); \ | 367 | unsigned long __ksp0 = task_ksp0(task); \ |
360 | int __cpu = raw_smp_processor_id(); \ | 368 | int __cpu = raw_smp_processor_id(); \ |
361 | BUG_ON(__ksp0 & CPU_MASK_VALUE); \ | 369 | BUG_ON(__ksp0 & MAX_CPU_ID); \ |
362 | __ksp0 | __cpu; \ | 370 | __ksp0 | __cpu; \ |
363 | }) | 371 | }) |
372 | #endif | ||
373 | #if CONFIG_NR_CPUS > (MAX_CPU_ID + 1) | ||
374 | # error Too many cpus! | ||
375 | #endif | ||
364 | 376 | ||
365 | #endif /* _ASM_TILE_PROCESSOR_H */ | 377 | #endif /* _ASM_TILE_PROCESSOR_H */ |
diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h index fd412260aff7..b9620c077abc 100644 --- a/arch/tile/include/asm/ptrace.h +++ b/arch/tile/include/asm/ptrace.h | |||
@@ -33,12 +33,13 @@ typedef unsigned long pt_reg_t; | |||
33 | 33 | ||
34 | #ifndef __ASSEMBLY__ | 34 | #ifndef __ASSEMBLY__ |
35 | 35 | ||
36 | #define regs_return_value(regs) ((regs)->regs[0]) | ||
36 | #define instruction_pointer(regs) ((regs)->pc) | 37 | #define instruction_pointer(regs) ((regs)->pc) |
37 | #define profile_pc(regs) instruction_pointer(regs) | 38 | #define profile_pc(regs) instruction_pointer(regs) |
38 | #define user_stack_pointer(regs) ((regs)->sp) | 39 | #define user_stack_pointer(regs) ((regs)->sp) |
39 | 40 | ||
40 | /* Does the process account for user or for system time? */ | 41 | /* Does the process account for user or for system time? */ |
41 | #define user_mode(regs) (EX1_PL((regs)->ex1) == USER_PL) | 42 | #define user_mode(regs) (EX1_PL((regs)->ex1) < KERNEL_PL) |
42 | 43 | ||
43 | /* Fill in a struct pt_regs with the current kernel registers. */ | 44 | /* Fill in a struct pt_regs with the current kernel registers. */ |
44 | struct pt_regs *get_pt_regs(struct pt_regs *); | 45 | struct pt_regs *get_pt_regs(struct pt_regs *); |
@@ -79,8 +80,7 @@ extern void single_step_execve(void); | |||
79 | 80 | ||
80 | struct task_struct; | 81 | struct task_struct; |
81 | 82 | ||
82 | extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, | 83 | extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs); |
83 | int error_code); | ||
84 | 84 | ||
85 | #ifdef __tilegx__ | 85 | #ifdef __tilegx__ |
86 | /* We need this since sigval_t has a user pointer in it, for GETSIGINFO etc. */ | 86 | /* We need this since sigval_t has a user pointer in it, for GETSIGINFO etc. */ |
diff --git a/arch/tile/include/asm/sections.h b/arch/tile/include/asm/sections.h index 7d8a935a9238..5d5d3b739a6b 100644 --- a/arch/tile/include/asm/sections.h +++ b/arch/tile/include/asm/sections.h | |||
@@ -25,10 +25,16 @@ extern char _sinitdata[], _einitdata[]; | |||
25 | /* Write-once data is writable only till the end of initialization. */ | 25 | /* Write-once data is writable only till the end of initialization. */ |
26 | extern char __w1data_begin[], __w1data_end[]; | 26 | extern char __w1data_begin[], __w1data_end[]; |
27 | 27 | ||
28 | extern char vdso_start[], vdso_end[]; | ||
29 | #ifdef CONFIG_COMPAT | ||
30 | extern char vdso32_start[], vdso32_end[]; | ||
31 | #endif | ||
28 | 32 | ||
29 | /* Not exactly sections, but PC comparison points in the code. */ | 33 | /* Not exactly sections, but PC comparison points in the code. */ |
30 | extern char __rt_sigreturn[], __rt_sigreturn_end[]; | 34 | extern char __rt_sigreturn[], __rt_sigreturn_end[]; |
31 | #ifndef __tilegx__ | 35 | #ifdef __tilegx__ |
36 | extern char __start_unalign_asm_code[], __end_unalign_asm_code[]; | ||
37 | #else | ||
32 | extern char sys_cmpxchg[], __sys_cmpxchg_end[]; | 38 | extern char sys_cmpxchg[], __sys_cmpxchg_end[]; |
33 | extern char __sys_cmpxchg_grab_lock[]; | 39 | extern char __sys_cmpxchg_grab_lock[]; |
34 | extern char __start_atomic_asm_code[], __end_atomic_asm_code[]; | 40 | extern char __start_atomic_asm_code[], __end_atomic_asm_code[]; |
diff --git a/arch/tile/include/asm/setup.h b/arch/tile/include/asm/setup.h index d048888c5d9a..e98909033e5b 100644 --- a/arch/tile/include/asm/setup.h +++ b/arch/tile/include/asm/setup.h | |||
@@ -24,9 +24,8 @@ | |||
24 | */ | 24 | */ |
25 | #define MAXMEM_PFN PFN_DOWN(MAXMEM) | 25 | #define MAXMEM_PFN PFN_DOWN(MAXMEM) |
26 | 26 | ||
27 | int tile_console_write(const char *buf, int count); | ||
27 | void early_panic(const char *fmt, ...); | 28 | void early_panic(const char *fmt, ...); |
28 | void warn_early_printk(void); | ||
29 | void __init disable_early_printk(void); | ||
30 | 29 | ||
31 | /* Init-time routine to do tile-specific per-cpu setup. */ | 30 | /* Init-time routine to do tile-specific per-cpu setup. */ |
32 | void setup_cpu(int boot); | 31 | void setup_cpu(int boot); |
diff --git a/arch/tile/include/asm/smp.h b/arch/tile/include/asm/smp.h index 1aa759aeb5b3..9a326b64f7ae 100644 --- a/arch/tile/include/asm/smp.h +++ b/arch/tile/include/asm/smp.h | |||
@@ -101,10 +101,8 @@ void print_disabled_cpus(void); | |||
101 | extern struct cpumask cpu_lotar_map; | 101 | extern struct cpumask cpu_lotar_map; |
102 | #define cpu_is_valid_lotar(cpu) cpumask_test_cpu((cpu), &cpu_lotar_map) | 102 | #define cpu_is_valid_lotar(cpu) cpumask_test_cpu((cpu), &cpu_lotar_map) |
103 | 103 | ||
104 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
105 | /* Which processors are used for hash-for-home mapping */ | 104 | /* Which processors are used for hash-for-home mapping */ |
106 | extern struct cpumask hash_for_home_map; | 105 | extern struct cpumask hash_for_home_map; |
107 | #endif | ||
108 | 106 | ||
109 | /* Which cpus can have their cache flushed by hv_flush_remote(). */ | 107 | /* Which cpus can have their cache flushed by hv_flush_remote(). */ |
110 | extern struct cpumask cpu_cacheable_map; | 108 | extern struct cpumask cpu_cacheable_map; |
diff --git a/arch/tile/include/asm/spinlock_64.h b/arch/tile/include/asm/spinlock_64.h index 5f8b6a095fd8..9a12b9c7e5d3 100644 --- a/arch/tile/include/asm/spinlock_64.h +++ b/arch/tile/include/asm/spinlock_64.h | |||
@@ -27,7 +27,7 @@ | |||
27 | * Return the "current" portion of a ticket lock value, | 27 | * Return the "current" portion of a ticket lock value, |
28 | * i.e. the number that currently owns the lock. | 28 | * i.e. the number that currently owns the lock. |
29 | */ | 29 | */ |
30 | static inline int arch_spin_current(u32 val) | 30 | static inline u32 arch_spin_current(u32 val) |
31 | { | 31 | { |
32 | return val >> __ARCH_SPIN_CURRENT_SHIFT; | 32 | return val >> __ARCH_SPIN_CURRENT_SHIFT; |
33 | } | 33 | } |
@@ -36,7 +36,7 @@ static inline int arch_spin_current(u32 val) | |||
36 | * Return the "next" portion of a ticket lock value, | 36 | * Return the "next" portion of a ticket lock value, |
37 | * i.e. the number that the next task to try to acquire the lock will get. | 37 | * i.e. the number that the next task to try to acquire the lock will get. |
38 | */ | 38 | */ |
39 | static inline int arch_spin_next(u32 val) | 39 | static inline u32 arch_spin_next(u32 val) |
40 | { | 40 | { |
41 | return val & __ARCH_SPIN_NEXT_MASK; | 41 | return val & __ARCH_SPIN_NEXT_MASK; |
42 | } | 42 | } |
diff --git a/arch/tile/include/asm/string.h b/arch/tile/include/asm/string.h index 7535cf1a30e4..92b271bd9ebd 100644 --- a/arch/tile/include/asm/string.h +++ b/arch/tile/include/asm/string.h | |||
@@ -21,8 +21,10 @@ | |||
21 | #define __HAVE_ARCH_MEMMOVE | 21 | #define __HAVE_ARCH_MEMMOVE |
22 | #define __HAVE_ARCH_STRCHR | 22 | #define __HAVE_ARCH_STRCHR |
23 | #define __HAVE_ARCH_STRLEN | 23 | #define __HAVE_ARCH_STRLEN |
24 | #define __HAVE_ARCH_STRNLEN | ||
24 | 25 | ||
25 | extern __kernel_size_t strlen(const char *); | 26 | extern __kernel_size_t strlen(const char *); |
27 | extern __kernel_size_t strnlen(const char *, __kernel_size_t); | ||
26 | extern char *strchr(const char *s, int c); | 28 | extern char *strchr(const char *s, int c); |
27 | extern void *memchr(const void *s, int c, size_t n); | 29 | extern void *memchr(const void *s, int c, size_t n); |
28 | extern void *memset(void *, int, __kernel_size_t); | 30 | extern void *memset(void *, int, __kernel_size_t); |
diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h index d1733dee98a2..b8aa6df3e102 100644 --- a/arch/tile/include/asm/thread_info.h +++ b/arch/tile/include/asm/thread_info.h | |||
@@ -39,6 +39,11 @@ struct thread_info { | |||
39 | struct restart_block restart_block; | 39 | struct restart_block restart_block; |
40 | struct single_step_state *step_state; /* single step state | 40 | struct single_step_state *step_state; /* single step state |
41 | (if non-zero) */ | 41 | (if non-zero) */ |
42 | int align_ctl; /* controls unaligned access */ | ||
43 | #ifdef __tilegx__ | ||
44 | unsigned long unalign_jit_tmp[4]; /* temp r0..r3 storage */ | ||
45 | void __user *unalign_jit_base; /* unalign fixup JIT base */ | ||
46 | #endif | ||
42 | }; | 47 | }; |
43 | 48 | ||
44 | /* | 49 | /* |
@@ -56,6 +61,7 @@ struct thread_info { | |||
56 | .fn = do_no_restart_syscall, \ | 61 | .fn = do_no_restart_syscall, \ |
57 | }, \ | 62 | }, \ |
58 | .step_state = NULL, \ | 63 | .step_state = NULL, \ |
64 | .align_ctl = 0, \ | ||
59 | } | 65 | } |
60 | 66 | ||
61 | #define init_thread_info (init_thread_union.thread_info) | 67 | #define init_thread_info (init_thread_union.thread_info) |
diff --git a/arch/tile/include/asm/traps.h b/arch/tile/include/asm/traps.h index e28c3df4176a..4b99a1c3aab2 100644 --- a/arch/tile/include/asm/traps.h +++ b/arch/tile/include/asm/traps.h | |||
@@ -15,12 +15,13 @@ | |||
15 | #ifndef _ASM_TILE_TRAPS_H | 15 | #ifndef _ASM_TILE_TRAPS_H |
16 | #define _ASM_TILE_TRAPS_H | 16 | #define _ASM_TILE_TRAPS_H |
17 | 17 | ||
18 | #ifndef __ASSEMBLY__ | ||
18 | #include <arch/chip.h> | 19 | #include <arch/chip.h> |
19 | 20 | ||
20 | /* mm/fault.c */ | 21 | /* mm/fault.c */ |
21 | void do_page_fault(struct pt_regs *, int fault_num, | 22 | void do_page_fault(struct pt_regs *, int fault_num, |
22 | unsigned long address, unsigned long write); | 23 | unsigned long address, unsigned long write); |
23 | #if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() | 24 | #if CHIP_HAS_TILE_DMA() |
24 | void do_async_page_fault(struct pt_regs *); | 25 | void do_async_page_fault(struct pt_regs *); |
25 | #endif | 26 | #endif |
26 | 27 | ||
@@ -69,6 +70,16 @@ void gx_singlestep_handle(struct pt_regs *, int fault_num); | |||
69 | 70 | ||
70 | /* kernel/intvec_64.S */ | 71 | /* kernel/intvec_64.S */ |
71 | void fill_ra_stack(void); | 72 | void fill_ra_stack(void); |
73 | |||
74 | /* Handle unalign data fixup. */ | ||
75 | extern void do_unaligned(struct pt_regs *regs, int vecnum); | ||
76 | #endif | ||
77 | |||
78 | #endif /* __ASSEMBLY__ */ | ||
79 | |||
80 | #ifdef __tilegx__ | ||
81 | /* 128 byte JIT per unalign fixup. */ | ||
82 | #define UNALIGN_JIT_SHIFT 7 | ||
72 | #endif | 83 | #endif |
73 | 84 | ||
74 | #endif /* _ASM_TILE_TRAPS_H */ | 85 | #endif /* _ASM_TILE_TRAPS_H */ |
diff --git a/arch/tile/include/asm/uaccess.h b/arch/tile/include/asm/uaccess.h index e4d44bd7df27..b6cde3209b96 100644 --- a/arch/tile/include/asm/uaccess.h +++ b/arch/tile/include/asm/uaccess.h | |||
@@ -127,8 +127,10 @@ extern int fixup_exception(struct pt_regs *regs); | |||
127 | 127 | ||
128 | #ifdef __LP64__ | 128 | #ifdef __LP64__ |
129 | #define _ASM_PTR ".quad" | 129 | #define _ASM_PTR ".quad" |
130 | #define _ASM_ALIGN ".align 8" | ||
130 | #else | 131 | #else |
131 | #define _ASM_PTR ".long" | 132 | #define _ASM_PTR ".long" |
133 | #define _ASM_ALIGN ".align 4" | ||
132 | #endif | 134 | #endif |
133 | 135 | ||
134 | #define __get_user_asm(OP, x, ptr, ret) \ | 136 | #define __get_user_asm(OP, x, ptr, ret) \ |
@@ -137,6 +139,7 @@ extern int fixup_exception(struct pt_regs *regs); | |||
137 | "0: { movei %1, 0; movei %0, %3 }\n" \ | 139 | "0: { movei %1, 0; movei %0, %3 }\n" \ |
138 | "j 9f\n" \ | 140 | "j 9f\n" \ |
139 | ".section __ex_table,\"a\"\n" \ | 141 | ".section __ex_table,\"a\"\n" \ |
142 | _ASM_ALIGN "\n" \ | ||
140 | _ASM_PTR " 1b, 0b\n" \ | 143 | _ASM_PTR " 1b, 0b\n" \ |
141 | ".popsection\n" \ | 144 | ".popsection\n" \ |
142 | "9:" \ | 145 | "9:" \ |
@@ -168,6 +171,7 @@ extern int fixup_exception(struct pt_regs *regs); | |||
168 | "0: { movei %1, 0; movei %2, 0 }\n" \ | 171 | "0: { movei %1, 0; movei %2, 0 }\n" \ |
169 | "{ movei %0, %4; j 9f }\n" \ | 172 | "{ movei %0, %4; j 9f }\n" \ |
170 | ".section __ex_table,\"a\"\n" \ | 173 | ".section __ex_table,\"a\"\n" \ |
174 | ".align 4\n" \ | ||
171 | ".word 1b, 0b\n" \ | 175 | ".word 1b, 0b\n" \ |
172 | ".word 2b, 0b\n" \ | 176 | ".word 2b, 0b\n" \ |
173 | ".popsection\n" \ | 177 | ".popsection\n" \ |
@@ -224,6 +228,7 @@ extern int __get_user_bad(void) | |||
224 | ".pushsection .fixup,\"ax\"\n" \ | 228 | ".pushsection .fixup,\"ax\"\n" \ |
225 | "0: { movei %0, %3; j 9f }\n" \ | 229 | "0: { movei %0, %3; j 9f }\n" \ |
226 | ".section __ex_table,\"a\"\n" \ | 230 | ".section __ex_table,\"a\"\n" \ |
231 | _ASM_ALIGN "\n" \ | ||
227 | _ASM_PTR " 1b, 0b\n" \ | 232 | _ASM_PTR " 1b, 0b\n" \ |
228 | ".popsection\n" \ | 233 | ".popsection\n" \ |
229 | "9:" \ | 234 | "9:" \ |
@@ -248,6 +253,7 @@ extern int __get_user_bad(void) | |||
248 | ".pushsection .fixup,\"ax\"\n" \ | 253 | ".pushsection .fixup,\"ax\"\n" \ |
249 | "0: { movei %0, %4; j 9f }\n" \ | 254 | "0: { movei %0, %4; j 9f }\n" \ |
250 | ".section __ex_table,\"a\"\n" \ | 255 | ".section __ex_table,\"a\"\n" \ |
256 | ".align 4\n" \ | ||
251 | ".word 1b, 0b\n" \ | 257 | ".word 1b, 0b\n" \ |
252 | ".word 2b, 0b\n" \ | 258 | ".word 2b, 0b\n" \ |
253 | ".popsection\n" \ | 259 | ".popsection\n" \ |
@@ -567,37 +573,6 @@ static inline unsigned long __must_check flush_user( | |||
567 | } | 573 | } |
568 | 574 | ||
569 | /** | 575 | /** |
570 | * inv_user: - Invalidate a block of memory in user space from cache. | ||
571 | * @mem: Destination address, in user space. | ||
572 | * @len: Number of bytes to invalidate. | ||
573 | * | ||
574 | * Returns number of bytes that could not be invalidated. | ||
575 | * On success, this will be zero. | ||
576 | * | ||
577 | * Note that on Tile64, the "inv" operation is in fact a | ||
578 | * "flush and invalidate", so cache write-backs will occur prior | ||
579 | * to the cache being marked invalid. | ||
580 | */ | ||
581 | extern unsigned long inv_user_asm(void __user *mem, unsigned long len); | ||
582 | static inline unsigned long __must_check __inv_user( | ||
583 | void __user *mem, unsigned long len) | ||
584 | { | ||
585 | int retval; | ||
586 | |||
587 | might_fault(); | ||
588 | retval = inv_user_asm(mem, len); | ||
589 | mb_incoherent(); | ||
590 | return retval; | ||
591 | } | ||
592 | static inline unsigned long __must_check inv_user( | ||
593 | void __user *mem, unsigned long len) | ||
594 | { | ||
595 | if (access_ok(VERIFY_WRITE, mem, len)) | ||
596 | return __inv_user(mem, len); | ||
597 | return len; | ||
598 | } | ||
599 | |||
600 | /** | ||
601 | * finv_user: - Flush-inval a block of memory in user space from cache. | 576 | * finv_user: - Flush-inval a block of memory in user space from cache. |
602 | * @mem: Destination address, in user space. | 577 | * @mem: Destination address, in user space. |
603 | * @len: Number of bytes to invalidate. | 578 | * @len: Number of bytes to invalidate. |
diff --git a/arch/tile/include/asm/unaligned.h b/arch/tile/include/asm/unaligned.h index 37dfbe598872..5a58a0d11449 100644 --- a/arch/tile/include/asm/unaligned.h +++ b/arch/tile/include/asm/unaligned.h | |||
@@ -15,11 +15,15 @@ | |||
15 | #ifndef _ASM_TILE_UNALIGNED_H | 15 | #ifndef _ASM_TILE_UNALIGNED_H |
16 | #define _ASM_TILE_UNALIGNED_H | 16 | #define _ASM_TILE_UNALIGNED_H |
17 | 17 | ||
18 | #include <linux/unaligned/le_struct.h> | 18 | /* |
19 | #include <linux/unaligned/be_byteshift.h> | 19 | * We could implement faster get_unaligned_[be/le]64 using the ldna |
20 | #include <linux/unaligned/generic.h> | 20 | * instruction on tilegx; however, we need to either copy all of the |
21 | #define get_unaligned __get_unaligned_le | 21 | * other generic functions to here (which is pretty ugly) or else |
22 | #define put_unaligned __put_unaligned_le | 22 | * modify both the generic code and other arch code to allow arch |
23 | * specific unaligned data access functions. Given these functions | ||
24 | * are not often called, we'll stick with the generic version. | ||
25 | */ | ||
26 | #include <asm-generic/unaligned.h> | ||
23 | 27 | ||
24 | /* | 28 | /* |
25 | * Is the kernel doing fixups of unaligned accesses? If <0, no kernel | 29 | * Is the kernel doing fixups of unaligned accesses? If <0, no kernel |
diff --git a/arch/tile/include/asm/vdso.h b/arch/tile/include/asm/vdso.h new file mode 100644 index 000000000000..9f6a78d665fa --- /dev/null +++ b/arch/tile/include/asm/vdso.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #ifndef __TILE_VDSO_H__ | ||
16 | #define __TILE_VDSO_H__ | ||
17 | |||
18 | #include <linux/types.h> | ||
19 | |||
20 | /* | ||
21 | * Note about the vdso_data structure: | ||
22 | * | ||
23 | * NEVER USE THEM IN USERSPACE CODE DIRECTLY. The layout of the | ||
24 | * structure is supposed to be known only to the function in the vdso | ||
25 | * itself and may change without notice. | ||
26 | */ | ||
27 | |||
28 | struct vdso_data { | ||
29 | __u64 tz_update_count; /* Timezone atomicity ctr */ | ||
30 | __u64 tb_update_count; /* Timebase atomicity ctr */ | ||
31 | __u64 xtime_tod_stamp; /* TOD clock for xtime */ | ||
32 | __u64 xtime_clock_sec; /* Kernel time second */ | ||
33 | __u64 xtime_clock_nsec; /* Kernel time nanosecond */ | ||
34 | __u64 wtom_clock_sec; /* Wall to monotonic clock second */ | ||
35 | __u64 wtom_clock_nsec; /* Wall to monotonic clock nanosecond */ | ||
36 | __u32 mult; /* Cycle to nanosecond multiplier */ | ||
37 | __u32 shift; /* Cycle to nanosecond divisor (power of two) */ | ||
38 | __u32 tz_minuteswest; /* Minutes west of Greenwich */ | ||
39 | __u32 tz_dsttime; /* Type of dst correction */ | ||
40 | }; | ||
41 | |||
42 | extern struct vdso_data *vdso_data; | ||
43 | |||
44 | /* __vdso_rt_sigreturn is defined with the addresses in the vdso page. */ | ||
45 | extern void __vdso_rt_sigreturn(void); | ||
46 | |||
47 | extern int setup_vdso_pages(void); | ||
48 | |||
49 | #endif /* __TILE_VDSO_H__ */ | ||
diff --git a/arch/tile/include/gxio/iorpc_trio.h b/arch/tile/include/gxio/iorpc_trio.h index 58105c31228b..d95b96fd6c93 100644 --- a/arch/tile/include/gxio/iorpc_trio.h +++ b/arch/tile/include/gxio/iorpc_trio.h | |||
@@ -30,6 +30,7 @@ | |||
30 | 30 | ||
31 | #define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1404) | 31 | #define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1404) |
32 | 32 | ||
33 | #define GXIO_TRIO_OP_ALLOC_SCATTER_QUEUES IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140e) | ||
33 | #define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1412) | 34 | #define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1412) |
34 | 35 | ||
35 | #define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1414) | 36 | #define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1414) |
@@ -54,6 +55,10 @@ int gxio_trio_alloc_memory_maps(gxio_trio_context_t * context, | |||
54 | unsigned int flags); | 55 | unsigned int flags); |
55 | 56 | ||
56 | 57 | ||
58 | int gxio_trio_alloc_scatter_queues(gxio_trio_context_t * context, | ||
59 | unsigned int count, unsigned int first, | ||
60 | unsigned int flags); | ||
61 | |||
57 | int gxio_trio_alloc_pio_regions(gxio_trio_context_t * context, | 62 | int gxio_trio_alloc_pio_regions(gxio_trio_context_t * context, |
58 | unsigned int count, unsigned int first, | 63 | unsigned int count, unsigned int first, |
59 | unsigned int flags); | 64 | unsigned int flags); |
diff --git a/arch/tile/include/gxio/iorpc_uart.h b/arch/tile/include/gxio/iorpc_uart.h new file mode 100644 index 000000000000..55429d48ea56 --- /dev/null +++ b/arch/tile/include/gxio/iorpc_uart.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | /* This file is machine-generated; DO NOT EDIT! */ | ||
16 | #ifndef __GXIO_UART_LINUX_RPC_H__ | ||
17 | #define __GXIO_UART_LINUX_RPC_H__ | ||
18 | |||
19 | #include <hv/iorpc.h> | ||
20 | |||
21 | #include <hv/drv_uart_intf.h> | ||
22 | #include <gxio/uart.h> | ||
23 | #include <gxio/kiorpc.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <asm/pgtable.h> | ||
27 | |||
28 | #define GXIO_UART_OP_CFG_INTERRUPT IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1900) | ||
29 | #define GXIO_UART_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000) | ||
30 | #define GXIO_UART_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001) | ||
31 | |||
32 | int gxio_uart_cfg_interrupt(gxio_uart_context_t *context, int inter_x, | ||
33 | int inter_y, int inter_ipi, int inter_event); | ||
34 | |||
35 | int gxio_uart_get_mmio_base(gxio_uart_context_t *context, HV_PTE *base); | ||
36 | |||
37 | int gxio_uart_check_mmio_offset(gxio_uart_context_t *context, | ||
38 | unsigned long offset, unsigned long size); | ||
39 | |||
40 | #endif /* !__GXIO_UART_LINUX_RPC_H__ */ | ||
diff --git a/arch/tile/include/gxio/uart.h b/arch/tile/include/gxio/uart.h new file mode 100644 index 000000000000..438ee7e46c7b --- /dev/null +++ b/arch/tile/include/gxio/uart.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #ifndef _GXIO_UART_H_ | ||
16 | #define _GXIO_UART_H_ | ||
17 | |||
18 | #include "common.h" | ||
19 | |||
20 | #include <hv/drv_uart_intf.h> | ||
21 | #include <hv/iorpc.h> | ||
22 | |||
23 | /* | ||
24 | * | ||
25 | * An API for manipulating UART interface. | ||
26 | */ | ||
27 | |||
28 | /* | ||
29 | * | ||
30 | * The Rshim allows access to the processor's UART interface. | ||
31 | */ | ||
32 | |||
33 | /* A context object used to manage UART resources. */ | ||
34 | typedef struct { | ||
35 | |||
36 | /* File descriptor for calling up to the hypervisor. */ | ||
37 | int fd; | ||
38 | |||
39 | /* The VA at which our MMIO registers are mapped. */ | ||
40 | char *mmio_base; | ||
41 | |||
42 | } gxio_uart_context_t; | ||
43 | |||
44 | /* Request UART interrupts. | ||
45 | * | ||
46 | * Request that interrupts be delivered to a tile when the UART's | ||
47 | * Receive FIFO is written, or the Write FIFO is read. | ||
48 | * | ||
49 | * @param context Pointer to a properly initialized gxio_uart_context_t. | ||
50 | * @param bind_cpu_x X coordinate of CPU to which interrupt will be delivered. | ||
51 | * @param bind_cpu_y Y coordinate of CPU to which interrupt will be delivered. | ||
52 | * @param bind_interrupt IPI interrupt number. | ||
53 | * @param bind_event Sub-interrupt event bit number; a negative value can | ||
54 | * disable the interrupt. | ||
55 | * @return Zero if all of the requested UART events were successfully | ||
56 | * configured to interrupt. | ||
57 | */ | ||
58 | extern int gxio_uart_cfg_interrupt(gxio_uart_context_t *context, | ||
59 | int bind_cpu_x, | ||
60 | int bind_cpu_y, | ||
61 | int bind_interrupt, int bind_event); | ||
62 | |||
63 | /* Initialize a UART context. | ||
64 | * | ||
65 | * A properly initialized context must be obtained before any of the other | ||
66 | * gxio_uart routines may be used. | ||
67 | * | ||
68 | * @param context Pointer to a gxio_uart_context_t, which will be initialized | ||
69 | * by this routine, if it succeeds. | ||
70 | * @param uart_index Index of the UART to use. | ||
71 | * @return Zero if the context was successfully initialized, else a | ||
72 | * GXIO_ERR_xxx error code. | ||
73 | */ | ||
74 | extern int gxio_uart_init(gxio_uart_context_t *context, int uart_index); | ||
75 | |||
76 | /* Destroy a UART context. | ||
77 | * | ||
78 | * Once destroyed, a context may not be used with any gxio_uart routines | ||
79 | * other than gxio_uart_init(). After this routine returns, no further | ||
80 | * interrupts requested on this context will be delivered. The state and | ||
81 | * configuration of the pins which had been attached to this context are | ||
82 | * unchanged by this operation. | ||
83 | * | ||
84 | * @param context Pointer to a gxio_uart_context_t. | ||
85 | * @return Zero if the context was successfully destroyed, else a | ||
86 | * GXIO_ERR_xxx error code. | ||
87 | */ | ||
88 | extern int gxio_uart_destroy(gxio_uart_context_t *context); | ||
89 | |||
90 | /* Write UART register. | ||
91 | * @param context Pointer to a gxio_uart_context_t. | ||
92 | * @param offset UART register offset. | ||
93 | * @param word Data will be wrote to UART reigister. | ||
94 | */ | ||
95 | extern void gxio_uart_write(gxio_uart_context_t *context, uint64_t offset, | ||
96 | uint64_t word); | ||
97 | |||
98 | /* Read UART register. | ||
99 | * @param context Pointer to a gxio_uart_context_t. | ||
100 | * @param offset UART register offset. | ||
101 | * @return Data read from UART register. | ||
102 | */ | ||
103 | extern uint64_t gxio_uart_read(gxio_uart_context_t *context, uint64_t offset); | ||
104 | |||
105 | #endif /* _GXIO_UART_H_ */ | ||
diff --git a/arch/tile/include/hv/drv_trio_intf.h b/arch/tile/include/hv/drv_trio_intf.h index ef9f3f52ee27..237e04dee66c 100644 --- a/arch/tile/include/hv/drv_trio_intf.h +++ b/arch/tile/include/hv/drv_trio_intf.h | |||
@@ -64,8 +64,9 @@ struct pcie_port_property | |||
64 | * will not consider it an error if the link comes up as a x8 link. */ | 64 | * will not consider it an error if the link comes up as a x8 link. */ |
65 | uint8_t allow_x8: 1; | 65 | uint8_t allow_x8: 1; |
66 | 66 | ||
67 | /** Reserved. */ | 67 | /** If true, this link is connected to a device which may or may not |
68 | uint8_t reserved: 1; | 68 | * be present. */ |
69 | uint8_t removable: 1; | ||
69 | 70 | ||
70 | }; | 71 | }; |
71 | 72 | ||
@@ -167,6 +168,9 @@ pcie_stream_intr_config_sel_t; | |||
167 | struct pcie_trio_ports_property | 168 | struct pcie_trio_ports_property |
168 | { | 169 | { |
169 | struct pcie_port_property ports[TILEGX_TRIO_PCIES]; | 170 | struct pcie_port_property ports[TILEGX_TRIO_PCIES]; |
171 | |||
172 | /** Set if this TRIO belongs to a Gx72 device. */ | ||
173 | uint8_t is_gx72; | ||
170 | }; | 174 | }; |
171 | 175 | ||
172 | /* Flags indicating traffic class. */ | 176 | /* Flags indicating traffic class. */ |
diff --git a/arch/tile/include/hv/drv_uart_intf.h b/arch/tile/include/hv/drv_uart_intf.h new file mode 100644 index 000000000000..f5379e2404fd --- /dev/null +++ b/arch/tile/include/hv/drv_uart_intf.h | |||
@@ -0,0 +1,33 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | /** | ||
16 | * Interface definitions for the UART driver. | ||
17 | */ | ||
18 | |||
19 | #ifndef _SYS_HV_DRV_UART_INTF_H | ||
20 | #define _SYS_HV_DRV_UART_INTF_H | ||
21 | |||
22 | #include <arch/uart.h> | ||
23 | |||
24 | /** Number of UART ports supported. */ | ||
25 | #define TILEGX_UART_NR 2 | ||
26 | |||
27 | /** The mmap file offset (PA) of the UART MMIO region. */ | ||
28 | #define HV_UART_MMIO_OFFSET 0 | ||
29 | |||
30 | /** The maximum size of the UARTs MMIO region (64K Bytes). */ | ||
31 | #define HV_UART_MMIO_SIZE (1UL << 16) | ||
32 | |||
33 | #endif /* _SYS_HV_DRV_UART_INTF_H */ | ||
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h index 837dca5328c2..dfcdeb61ba34 100644 --- a/arch/tile/include/hv/hypervisor.h +++ b/arch/tile/include/hv/hypervisor.h | |||
@@ -318,8 +318,11 @@ | |||
318 | /** hv_set_pte_super_shift */ | 318 | /** hv_set_pte_super_shift */ |
319 | #define HV_DISPATCH_SET_PTE_SUPER_SHIFT 57 | 319 | #define HV_DISPATCH_SET_PTE_SUPER_SHIFT 57 |
320 | 320 | ||
321 | /** hv_console_set_ipi */ | ||
322 | #define HV_DISPATCH_CONSOLE_SET_IPI 63 | ||
323 | |||
321 | /** One more than the largest dispatch value */ | 324 | /** One more than the largest dispatch value */ |
322 | #define _HV_DISPATCH_END 58 | 325 | #define _HV_DISPATCH_END 64 |
323 | 326 | ||
324 | 327 | ||
325 | #ifndef __ASSEMBLER__ | 328 | #ifndef __ASSEMBLER__ |
@@ -541,14 +544,24 @@ typedef enum { | |||
541 | HV_CONFSTR_CPUMOD_REV = 18, | 544 | HV_CONFSTR_CPUMOD_REV = 18, |
542 | 545 | ||
543 | /** Human-readable CPU module description. */ | 546 | /** Human-readable CPU module description. */ |
544 | HV_CONFSTR_CPUMOD_DESC = 19 | 547 | HV_CONFSTR_CPUMOD_DESC = 19, |
548 | |||
549 | /** Per-tile hypervisor statistics. When this identifier is specified, | ||
550 | * the hv_confstr call takes two extra arguments. The first is the | ||
551 | * HV_XY_TO_LOTAR of the target tile's coordinates. The second is | ||
552 | * a flag word. The only current flag is the lowest bit, which means | ||
553 | * "zero out the stats instead of retrieving them"; in this case the | ||
554 | * buffer and buffer length are ignored. */ | ||
555 | HV_CONFSTR_HV_STATS = 20 | ||
545 | 556 | ||
546 | } HV_ConfstrQuery; | 557 | } HV_ConfstrQuery; |
547 | 558 | ||
548 | /** Query a configuration string from the hypervisor. | 559 | /** Query a configuration string from the hypervisor. |
549 | * | 560 | * |
550 | * @param query Identifier for the specific string to be retrieved | 561 | * @param query Identifier for the specific string to be retrieved |
551 | * (HV_CONFSTR_xxx). | 562 | * (HV_CONFSTR_xxx). Some strings may require or permit extra |
563 | * arguments to be appended which select specific objects to be | ||
564 | * described; see the string descriptions above. | ||
552 | * @param buf Buffer in which to place the string. | 565 | * @param buf Buffer in which to place the string. |
553 | * @param len Length of the buffer. | 566 | * @param len Length of the buffer. |
554 | * @return If query is valid, then the length of the corresponding string, | 567 | * @return If query is valid, then the length of the corresponding string, |
@@ -556,21 +569,16 @@ typedef enum { | |||
556 | * was truncated. If query is invalid, HV_EINVAL. If the specified | 569 | * was truncated. If query is invalid, HV_EINVAL. If the specified |
557 | * buffer is not writable by the client, HV_EFAULT. | 570 | * buffer is not writable by the client, HV_EFAULT. |
558 | */ | 571 | */ |
559 | int hv_confstr(HV_ConfstrQuery query, HV_VirtAddr buf, int len); | 572 | int hv_confstr(HV_ConfstrQuery query, HV_VirtAddr buf, int len, ...); |
560 | 573 | ||
561 | /** Tile coordinate */ | 574 | /** Tile coordinate */ |
562 | typedef struct | 575 | typedef struct |
563 | { | 576 | { |
564 | #ifndef __BIG_ENDIAN__ | ||
565 | /** X coordinate, relative to supervisor's top-left coordinate */ | 577 | /** X coordinate, relative to supervisor's top-left coordinate */ |
566 | int x; | 578 | int x; |
567 | 579 | ||
568 | /** Y coordinate, relative to supervisor's top-left coordinate */ | 580 | /** Y coordinate, relative to supervisor's top-left coordinate */ |
569 | int y; | 581 | int y; |
570 | #else | ||
571 | int y; | ||
572 | int x; | ||
573 | #endif | ||
574 | } HV_Coord; | 582 | } HV_Coord; |
575 | 583 | ||
576 | 584 | ||
@@ -585,6 +593,30 @@ typedef struct | |||
585 | */ | 593 | */ |
586 | int hv_get_ipi_pte(HV_Coord tile, int pl, HV_PTE* pte); | 594 | int hv_get_ipi_pte(HV_Coord tile, int pl, HV_PTE* pte); |
587 | 595 | ||
596 | /** Configure the console interrupt. | ||
597 | * | ||
598 | * When the console client interrupt is enabled, the hypervisor will | ||
599 | * deliver the specified IPI to the client in the following situations: | ||
600 | * | ||
601 | * - The console has at least one character available for input. | ||
602 | * | ||
603 | * - The console can accept new characters for output, and the last call | ||
604 | * to hv_console_write() did not write all of the characters requested | ||
605 | * by the client. | ||
606 | * | ||
607 | * Note that in some system configurations, console interrupt will not | ||
608 | * be available; clients should be prepared for this routine to fail and | ||
609 | * to fall back to periodic console polling in that case. | ||
610 | * | ||
611 | * @param ipi Index of the IPI register which will receive the interrupt. | ||
612 | * @param event IPI event number for console interrupt. If less than 0, | ||
613 | * disable the console IPI interrupt. | ||
614 | * @param coord Tile to be targeted for console interrupt. | ||
615 | * @return 0 on success, otherwise, HV_EINVAL if illegal parameter, | ||
616 | * HV_ENOTSUP if console interrupt are not available. | ||
617 | */ | ||
618 | int hv_console_set_ipi(int ipi, int event, HV_Coord coord); | ||
619 | |||
588 | #else /* !CHIP_HAS_IPI() */ | 620 | #else /* !CHIP_HAS_IPI() */ |
589 | 621 | ||
590 | /** A set of interrupts. */ | 622 | /** A set of interrupts. */ |
@@ -1092,13 +1124,8 @@ HV_VirtAddrRange hv_inquire_virtual(int idx); | |||
1092 | /** A range of ASID values. */ | 1124 | /** A range of ASID values. */ |
1093 | typedef struct | 1125 | typedef struct |
1094 | { | 1126 | { |
1095 | #ifndef __BIG_ENDIAN__ | ||
1096 | HV_ASID start; /**< First ASID in the range. */ | 1127 | HV_ASID start; /**< First ASID in the range. */ |
1097 | unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */ | 1128 | unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */ |
1098 | #else | ||
1099 | unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */ | ||
1100 | HV_ASID start; /**< First ASID in the range. */ | ||
1101 | #endif | ||
1102 | } HV_ASIDRange; | 1129 | } HV_ASIDRange; |
1103 | 1130 | ||
1104 | /** Returns information about a range of ASIDs. | 1131 | /** Returns information about a range of ASIDs. |
@@ -1422,7 +1449,6 @@ typedef enum | |||
1422 | /** Message recipient. */ | 1449 | /** Message recipient. */ |
1423 | typedef struct | 1450 | typedef struct |
1424 | { | 1451 | { |
1425 | #ifndef __BIG_ENDIAN__ | ||
1426 | /** X coordinate, relative to supervisor's top-left coordinate */ | 1452 | /** X coordinate, relative to supervisor's top-left coordinate */ |
1427 | unsigned int x:11; | 1453 | unsigned int x:11; |
1428 | 1454 | ||
@@ -1431,11 +1457,6 @@ typedef struct | |||
1431 | 1457 | ||
1432 | /** Status of this recipient */ | 1458 | /** Status of this recipient */ |
1433 | HV_Recip_State state:10; | 1459 | HV_Recip_State state:10; |
1434 | #else //__BIG_ENDIAN__ | ||
1435 | HV_Recip_State state:10; | ||
1436 | unsigned int y:11; | ||
1437 | unsigned int x:11; | ||
1438 | #endif | ||
1439 | } HV_Recipient; | 1460 | } HV_Recipient; |
1440 | 1461 | ||
1441 | /** Send a message to a set of recipients. | 1462 | /** Send a message to a set of recipients. |
diff --git a/arch/tile/include/uapi/arch/Kbuild b/arch/tile/include/uapi/arch/Kbuild index 4ebc34f4768d..97dfbecec6b6 100644 --- a/arch/tile/include/uapi/arch/Kbuild +++ b/arch/tile/include/uapi/arch/Kbuild | |||
@@ -1,7 +1,6 @@ | |||
1 | # UAPI Header export list | 1 | # UAPI Header export list |
2 | header-y += abi.h | 2 | header-y += abi.h |
3 | header-y += chip.h | 3 | header-y += chip.h |
4 | header-y += chip_tile64.h | ||
5 | header-y += chip_tilegx.h | 4 | header-y += chip_tilegx.h |
6 | header-y += chip_tilepro.h | 5 | header-y += chip_tilepro.h |
7 | header-y += icache.h | 6 | header-y += icache.h |
diff --git a/arch/tile/include/uapi/arch/chip.h b/arch/tile/include/uapi/arch/chip.h index 926d3db0e91e..4c91f90b9369 100644 --- a/arch/tile/include/uapi/arch/chip.h +++ b/arch/tile/include/uapi/arch/chip.h | |||
@@ -12,9 +12,7 @@ | |||
12 | * more details. | 12 | * more details. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #if __tile_chip__ == 0 | 15 | #if __tile_chip__ == 1 |
16 | #include <arch/chip_tile64.h> | ||
17 | #elif __tile_chip__ == 1 | ||
18 | #include <arch/chip_tilepro.h> | 16 | #include <arch/chip_tilepro.h> |
19 | #elif defined(__tilegx__) | 17 | #elif defined(__tilegx__) |
20 | #include <arch/chip_tilegx.h> | 18 | #include <arch/chip_tilegx.h> |
diff --git a/arch/tile/include/uapi/arch/chip_tile64.h b/arch/tile/include/uapi/arch/chip_tile64.h deleted file mode 100644 index 261aaba092d4..000000000000 --- a/arch/tile/include/uapi/arch/chip_tile64.h +++ /dev/null | |||
@@ -1,258 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * @file | ||
17 | * Global header file. | ||
18 | * This header file specifies defines for TILE64. | ||
19 | */ | ||
20 | |||
21 | #ifndef __ARCH_CHIP_H__ | ||
22 | #define __ARCH_CHIP_H__ | ||
23 | |||
24 | /** Specify chip version. | ||
25 | * When possible, prefer the CHIP_xxx symbols below for future-proofing. | ||
26 | * This is intended for cross-compiling; native compilation should | ||
27 | * use the predefined __tile_chip__ symbol. | ||
28 | */ | ||
29 | #define TILE_CHIP 0 | ||
30 | |||
31 | /** Specify chip revision. | ||
32 | * This provides for the case of a respin of a particular chip type; | ||
33 | * the normal value for this symbol is "0". | ||
34 | * This is intended for cross-compiling; native compilation should | ||
35 | * use the predefined __tile_chip_rev__ symbol. | ||
36 | */ | ||
37 | #define TILE_CHIP_REV 0 | ||
38 | |||
39 | /** The name of this architecture. */ | ||
40 | #define CHIP_ARCH_NAME "tile64" | ||
41 | |||
42 | /** The ELF e_machine type for binaries for this chip. */ | ||
43 | #define CHIP_ELF_TYPE() EM_TILE64 | ||
44 | |||
45 | /** The alternate ELF e_machine type for binaries for this chip. */ | ||
46 | #define CHIP_COMPAT_ELF_TYPE() 0x2506 | ||
47 | |||
48 | /** What is the native word size of the machine? */ | ||
49 | #define CHIP_WORD_SIZE() 32 | ||
50 | |||
51 | /** How many bits of a virtual address are used. Extra bits must be | ||
52 | * the sign extension of the low bits. | ||
53 | */ | ||
54 | #define CHIP_VA_WIDTH() 32 | ||
55 | |||
56 | /** How many bits are in a physical address? */ | ||
57 | #define CHIP_PA_WIDTH() 36 | ||
58 | |||
59 | /** Size of the L2 cache, in bytes. */ | ||
60 | #define CHIP_L2_CACHE_SIZE() 65536 | ||
61 | |||
62 | /** Log size of an L2 cache line in bytes. */ | ||
63 | #define CHIP_L2_LOG_LINE_SIZE() 6 | ||
64 | |||
65 | /** Size of an L2 cache line, in bytes. */ | ||
66 | #define CHIP_L2_LINE_SIZE() (1 << CHIP_L2_LOG_LINE_SIZE()) | ||
67 | |||
68 | /** Associativity of the L2 cache. */ | ||
69 | #define CHIP_L2_ASSOC() 2 | ||
70 | |||
71 | /** Size of the L1 data cache, in bytes. */ | ||
72 | #define CHIP_L1D_CACHE_SIZE() 8192 | ||
73 | |||
74 | /** Log size of an L1 data cache line in bytes. */ | ||
75 | #define CHIP_L1D_LOG_LINE_SIZE() 4 | ||
76 | |||
77 | /** Size of an L1 data cache line, in bytes. */ | ||
78 | #define CHIP_L1D_LINE_SIZE() (1 << CHIP_L1D_LOG_LINE_SIZE()) | ||
79 | |||
80 | /** Associativity of the L1 data cache. */ | ||
81 | #define CHIP_L1D_ASSOC() 2 | ||
82 | |||
83 | /** Size of the L1 instruction cache, in bytes. */ | ||
84 | #define CHIP_L1I_CACHE_SIZE() 8192 | ||
85 | |||
86 | /** Log size of an L1 instruction cache line in bytes. */ | ||
87 | #define CHIP_L1I_LOG_LINE_SIZE() 6 | ||
88 | |||
89 | /** Size of an L1 instruction cache line, in bytes. */ | ||
90 | #define CHIP_L1I_LINE_SIZE() (1 << CHIP_L1I_LOG_LINE_SIZE()) | ||
91 | |||
92 | /** Associativity of the L1 instruction cache. */ | ||
93 | #define CHIP_L1I_ASSOC() 1 | ||
94 | |||
95 | /** Stride with which flush instructions must be issued. */ | ||
96 | #define CHIP_FLUSH_STRIDE() CHIP_L2_LINE_SIZE() | ||
97 | |||
98 | /** Stride with which inv instructions must be issued. */ | ||
99 | #define CHIP_INV_STRIDE() CHIP_L1D_LINE_SIZE() | ||
100 | |||
101 | /** Stride with which finv instructions must be issued. */ | ||
102 | #define CHIP_FINV_STRIDE() CHIP_L1D_LINE_SIZE() | ||
103 | |||
104 | /** Can the local cache coherently cache data that is homed elsewhere? */ | ||
105 | #define CHIP_HAS_COHERENT_LOCAL_CACHE() 0 | ||
106 | |||
107 | /** How many simultaneous outstanding victims can the L2 cache have? */ | ||
108 | #define CHIP_MAX_OUTSTANDING_VICTIMS() 2 | ||
109 | |||
110 | /** Does the TLB support the NC and NOALLOC bits? */ | ||
111 | #define CHIP_HAS_NC_AND_NOALLOC_BITS() 0 | ||
112 | |||
113 | /** Does the chip support hash-for-home caching? */ | ||
114 | #define CHIP_HAS_CBOX_HOME_MAP() 0 | ||
115 | |||
116 | /** Number of entries in the chip's home map tables. */ | ||
117 | /* #define CHIP_CBOX_HOME_MAP_SIZE() -- does not apply to chip 0 */ | ||
118 | |||
119 | /** Do uncacheable requests miss in the cache regardless of whether | ||
120 | * there is matching data? */ | ||
121 | #define CHIP_HAS_ENFORCED_UNCACHEABLE_REQUESTS() 0 | ||
122 | |||
123 | /** Does the mf instruction wait for victims? */ | ||
124 | #define CHIP_HAS_MF_WAITS_FOR_VICTIMS() 1 | ||
125 | |||
126 | /** Does the chip have an "inv" instruction that doesn't also flush? */ | ||
127 | #define CHIP_HAS_INV() 0 | ||
128 | |||
129 | /** Does the chip have a "wh64" instruction? */ | ||
130 | #define CHIP_HAS_WH64() 0 | ||
131 | |||
132 | /** Does this chip have a 'dword_align' instruction? */ | ||
133 | #define CHIP_HAS_DWORD_ALIGN() 0 | ||
134 | |||
135 | /** Number of performance counters. */ | ||
136 | #define CHIP_PERFORMANCE_COUNTERS() 2 | ||
137 | |||
138 | /** Does this chip have auxiliary performance counters? */ | ||
139 | #define CHIP_HAS_AUX_PERF_COUNTERS() 0 | ||
140 | |||
141 | /** Is the CBOX_MSR1 SPR supported? */ | ||
142 | #define CHIP_HAS_CBOX_MSR1() 0 | ||
143 | |||
144 | /** Is the TILE_RTF_HWM SPR supported? */ | ||
145 | #define CHIP_HAS_TILE_RTF_HWM() 0 | ||
146 | |||
147 | /** Is the TILE_WRITE_PENDING SPR supported? */ | ||
148 | #define CHIP_HAS_TILE_WRITE_PENDING() 0 | ||
149 | |||
150 | /** Is the PROC_STATUS SPR supported? */ | ||
151 | #define CHIP_HAS_PROC_STATUS_SPR() 0 | ||
152 | |||
153 | /** Is the DSTREAM_PF SPR supported? */ | ||
154 | #define CHIP_HAS_DSTREAM_PF() 0 | ||
155 | |||
156 | /** Log of the number of mshims we have. */ | ||
157 | #define CHIP_LOG_NUM_MSHIMS() 2 | ||
158 | |||
159 | /** Are the bases of the interrupt vector areas fixed? */ | ||
160 | #define CHIP_HAS_FIXED_INTVEC_BASE() 1 | ||
161 | |||
162 | /** Are the interrupt masks split up into 2 SPRs? */ | ||
163 | #define CHIP_HAS_SPLIT_INTR_MASK() 1 | ||
164 | |||
165 | /** Is the cycle count split up into 2 SPRs? */ | ||
166 | #define CHIP_HAS_SPLIT_CYCLE() 1 | ||
167 | |||
168 | /** Does the chip have a static network? */ | ||
169 | #define CHIP_HAS_SN() 1 | ||
170 | |||
171 | /** Does the chip have a static network processor? */ | ||
172 | #define CHIP_HAS_SN_PROC() 1 | ||
173 | |||
174 | /** Size of the L1 static network processor instruction cache, in bytes. */ | ||
175 | #define CHIP_L1SNI_CACHE_SIZE() 2048 | ||
176 | |||
177 | /** Does the chip have DMA support in each tile? */ | ||
178 | #define CHIP_HAS_TILE_DMA() 1 | ||
179 | |||
180 | /** Does the chip have the second revision of the directly accessible | ||
181 | * dynamic networks? This encapsulates a number of characteristics, | ||
182 | * including the absence of the catch-all, the absence of inline message | ||
183 | * tags, the absence of support for network context-switching, and so on. | ||
184 | */ | ||
185 | #define CHIP_HAS_REV1_XDN() 0 | ||
186 | |||
187 | /** Does the chip have cmpexch and similar (fetchadd, exch, etc.)? */ | ||
188 | #define CHIP_HAS_CMPEXCH() 0 | ||
189 | |||
190 | /** Does the chip have memory-mapped I/O support? */ | ||
191 | #define CHIP_HAS_MMIO() 0 | ||
192 | |||
193 | /** Does the chip have post-completion interrupts? */ | ||
194 | #define CHIP_HAS_POST_COMPLETION_INTERRUPTS() 0 | ||
195 | |||
196 | /** Does the chip have native single step support? */ | ||
197 | #define CHIP_HAS_SINGLE_STEP() 0 | ||
198 | |||
199 | #ifndef __OPEN_SOURCE__ /* features only relevant to hypervisor-level code */ | ||
200 | |||
201 | /** How many entries are present in the instruction TLB? */ | ||
202 | #define CHIP_ITLB_ENTRIES() 8 | ||
203 | |||
204 | /** How many entries are present in the data TLB? */ | ||
205 | #define CHIP_DTLB_ENTRIES() 16 | ||
206 | |||
207 | /** How many MAF entries does the XAUI shim have? */ | ||
208 | #define CHIP_XAUI_MAF_ENTRIES() 16 | ||
209 | |||
210 | /** Does the memory shim have a source-id table? */ | ||
211 | #define CHIP_HAS_MSHIM_SRCID_TABLE() 1 | ||
212 | |||
213 | /** Does the L1 instruction cache clear on reset? */ | ||
214 | #define CHIP_HAS_L1I_CLEAR_ON_RESET() 0 | ||
215 | |||
216 | /** Does the chip come out of reset with valid coordinates on all tiles? | ||
217 | * Note that if defined, this also implies that the upper left is 1,1. | ||
218 | */ | ||
219 | #define CHIP_HAS_VALID_TILE_COORD_RESET() 0 | ||
220 | |||
221 | /** Does the chip have unified packet formats? */ | ||
222 | #define CHIP_HAS_UNIFIED_PACKET_FORMATS() 0 | ||
223 | |||
224 | /** Does the chip support write reordering? */ | ||
225 | #define CHIP_HAS_WRITE_REORDERING() 0 | ||
226 | |||
227 | /** Does the chip support Y-X routing as well as X-Y? */ | ||
228 | #define CHIP_HAS_Y_X_ROUTING() 0 | ||
229 | |||
230 | /** Is INTCTRL_3 managed with the correct MPL? */ | ||
231 | #define CHIP_HAS_INTCTRL_3_STATUS_FIX() 0 | ||
232 | |||
233 | /** Is it possible to configure the chip to be big-endian? */ | ||
234 | #define CHIP_HAS_BIG_ENDIAN_CONFIG() 0 | ||
235 | |||
236 | /** Is the CACHE_RED_WAY_OVERRIDDEN SPR supported? */ | ||
237 | #define CHIP_HAS_CACHE_RED_WAY_OVERRIDDEN() 0 | ||
238 | |||
239 | /** Is the DIAG_TRACE_WAY SPR supported? */ | ||
240 | #define CHIP_HAS_DIAG_TRACE_WAY() 0 | ||
241 | |||
242 | /** Is the MEM_STRIPE_CONFIG SPR supported? */ | ||
243 | #define CHIP_HAS_MEM_STRIPE_CONFIG() 0 | ||
244 | |||
245 | /** Are the TLB_PERF SPRs supported? */ | ||
246 | #define CHIP_HAS_TLB_PERF() 0 | ||
247 | |||
248 | /** Is the VDN_SNOOP_SHIM_CTL SPR supported? */ | ||
249 | #define CHIP_HAS_VDN_SNOOP_SHIM_CTL() 0 | ||
250 | |||
251 | /** Does the chip support rev1 DMA packets? */ | ||
252 | #define CHIP_HAS_REV1_DMA_PACKETS() 0 | ||
253 | |||
254 | /** Does the chip have an IPI shim? */ | ||
255 | #define CHIP_HAS_IPI() 0 | ||
256 | |||
257 | #endif /* !__OPEN_SOURCE__ */ | ||
258 | #endif /* __ARCH_CHIP_H__ */ | ||
diff --git a/arch/tile/include/uapi/arch/opcode_tilegx.h b/arch/tile/include/uapi/arch/opcode_tilegx.h index c14d02c81600..d76ff2db745e 100644 --- a/arch/tile/include/uapi/arch/opcode_tilegx.h +++ b/arch/tile/include/uapi/arch/opcode_tilegx.h | |||
@@ -61,6 +61,7 @@ typedef tilegx_bundle_bits tile_bundle_bits; | |||
61 | #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES | 61 | #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES |
62 | #define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \ | 62 | #define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \ |
63 | TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES | 63 | TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES |
64 | #define TILE_BPT_BUNDLE TILEGX_BPT_BUNDLE | ||
64 | 65 | ||
65 | /* 64-bit pattern for a { bpt ; nop } bundle. */ | 66 | /* 64-bit pattern for a { bpt ; nop } bundle. */ |
66 | #define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL | 67 | #define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL |
diff --git a/arch/tile/include/uapi/arch/opcode_tilepro.h b/arch/tile/include/uapi/arch/opcode_tilepro.h index 71b763b8ce83..4451cff1a861 100644 --- a/arch/tile/include/uapi/arch/opcode_tilepro.h +++ b/arch/tile/include/uapi/arch/opcode_tilepro.h | |||
@@ -71,6 +71,7 @@ typedef tilepro_bundle_bits tile_bundle_bits; | |||
71 | #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES | 71 | #define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES |
72 | #define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \ | 72 | #define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \ |
73 | TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES | 73 | TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES |
74 | #define TILE_BPT_BUNDLE TILEPRO_BPT_BUNDLE | ||
74 | 75 | ||
75 | /* 64-bit pattern for a { bpt ; nop } bundle. */ | 76 | /* 64-bit pattern for a { bpt ; nop } bundle. */ |
76 | #define TILEPRO_BPT_BUNDLE 0x400b3cae70166000ULL | 77 | #define TILEPRO_BPT_BUNDLE 0x400b3cae70166000ULL |
diff --git a/arch/tile/include/uapi/arch/spr_def_32.h b/arch/tile/include/uapi/arch/spr_def_32.h index c689446e6284..78daa3146d25 100644 --- a/arch/tile/include/uapi/arch/spr_def_32.h +++ b/arch/tile/include/uapi/arch/spr_def_32.h | |||
@@ -200,8 +200,6 @@ | |||
200 | #define SPR_SIM_CONTROL 0x4e0c | 200 | #define SPR_SIM_CONTROL 0x4e0c |
201 | #define SPR_SNCTL 0x0805 | 201 | #define SPR_SNCTL 0x0805 |
202 | #define SPR_SNCTL__FRZFABRIC_MASK 0x1 | 202 | #define SPR_SNCTL__FRZFABRIC_MASK 0x1 |
203 | #define SPR_SNCTL__FRZPROC_MASK 0x2 | ||
204 | #define SPR_SNPC 0x080b | ||
205 | #define SPR_SNSTATIC 0x080c | 203 | #define SPR_SNSTATIC 0x080c |
206 | #define SPR_SYSTEM_SAVE_0_0 0x4b00 | 204 | #define SPR_SYSTEM_SAVE_0_0 0x4b00 |
207 | #define SPR_SYSTEM_SAVE_0_1 0x4b01 | 205 | #define SPR_SYSTEM_SAVE_0_1 0x4b01 |
diff --git a/arch/tile/include/uapi/asm/auxvec.h b/arch/tile/include/uapi/asm/auxvec.h index 1d393edb0641..c93e92709f14 100644 --- a/arch/tile/include/uapi/asm/auxvec.h +++ b/arch/tile/include/uapi/asm/auxvec.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #ifndef _ASM_TILE_AUXVEC_H | 15 | #ifndef _ASM_TILE_AUXVEC_H |
16 | #define _ASM_TILE_AUXVEC_H | 16 | #define _ASM_TILE_AUXVEC_H |
17 | 17 | ||
18 | /* No extensions to auxvec */ | 18 | /* The vDSO location. */ |
19 | #define AT_SYSINFO_EHDR 33 | ||
19 | 20 | ||
20 | #endif /* _ASM_TILE_AUXVEC_H */ | 21 | #endif /* _ASM_TILE_AUXVEC_H */ |
diff --git a/arch/tile/include/uapi/asm/cachectl.h b/arch/tile/include/uapi/asm/cachectl.h index af4c9f9154d1..572ddcad2090 100644 --- a/arch/tile/include/uapi/asm/cachectl.h +++ b/arch/tile/include/uapi/asm/cachectl.h | |||
@@ -29,8 +29,8 @@ | |||
29 | * to honor the arguments at some point.) | 29 | * to honor the arguments at some point.) |
30 | * | 30 | * |
31 | * Flush and invalidation of memory can normally be performed with the | 31 | * Flush and invalidation of memory can normally be performed with the |
32 | * __insn_flush(), __insn_inv(), and __insn_finv() instructions from | 32 | * __insn_flush() and __insn_finv() instructions from userspace. |
33 | * userspace. The DCACHE option to the system call allows userspace | 33 | * The DCACHE option to the system call allows userspace |
34 | * to flush the entire L1+L2 data cache from the core. In this case, | 34 | * to flush the entire L1+L2 data cache from the core. In this case, |
35 | * the address and length arguments are not used. The DCACHE flush is | 35 | * the address and length arguments are not used. The DCACHE flush is |
36 | * restricted to the current core, not all cores in the address space. | 36 | * restricted to the current core, not all cores in the address space. |
diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile index 5334be8e2538..27a2bf39dae8 100644 --- a/arch/tile/kernel/Makefile +++ b/arch/tile/kernel/Makefile | |||
@@ -3,11 +3,17 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | extra-y := vmlinux.lds head_$(BITS).o | 5 | extra-y := vmlinux.lds head_$(BITS).o |
6 | obj-y := backtrace.o entry.o irq.o messaging.o \ | 6 | obj-y := backtrace.o entry.o hvglue.o irq.o messaging.o \ |
7 | pci-dma.o proc.o process.o ptrace.o reboot.o \ | 7 | pci-dma.o proc.o process.o ptrace.o reboot.o \ |
8 | setup.o signal.o single_step.o stack.o sys.o sysfs.o time.o traps.o \ | 8 | setup.o signal.o single_step.o stack.o sys.o \ |
9 | sysfs.o time.o traps.o unaligned.o vdso.o \ | ||
9 | intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o | 10 | intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o |
10 | 11 | ||
12 | ifdef CONFIG_FUNCTION_TRACER | ||
13 | CFLAGS_REMOVE_ftrace.o = -pg | ||
14 | CFLAGS_REMOVE_early_printk.o = -pg | ||
15 | endif | ||
16 | |||
11 | obj-$(CONFIG_HARDWALL) += hardwall.o | 17 | obj-$(CONFIG_HARDWALL) += hardwall.o |
12 | obj-$(CONFIG_COMPAT) += compat.o compat_signal.o | 18 | obj-$(CONFIG_COMPAT) += compat.o compat_signal.o |
13 | obj-$(CONFIG_SMP) += smpboot.o smp.o tlb.o | 19 | obj-$(CONFIG_SMP) += smpboot.o smp.o tlb.o |
@@ -20,3 +26,9 @@ else | |||
20 | obj-$(CONFIG_PCI) += pci.o | 26 | obj-$(CONFIG_PCI) += pci.o |
21 | endif | 27 | endif |
22 | obj-$(CONFIG_TILE_USB) += usb.o | 28 | obj-$(CONFIG_TILE_USB) += usb.o |
29 | obj-$(CONFIG_TILE_HVGLUE_TRACE) += hvglue_trace.o | ||
30 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount_64.o | ||
31 | obj-$(CONFIG_KPROBES) += kprobes.o | ||
32 | obj-$(CONFIG_KGDB) += kgdb.o | ||
33 | |||
34 | obj-y += vdso/ | ||
diff --git a/arch/tile/kernel/asm-offsets.c b/arch/tile/kernel/asm-offsets.c index 01ddf19cc36d..375e7c321eef 100644 --- a/arch/tile/kernel/asm-offsets.c +++ b/arch/tile/kernel/asm-offsets.c | |||
@@ -14,13 +14,6 @@ | |||
14 | * Generates definitions from c-type structures used by assembly sources. | 14 | * Generates definitions from c-type structures used by assembly sources. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | #include <linux/kbuild.h> | ||
18 | #include <linux/thread_info.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/hardirq.h> | ||
21 | #include <linux/ptrace.h> | ||
22 | #include <hv/hypervisor.h> | ||
23 | |||
24 | /* Check for compatible compiler early in the build. */ | 17 | /* Check for compatible compiler early in the build. */ |
25 | #ifdef CONFIG_TILEGX | 18 | #ifdef CONFIG_TILEGX |
26 | # ifndef __tilegx__ | 19 | # ifndef __tilegx__ |
@@ -31,46 +24,61 @@ | |||
31 | # endif | 24 | # endif |
32 | #else | 25 | #else |
33 | # ifdef __tilegx__ | 26 | # ifdef __tilegx__ |
34 | # error Can not build TILEPro/TILE64 configurations with tilegx compiler | 27 | # error Can not build TILEPro configurations with tilegx compiler |
35 | # endif | 28 | # endif |
36 | #endif | 29 | #endif |
37 | 30 | ||
31 | #include <linux/kbuild.h> | ||
32 | #include <linux/thread_info.h> | ||
33 | #include <linux/sched.h> | ||
34 | #include <linux/hardirq.h> | ||
35 | #include <linux/ptrace.h> | ||
36 | #include <hv/hypervisor.h> | ||
37 | |||
38 | void foo(void) | 38 | void foo(void) |
39 | { | 39 | { |
40 | DEFINE(SINGLESTEP_STATE_BUFFER_OFFSET, \ | 40 | DEFINE(SINGLESTEP_STATE_BUFFER_OFFSET, |
41 | offsetof(struct single_step_state, buffer)); | 41 | offsetof(struct single_step_state, buffer)); |
42 | DEFINE(SINGLESTEP_STATE_FLAGS_OFFSET, \ | 42 | DEFINE(SINGLESTEP_STATE_FLAGS_OFFSET, |
43 | offsetof(struct single_step_state, flags)); | 43 | offsetof(struct single_step_state, flags)); |
44 | DEFINE(SINGLESTEP_STATE_ORIG_PC_OFFSET, \ | 44 | DEFINE(SINGLESTEP_STATE_ORIG_PC_OFFSET, |
45 | offsetof(struct single_step_state, orig_pc)); | 45 | offsetof(struct single_step_state, orig_pc)); |
46 | DEFINE(SINGLESTEP_STATE_NEXT_PC_OFFSET, \ | 46 | DEFINE(SINGLESTEP_STATE_NEXT_PC_OFFSET, |
47 | offsetof(struct single_step_state, next_pc)); | 47 | offsetof(struct single_step_state, next_pc)); |
48 | DEFINE(SINGLESTEP_STATE_BRANCH_NEXT_PC_OFFSET, \ | 48 | DEFINE(SINGLESTEP_STATE_BRANCH_NEXT_PC_OFFSET, |
49 | offsetof(struct single_step_state, branch_next_pc)); | 49 | offsetof(struct single_step_state, branch_next_pc)); |
50 | DEFINE(SINGLESTEP_STATE_UPDATE_VALUE_OFFSET, \ | 50 | DEFINE(SINGLESTEP_STATE_UPDATE_VALUE_OFFSET, |
51 | offsetof(struct single_step_state, update_value)); | 51 | offsetof(struct single_step_state, update_value)); |
52 | 52 | ||
53 | DEFINE(THREAD_INFO_TASK_OFFSET, \ | 53 | DEFINE(THREAD_INFO_TASK_OFFSET, |
54 | offsetof(struct thread_info, task)); | 54 | offsetof(struct thread_info, task)); |
55 | DEFINE(THREAD_INFO_FLAGS_OFFSET, \ | 55 | DEFINE(THREAD_INFO_FLAGS_OFFSET, |
56 | offsetof(struct thread_info, flags)); | 56 | offsetof(struct thread_info, flags)); |
57 | DEFINE(THREAD_INFO_STATUS_OFFSET, \ | 57 | DEFINE(THREAD_INFO_STATUS_OFFSET, |
58 | offsetof(struct thread_info, status)); | 58 | offsetof(struct thread_info, status)); |
59 | DEFINE(THREAD_INFO_HOMECACHE_CPU_OFFSET, \ | 59 | DEFINE(THREAD_INFO_HOMECACHE_CPU_OFFSET, |
60 | offsetof(struct thread_info, homecache_cpu)); | 60 | offsetof(struct thread_info, homecache_cpu)); |
61 | DEFINE(THREAD_INFO_STEP_STATE_OFFSET, \ | 61 | DEFINE(THREAD_INFO_PREEMPT_COUNT_OFFSET, |
62 | offsetof(struct thread_info, preempt_count)); | ||
63 | DEFINE(THREAD_INFO_STEP_STATE_OFFSET, | ||
62 | offsetof(struct thread_info, step_state)); | 64 | offsetof(struct thread_info, step_state)); |
65 | #ifdef __tilegx__ | ||
66 | DEFINE(THREAD_INFO_UNALIGN_JIT_BASE_OFFSET, | ||
67 | offsetof(struct thread_info, unalign_jit_base)); | ||
68 | DEFINE(THREAD_INFO_UNALIGN_JIT_TMP_OFFSET, | ||
69 | offsetof(struct thread_info, unalign_jit_tmp)); | ||
70 | #endif | ||
63 | 71 | ||
64 | DEFINE(TASK_STRUCT_THREAD_KSP_OFFSET, | 72 | DEFINE(TASK_STRUCT_THREAD_KSP_OFFSET, |
65 | offsetof(struct task_struct, thread.ksp)); | 73 | offsetof(struct task_struct, thread.ksp)); |
66 | DEFINE(TASK_STRUCT_THREAD_PC_OFFSET, | 74 | DEFINE(TASK_STRUCT_THREAD_PC_OFFSET, |
67 | offsetof(struct task_struct, thread.pc)); | 75 | offsetof(struct task_struct, thread.pc)); |
68 | 76 | ||
69 | DEFINE(HV_TOPOLOGY_WIDTH_OFFSET, \ | 77 | DEFINE(HV_TOPOLOGY_WIDTH_OFFSET, |
70 | offsetof(HV_Topology, width)); | 78 | offsetof(HV_Topology, width)); |
71 | DEFINE(HV_TOPOLOGY_HEIGHT_OFFSET, \ | 79 | DEFINE(HV_TOPOLOGY_HEIGHT_OFFSET, |
72 | offsetof(HV_Topology, height)); | 80 | offsetof(HV_Topology, height)); |
73 | 81 | ||
74 | DEFINE(IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET, \ | 82 | DEFINE(IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET, |
75 | offsetof(irq_cpustat_t, irq_syscall_count)); | 83 | offsetof(irq_cpustat_t, irq_syscall_count)); |
76 | } | 84 | } |
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index d0a052e725be..85e00b2f39bf 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <asm/ucontext.h> | 32 | #include <asm/ucontext.h> |
33 | #include <asm/sigframe.h> | 33 | #include <asm/sigframe.h> |
34 | #include <asm/syscalls.h> | 34 | #include <asm/syscalls.h> |
35 | #include <asm/vdso.h> | ||
35 | #include <arch/interrupts.h> | 36 | #include <arch/interrupts.h> |
36 | 37 | ||
37 | struct compat_ucontext { | 38 | struct compat_ucontext { |
@@ -227,7 +228,7 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
227 | if (err) | 228 | if (err) |
228 | goto give_sigsegv; | 229 | goto give_sigsegv; |
229 | 230 | ||
230 | restorer = VDSO_BASE; | 231 | restorer = VDSO_SYM(&__vdso_rt_sigreturn); |
231 | if (ka->sa.sa_flags & SA_RESTORER) | 232 | if (ka->sa.sa_flags & SA_RESTORER) |
232 | restorer = ptr_to_compat_reg(ka->sa.sa_restorer); | 233 | restorer = ptr_to_compat_reg(ka->sa.sa_restorer); |
233 | 234 | ||
diff --git a/arch/tile/kernel/early_printk.c b/arch/tile/kernel/early_printk.c index 34d72a151bf3..b608e00e7f6d 100644 --- a/arch/tile/kernel/early_printk.c +++ b/arch/tile/kernel/early_printk.c | |||
@@ -23,19 +23,24 @@ | |||
23 | 23 | ||
24 | static void early_hv_write(struct console *con, const char *s, unsigned n) | 24 | static void early_hv_write(struct console *con, const char *s, unsigned n) |
25 | { | 25 | { |
26 | hv_console_write((HV_VirtAddr) s, n); | 26 | tile_console_write(s, n); |
27 | |||
28 | /* | ||
29 | * Convert NL to NLCR (close enough to CRNL) during early boot. | ||
30 | * We assume newlines are at the ends of strings, which turns out | ||
31 | * to be good enough for early boot console output. | ||
32 | */ | ||
33 | if (n && s[n-1] == '\n') | ||
34 | tile_console_write("\r", 1); | ||
27 | } | 35 | } |
28 | 36 | ||
29 | static struct console early_hv_console = { | 37 | static struct console early_hv_console = { |
30 | .name = "earlyhv", | 38 | .name = "earlyhv", |
31 | .write = early_hv_write, | 39 | .write = early_hv_write, |
32 | .flags = CON_PRINTBUFFER, | 40 | .flags = CON_PRINTBUFFER | CON_BOOT, |
33 | .index = -1, | 41 | .index = -1, |
34 | }; | 42 | }; |
35 | 43 | ||
36 | /* Direct interface for emergencies */ | ||
37 | static int early_console_complete; | ||
38 | |||
39 | void early_panic(const char *fmt, ...) | 44 | void early_panic(const char *fmt, ...) |
40 | { | 45 | { |
41 | va_list ap; | 46 | va_list ap; |
@@ -43,51 +48,21 @@ void early_panic(const char *fmt, ...) | |||
43 | va_start(ap, fmt); | 48 | va_start(ap, fmt); |
44 | early_printk("Kernel panic - not syncing: "); | 49 | early_printk("Kernel panic - not syncing: "); |
45 | early_vprintk(fmt, ap); | 50 | early_vprintk(fmt, ap); |
46 | early_console->write(early_console, "\n", 1); | 51 | early_printk("\n"); |
47 | va_end(ap); | 52 | va_end(ap); |
48 | dump_stack(); | 53 | dump_stack(); |
49 | hv_halt(); | 54 | hv_halt(); |
50 | } | 55 | } |
51 | 56 | ||
52 | static int __initdata keep_early; | ||
53 | |||
54 | static int __init setup_early_printk(char *str) | 57 | static int __init setup_early_printk(char *str) |
55 | { | 58 | { |
56 | if (early_console) | 59 | if (early_console) |
57 | return 1; | 60 | return 1; |
58 | 61 | ||
59 | if (str != NULL && strncmp(str, "keep", 4) == 0) | ||
60 | keep_early = 1; | ||
61 | |||
62 | early_console = &early_hv_console; | 62 | early_console = &early_hv_console; |
63 | register_console(early_console); | 63 | register_console(early_console); |
64 | 64 | ||
65 | return 0; | 65 | return 0; |
66 | } | 66 | } |
67 | 67 | ||
68 | void __init disable_early_printk(void) | ||
69 | { | ||
70 | early_console_complete = 1; | ||
71 | if (!early_console) | ||
72 | return; | ||
73 | if (!keep_early) { | ||
74 | early_printk("disabling early console\n"); | ||
75 | unregister_console(early_console); | ||
76 | early_console = NULL; | ||
77 | } else { | ||
78 | early_printk("keeping early console\n"); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | void warn_early_printk(void) | ||
83 | { | ||
84 | if (early_console_complete || early_console) | ||
85 | return; | ||
86 | early_printk("\ | ||
87 | Machine shutting down before console output is fully initialized.\n\ | ||
88 | You may wish to reboot and add the option 'earlyprintk' to your\n\ | ||
89 | boot command line to see any diagnostic early console output.\n\ | ||
90 | "); | ||
91 | } | ||
92 | |||
93 | early_param("earlyprintk", setup_early_printk); | 68 | early_param("earlyprintk", setup_early_printk); |
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S index f116cb0bce20..3d9175992a20 100644 --- a/arch/tile/kernel/entry.S +++ b/arch/tile/kernel/entry.S | |||
@@ -27,22 +27,6 @@ STD_ENTRY(current_text_addr) | |||
27 | { move r0, lr; jrp lr } | 27 | { move r0, lr; jrp lr } |
28 | STD_ENDPROC(current_text_addr) | 28 | STD_ENDPROC(current_text_addr) |
29 | 29 | ||
30 | /* | ||
31 | * We don't run this function directly, but instead copy it to a page | ||
32 | * we map into every user process. See vdso_setup(). | ||
33 | * | ||
34 | * Note that libc has a copy of this function that it uses to compare | ||
35 | * against the PC when a stack backtrace ends, so if this code is | ||
36 | * changed, the libc implementation(s) should also be updated. | ||
37 | */ | ||
38 | .pushsection .data | ||
39 | ENTRY(__rt_sigreturn) | ||
40 | moveli TREG_SYSCALL_NR_NAME,__NR_rt_sigreturn | ||
41 | swint1 | ||
42 | ENDPROC(__rt_sigreturn) | ||
43 | ENTRY(__rt_sigreturn_end) | ||
44 | .popsection | ||
45 | |||
46 | STD_ENTRY(dump_stack) | 30 | STD_ENTRY(dump_stack) |
47 | { move r2, lr; lnk r1 } | 31 | { move r2, lr; lnk r1 } |
48 | { move r4, r52; addli r1, r1, dump_stack - . } | 32 | { move r4, r52; addli r1, r1, dump_stack - . } |
diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c new file mode 100644 index 000000000000..f1c452092eeb --- /dev/null +++ b/arch/tile/kernel/ftrace.c | |||
@@ -0,0 +1,246 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * TILE-Gx specific ftrace support | ||
15 | */ | ||
16 | |||
17 | #include <linux/ftrace.h> | ||
18 | #include <linux/uaccess.h> | ||
19 | |||
20 | #include <asm/cacheflush.h> | ||
21 | #include <asm/ftrace.h> | ||
22 | #include <asm/sections.h> | ||
23 | |||
24 | #include <arch/opcode.h> | ||
25 | |||
26 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
27 | |||
28 | static inline tilegx_bundle_bits NOP(void) | ||
29 | { | ||
30 | return create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) | | ||
31 | create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | | ||
32 | create_Opcode_X0(RRR_0_OPCODE_X0) | | ||
33 | create_UnaryOpcodeExtension_X1(NOP_UNARY_OPCODE_X1) | | ||
34 | create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) | | ||
35 | create_Opcode_X1(RRR_0_OPCODE_X1); | ||
36 | } | ||
37 | |||
38 | static int machine_stopped __read_mostly; | ||
39 | |||
40 | int ftrace_arch_code_modify_prepare(void) | ||
41 | { | ||
42 | machine_stopped = 1; | ||
43 | return 0; | ||
44 | } | ||
45 | |||
46 | int ftrace_arch_code_modify_post_process(void) | ||
47 | { | ||
48 | flush_icache_range(0, CHIP_L1I_CACHE_SIZE()); | ||
49 | machine_stopped = 0; | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * Put { move r10, lr; jal ftrace_caller } in a bundle, this lets dynamic | ||
55 | * tracer just add one cycle overhead to every kernel function when disabled. | ||
56 | */ | ||
57 | static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, | ||
58 | bool link) | ||
59 | { | ||
60 | tilegx_bundle_bits opcode_x0, opcode_x1; | ||
61 | long pcrel_by_instr = (addr - pc) >> TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES; | ||
62 | |||
63 | if (link) { | ||
64 | /* opcode: jal addr */ | ||
65 | opcode_x1 = | ||
66 | create_Opcode_X1(JUMP_OPCODE_X1) | | ||
67 | create_JumpOpcodeExtension_X1(JAL_JUMP_OPCODE_X1) | | ||
68 | create_JumpOff_X1(pcrel_by_instr); | ||
69 | } else { | ||
70 | /* opcode: j addr */ | ||
71 | opcode_x1 = | ||
72 | create_Opcode_X1(JUMP_OPCODE_X1) | | ||
73 | create_JumpOpcodeExtension_X1(J_JUMP_OPCODE_X1) | | ||
74 | create_JumpOff_X1(pcrel_by_instr); | ||
75 | } | ||
76 | |||
77 | if (addr == FTRACE_ADDR) { | ||
78 | /* opcode: or r10, lr, zero */ | ||
79 | opcode_x0 = | ||
80 | create_Dest_X0(10) | | ||
81 | create_SrcA_X0(TREG_LR) | | ||
82 | create_SrcB_X0(TREG_ZERO) | | ||
83 | create_RRROpcodeExtension_X0(OR_RRR_0_OPCODE_X0) | | ||
84 | create_Opcode_X0(RRR_0_OPCODE_X0); | ||
85 | } else { | ||
86 | /* opcode: fnop */ | ||
87 | opcode_x0 = | ||
88 | create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) | | ||
89 | create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | | ||
90 | create_Opcode_X0(RRR_0_OPCODE_X0); | ||
91 | } | ||
92 | |||
93 | return opcode_x1 | opcode_x0; | ||
94 | } | ||
95 | |||
96 | static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec) | ||
97 | { | ||
98 | return NOP(); | ||
99 | } | ||
100 | |||
101 | static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) | ||
102 | { | ||
103 | return ftrace_gen_branch(pc, addr, true); | ||
104 | } | ||
105 | |||
106 | static int ftrace_modify_code(unsigned long pc, unsigned long old, | ||
107 | unsigned long new) | ||
108 | { | ||
109 | unsigned long pc_wr; | ||
110 | |||
111 | /* Check if the address is in kernel text space and module space. */ | ||
112 | if (!kernel_text_address(pc)) | ||
113 | return -EINVAL; | ||
114 | |||
115 | /* Operate on writable kernel text mapping. */ | ||
116 | pc_wr = pc - MEM_SV_START + PAGE_OFFSET; | ||
117 | |||
118 | if (probe_kernel_write((void *)pc_wr, &new, MCOUNT_INSN_SIZE)) | ||
119 | return -EPERM; | ||
120 | |||
121 | smp_wmb(); | ||
122 | |||
123 | if (!machine_stopped && num_online_cpus() > 1) | ||
124 | flush_icache_range(pc, pc + MCOUNT_INSN_SIZE); | ||
125 | |||
126 | return 0; | ||
127 | } | ||
128 | |||
129 | int ftrace_update_ftrace_func(ftrace_func_t func) | ||
130 | { | ||
131 | unsigned long pc, old; | ||
132 | unsigned long new; | ||
133 | int ret; | ||
134 | |||
135 | pc = (unsigned long)&ftrace_call; | ||
136 | memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE); | ||
137 | new = ftrace_call_replace(pc, (unsigned long)func); | ||
138 | |||
139 | ret = ftrace_modify_code(pc, old, new); | ||
140 | |||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | ||
145 | { | ||
146 | unsigned long new, old; | ||
147 | unsigned long ip = rec->ip; | ||
148 | |||
149 | old = ftrace_nop_replace(rec); | ||
150 | new = ftrace_call_replace(ip, addr); | ||
151 | |||
152 | return ftrace_modify_code(rec->ip, old, new); | ||
153 | } | ||
154 | |||
155 | int ftrace_make_nop(struct module *mod, | ||
156 | struct dyn_ftrace *rec, unsigned long addr) | ||
157 | { | ||
158 | unsigned long ip = rec->ip; | ||
159 | unsigned long old; | ||
160 | unsigned long new; | ||
161 | int ret; | ||
162 | |||
163 | old = ftrace_call_replace(ip, addr); | ||
164 | new = ftrace_nop_replace(rec); | ||
165 | ret = ftrace_modify_code(ip, old, new); | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | int __init ftrace_dyn_arch_init(void *data) | ||
171 | { | ||
172 | *(unsigned long *)data = 0; | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
177 | |||
178 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
179 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | ||
180 | unsigned long frame_pointer) | ||
181 | { | ||
182 | unsigned long return_hooker = (unsigned long) &return_to_handler; | ||
183 | struct ftrace_graph_ent trace; | ||
184 | unsigned long old; | ||
185 | int err; | ||
186 | |||
187 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
188 | return; | ||
189 | |||
190 | old = *parent; | ||
191 | *parent = return_hooker; | ||
192 | |||
193 | err = ftrace_push_return_trace(old, self_addr, &trace.depth, | ||
194 | frame_pointer); | ||
195 | if (err == -EBUSY) { | ||
196 | *parent = old; | ||
197 | return; | ||
198 | } | ||
199 | |||
200 | trace.func = self_addr; | ||
201 | |||
202 | /* Only trace if the calling function expects to */ | ||
203 | if (!ftrace_graph_entry(&trace)) { | ||
204 | current->curr_ret_stack--; | ||
205 | *parent = old; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
210 | extern unsigned long ftrace_graph_call; | ||
211 | |||
212 | static int __ftrace_modify_caller(unsigned long *callsite, | ||
213 | void (*func) (void), bool enable) | ||
214 | { | ||
215 | unsigned long caller_fn = (unsigned long) func; | ||
216 | unsigned long pc = (unsigned long) callsite; | ||
217 | unsigned long branch = ftrace_gen_branch(pc, caller_fn, false); | ||
218 | unsigned long nop = NOP(); | ||
219 | unsigned long old = enable ? nop : branch; | ||
220 | unsigned long new = enable ? branch : nop; | ||
221 | |||
222 | return ftrace_modify_code(pc, old, new); | ||
223 | } | ||
224 | |||
225 | static int ftrace_modify_graph_caller(bool enable) | ||
226 | { | ||
227 | int ret; | ||
228 | |||
229 | ret = __ftrace_modify_caller(&ftrace_graph_call, | ||
230 | ftrace_graph_caller, | ||
231 | enable); | ||
232 | |||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | int ftrace_enable_ftrace_graph_caller(void) | ||
237 | { | ||
238 | return ftrace_modify_graph_caller(true); | ||
239 | } | ||
240 | |||
241 | int ftrace_disable_ftrace_graph_caller(void) | ||
242 | { | ||
243 | return ftrace_modify_graph_caller(false); | ||
244 | } | ||
245 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
246 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
diff --git a/arch/tile/kernel/hardwall.c b/arch/tile/kernel/hardwall.c index 38ac189d9575..df27a1fd94a3 100644 --- a/arch/tile/kernel/hardwall.c +++ b/arch/tile/kernel/hardwall.c | |||
@@ -272,9 +272,9 @@ static void hardwall_setup_func(void *info) | |||
272 | struct hardwall_info *r = info; | 272 | struct hardwall_info *r = info; |
273 | struct hardwall_type *hwt = r->type; | 273 | struct hardwall_type *hwt = r->type; |
274 | 274 | ||
275 | int cpu = smp_processor_id(); | 275 | int cpu = smp_processor_id(); /* on_each_cpu disables preemption */ |
276 | int x = cpu % smp_width; | 276 | int x = cpu_x(cpu); |
277 | int y = cpu / smp_width; | 277 | int y = cpu_y(cpu); |
278 | int bits = 0; | 278 | int bits = 0; |
279 | if (x == r->ulhc_x) | 279 | if (x == r->ulhc_x) |
280 | bits |= W_PROTECT; | 280 | bits |= W_PROTECT; |
@@ -317,6 +317,7 @@ static void hardwall_protect_rectangle(struct hardwall_info *r) | |||
317 | on_each_cpu_mask(&rect_cpus, hardwall_setup_func, r, 1); | 317 | on_each_cpu_mask(&rect_cpus, hardwall_setup_func, r, 1); |
318 | } | 318 | } |
319 | 319 | ||
320 | /* Entered from INT_xDN_FIREWALL interrupt vector with irqs disabled. */ | ||
320 | void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) | 321 | void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) |
321 | { | 322 | { |
322 | struct hardwall_info *rect; | 323 | struct hardwall_info *rect; |
@@ -325,7 +326,6 @@ void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) | |||
325 | struct siginfo info; | 326 | struct siginfo info; |
326 | int cpu = smp_processor_id(); | 327 | int cpu = smp_processor_id(); |
327 | int found_processes; | 328 | int found_processes; |
328 | unsigned long flags; | ||
329 | struct pt_regs *old_regs = set_irq_regs(regs); | 329 | struct pt_regs *old_regs = set_irq_regs(regs); |
330 | 330 | ||
331 | irq_enter(); | 331 | irq_enter(); |
@@ -346,7 +346,7 @@ void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) | |||
346 | BUG_ON(hwt->disabled); | 346 | BUG_ON(hwt->disabled); |
347 | 347 | ||
348 | /* This tile trapped a network access; find the rectangle. */ | 348 | /* This tile trapped a network access; find the rectangle. */ |
349 | spin_lock_irqsave(&hwt->lock, flags); | 349 | spin_lock(&hwt->lock); |
350 | list_for_each_entry(rect, &hwt->list, list) { | 350 | list_for_each_entry(rect, &hwt->list, list) { |
351 | if (cpumask_test_cpu(cpu, &rect->cpumask)) | 351 | if (cpumask_test_cpu(cpu, &rect->cpumask)) |
352 | break; | 352 | break; |
@@ -401,7 +401,7 @@ void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) | |||
401 | pr_notice("hardwall: no associated processes!\n"); | 401 | pr_notice("hardwall: no associated processes!\n"); |
402 | 402 | ||
403 | done: | 403 | done: |
404 | spin_unlock_irqrestore(&hwt->lock, flags); | 404 | spin_unlock(&hwt->lock); |
405 | 405 | ||
406 | /* | 406 | /* |
407 | * We have to disable firewall interrupts now, or else when we | 407 | * We have to disable firewall interrupts now, or else when we |
@@ -540,6 +540,14 @@ static struct hardwall_info *hardwall_create(struct hardwall_type *hwt, | |||
540 | } | 540 | } |
541 | } | 541 | } |
542 | 542 | ||
543 | /* | ||
544 | * Eliminate cpus that are not part of this Linux client. | ||
545 | * Note that this allows for configurations that we might not want to | ||
546 | * support, such as one client on every even cpu, another client on | ||
547 | * every odd cpu. | ||
548 | */ | ||
549 | cpumask_and(&info->cpumask, &info->cpumask, cpu_online_mask); | ||
550 | |||
543 | /* Confirm it doesn't overlap and add it to the list. */ | 551 | /* Confirm it doesn't overlap and add it to the list. */ |
544 | spin_lock_irqsave(&hwt->lock, flags); | 552 | spin_lock_irqsave(&hwt->lock, flags); |
545 | list_for_each_entry(iter, &hwt->list, list) { | 553 | list_for_each_entry(iter, &hwt->list, list) { |
@@ -612,7 +620,7 @@ static int hardwall_activate(struct hardwall_info *info) | |||
612 | 620 | ||
613 | /* | 621 | /* |
614 | * Deactivate a task's hardwall. Must hold lock for hardwall_type. | 622 | * Deactivate a task's hardwall. Must hold lock for hardwall_type. |
615 | * This method may be called from free_task(), so we don't want to | 623 | * This method may be called from exit_thread(), so we don't want to |
616 | * rely on too many fields of struct task_struct still being valid. | 624 | * rely on too many fields of struct task_struct still being valid. |
617 | * We assume the cpus_allowed, pid, and comm fields are still valid. | 625 | * We assume the cpus_allowed, pid, and comm fields are still valid. |
618 | */ | 626 | */ |
@@ -653,7 +661,7 @@ static int hardwall_deactivate(struct hardwall_type *hwt, | |||
653 | return -EINVAL; | 661 | return -EINVAL; |
654 | 662 | ||
655 | printk(KERN_DEBUG "Pid %d (%s) deactivated for %s hardwall: cpu %d\n", | 663 | printk(KERN_DEBUG "Pid %d (%s) deactivated for %s hardwall: cpu %d\n", |
656 | task->pid, task->comm, hwt->name, smp_processor_id()); | 664 | task->pid, task->comm, hwt->name, raw_smp_processor_id()); |
657 | return 0; | 665 | return 0; |
658 | } | 666 | } |
659 | 667 | ||
@@ -795,8 +803,8 @@ static void reset_xdn_network_state(struct hardwall_type *hwt) | |||
795 | /* Reset UDN coordinates to their standard value */ | 803 | /* Reset UDN coordinates to their standard value */ |
796 | { | 804 | { |
797 | unsigned int cpu = smp_processor_id(); | 805 | unsigned int cpu = smp_processor_id(); |
798 | unsigned int x = cpu % smp_width; | 806 | unsigned int x = cpu_x(cpu); |
799 | unsigned int y = cpu / smp_width; | 807 | unsigned int y = cpu_y(cpu); |
800 | __insn_mtspr(SPR_UDN_TILE_COORD, (x << 18) | (y << 7)); | 808 | __insn_mtspr(SPR_UDN_TILE_COORD, (x << 18) | (y << 7)); |
801 | } | 809 | } |
802 | 810 | ||
diff --git a/arch/tile/kernel/head_32.S b/arch/tile/kernel/head_32.S index ac115307e5e4..8d5b40ff2922 100644 --- a/arch/tile/kernel/head_32.S +++ b/arch/tile/kernel/head_32.S | |||
@@ -39,12 +39,12 @@ ENTRY(_start) | |||
39 | } | 39 | } |
40 | { | 40 | { |
41 | moveli r0, _HV_VERSION_OLD_HV_INIT | 41 | moveli r0, _HV_VERSION_OLD_HV_INIT |
42 | jal hv_init | 42 | jal _hv_init |
43 | } | 43 | } |
44 | /* Get a reasonable default ASID in r0 */ | 44 | /* Get a reasonable default ASID in r0 */ |
45 | { | 45 | { |
46 | move r0, zero | 46 | move r0, zero |
47 | jal hv_inquire_asid | 47 | jal _hv_inquire_asid |
48 | } | 48 | } |
49 | /* Install the default page table */ | 49 | /* Install the default page table */ |
50 | { | 50 | { |
@@ -64,7 +64,7 @@ ENTRY(_start) | |||
64 | auli r0, r0, ha16(swapper_pg_dir - PAGE_OFFSET) | 64 | auli r0, r0, ha16(swapper_pg_dir - PAGE_OFFSET) |
65 | } | 65 | } |
66 | { | 66 | { |
67 | inv r6 | 67 | finv r6 |
68 | move r1, zero /* high 32 bits of CPA is zero */ | 68 | move r1, zero /* high 32 bits of CPA is zero */ |
69 | } | 69 | } |
70 | { | 70 | { |
@@ -73,12 +73,12 @@ ENTRY(_start) | |||
73 | } | 73 | } |
74 | { | 74 | { |
75 | auli lr, lr, ha16(1f) | 75 | auli lr, lr, ha16(1f) |
76 | j hv_install_context | 76 | j _hv_install_context |
77 | } | 77 | } |
78 | 1: | 78 | 1: |
79 | 79 | ||
80 | /* Get our processor number and save it away in SAVE_K_0. */ | 80 | /* Get our processor number and save it away in SAVE_K_0. */ |
81 | jal hv_inquire_topology | 81 | jal _hv_inquire_topology |
82 | mulll_uu r4, r1, r2 /* r1 == y, r2 == width */ | 82 | mulll_uu r4, r1, r2 /* r1 == y, r2 == width */ |
83 | add r4, r4, r0 /* r0 == x, so r4 == cpu == y*width + x */ | 83 | add r4, r4, r0 /* r0 == x, so r4 == cpu == y*width + x */ |
84 | 84 | ||
@@ -86,7 +86,7 @@ ENTRY(_start) | |||
86 | /* | 86 | /* |
87 | * Load up our per-cpu offset. When the first (master) tile | 87 | * Load up our per-cpu offset. When the first (master) tile |
88 | * boots, this value is still zero, so we will load boot_pc | 88 | * boots, this value is still zero, so we will load boot_pc |
89 | * with start_kernel, and boot_sp with init_stack + THREAD_SIZE. | 89 | * with start_kernel, and boot_sp at the top of init_stack. |
90 | * The master tile initializes the per-cpu offset array, so that | 90 | * The master tile initializes the per-cpu offset array, so that |
91 | * when subsequent (secondary) tiles boot, they will instead load | 91 | * when subsequent (secondary) tiles boot, they will instead load |
92 | * from their per-cpu versions of boot_sp and boot_pc. | 92 | * from their per-cpu versions of boot_sp and boot_pc. |
@@ -126,7 +126,6 @@ ENTRY(_start) | |||
126 | lw sp, r1 | 126 | lw sp, r1 |
127 | or r4, sp, r4 | 127 | or r4, sp, r4 |
128 | mtspr SPR_SYSTEM_SAVE_K_0, r4 /* save ksp0 + cpu */ | 128 | mtspr SPR_SYSTEM_SAVE_K_0, r4 /* save ksp0 + cpu */ |
129 | addi sp, sp, -STACK_TOP_DELTA | ||
130 | { | 129 | { |
131 | move lr, zero /* stop backtraces in the called function */ | 130 | move lr, zero /* stop backtraces in the called function */ |
132 | jr r0 | 131 | jr r0 |
@@ -163,8 +162,8 @@ ENTRY(swapper_pg_dir) | |||
163 | .set addr, addr + PGDIR_SIZE | 162 | .set addr, addr + PGDIR_SIZE |
164 | .endr | 163 | .endr |
165 | 164 | ||
166 | /* The true text VAs are mapped as VA = PA + MEM_SV_INTRPT */ | 165 | /* The true text VAs are mapped as VA = PA + MEM_SV_START */ |
167 | PTE MEM_SV_INTRPT, 0, (1 << (HV_PTE_INDEX_READABLE - 32)) | \ | 166 | PTE MEM_SV_START, 0, (1 << (HV_PTE_INDEX_READABLE - 32)) | \ |
168 | (1 << (HV_PTE_INDEX_EXECUTABLE - 32)) | 167 | (1 << (HV_PTE_INDEX_EXECUTABLE - 32)) |
169 | .org swapper_pg_dir + PGDIR_SIZE | 168 | .org swapper_pg_dir + PGDIR_SIZE |
170 | END(swapper_pg_dir) | 169 | END(swapper_pg_dir) |
diff --git a/arch/tile/kernel/head_64.S b/arch/tile/kernel/head_64.S index 6093964fa5c7..bd0e12f283f3 100644 --- a/arch/tile/kernel/head_64.S +++ b/arch/tile/kernel/head_64.S | |||
@@ -25,6 +25,15 @@ | |||
25 | #include <arch/chip.h> | 25 | #include <arch/chip.h> |
26 | #include <arch/spr_def.h> | 26 | #include <arch/spr_def.h> |
27 | 27 | ||
28 | /* Extract two 32-bit bit values that were read into one register. */ | ||
29 | #ifdef __BIG_ENDIAN__ | ||
30 | #define GET_FIRST_INT(rd, rs) shrsi rd, rs, 32 | ||
31 | #define GET_SECOND_INT(rd, rs) addxi rd, rs, 0 | ||
32 | #else | ||
33 | #define GET_FIRST_INT(rd, rs) addxi rd, rs, 0 | ||
34 | #define GET_SECOND_INT(rd, rs) shrsi rd, rs, 32 | ||
35 | #endif | ||
36 | |||
28 | /* | 37 | /* |
29 | * This module contains the entry code for kernel images. It performs the | 38 | * This module contains the entry code for kernel images. It performs the |
30 | * minimal setup needed to call the generic C routines. | 39 | * minimal setup needed to call the generic C routines. |
@@ -46,11 +55,11 @@ ENTRY(_start) | |||
46 | movei r2, TILE_CHIP_REV | 55 | movei r2, TILE_CHIP_REV |
47 | movei r3, KERNEL_PL | 56 | movei r3, KERNEL_PL |
48 | } | 57 | } |
49 | jal hv_init | 58 | jal _hv_init |
50 | /* Get a reasonable default ASID in r0 */ | 59 | /* Get a reasonable default ASID in r0 */ |
51 | { | 60 | { |
52 | move r0, zero | 61 | move r0, zero |
53 | jal hv_inquire_asid | 62 | jal _hv_inquire_asid |
54 | } | 63 | } |
55 | 64 | ||
56 | /* | 65 | /* |
@@ -61,7 +70,7 @@ ENTRY(_start) | |||
61 | * other CPUs should see a properly-constructed page table. | 70 | * other CPUs should see a properly-constructed page table. |
62 | */ | 71 | */ |
63 | { | 72 | { |
64 | v4int_l r2, zero, r0 /* ASID for hv_install_context */ | 73 | GET_FIRST_INT(r2, r0) /* ASID for hv_install_context */ |
65 | moveli r4, hw1_last(swapper_pgprot - PAGE_OFFSET) | 74 | moveli r4, hw1_last(swapper_pgprot - PAGE_OFFSET) |
66 | } | 75 | } |
67 | { | 76 | { |
@@ -77,7 +86,7 @@ ENTRY(_start) | |||
77 | { | 86 | { |
78 | /* After initializing swapper_pgprot, HV_PTE_GLOBAL is set. */ | 87 | /* After initializing swapper_pgprot, HV_PTE_GLOBAL is set. */ |
79 | bfextu r7, r1, HV_PTE_INDEX_GLOBAL, HV_PTE_INDEX_GLOBAL | 88 | bfextu r7, r1, HV_PTE_INDEX_GLOBAL, HV_PTE_INDEX_GLOBAL |
80 | inv r4 | 89 | finv r4 |
81 | } | 90 | } |
82 | bnez r7, .Lno_write | 91 | bnez r7, .Lno_write |
83 | { | 92 | { |
@@ -121,29 +130,24 @@ ENTRY(_start) | |||
121 | } | 130 | } |
122 | { | 131 | { |
123 | moveli r3, CTX_PAGE_FLAG | 132 | moveli r3, CTX_PAGE_FLAG |
124 | j hv_install_context | 133 | j _hv_install_context |
125 | } | 134 | } |
126 | 1: | 135 | 1: |
127 | 136 | ||
128 | /* Install the interrupt base. */ | 137 | /* Install the interrupt base. */ |
129 | moveli r0, hw2_last(MEM_SV_START) | 138 | moveli r0, hw2_last(intrpt_start) |
130 | shl16insli r0, r0, hw1(MEM_SV_START) | 139 | shl16insli r0, r0, hw1(intrpt_start) |
131 | shl16insli r0, r0, hw0(MEM_SV_START) | 140 | shl16insli r0, r0, hw0(intrpt_start) |
132 | mtspr SPR_INTERRUPT_VECTOR_BASE_K, r0 | 141 | mtspr SPR_INTERRUPT_VECTOR_BASE_K, r0 |
133 | 142 | ||
134 | /* | 143 | /* Get our processor number and save it away in SAVE_K_0. */ |
135 | * Get our processor number and save it away in SAVE_K_0. | 144 | jal _hv_inquire_topology |
136 | * Extract stuff from the topology structure: r4 = y, r6 = x, | ||
137 | * r5 = width. FIXME: consider whether we want to just make these | ||
138 | * 64-bit values (and if so fix smp_topology write below, too). | ||
139 | */ | ||
140 | jal hv_inquire_topology | ||
141 | { | 145 | { |
142 | v4int_l r5, zero, r1 /* r5 = width */ | 146 | GET_FIRST_INT(r5, r1) /* r5 = width */ |
143 | shrui r4, r0, 32 /* r4 = y */ | 147 | GET_SECOND_INT(r4, r0) /* r4 = y */ |
144 | } | 148 | } |
145 | { | 149 | { |
146 | v4int_l r6, zero, r0 /* r6 = x */ | 150 | GET_FIRST_INT(r6, r0) /* r6 = x */ |
147 | mul_lu_lu r4, r4, r5 | 151 | mul_lu_lu r4, r4, r5 |
148 | } | 152 | } |
149 | { | 153 | { |
@@ -154,7 +158,7 @@ ENTRY(_start) | |||
154 | /* | 158 | /* |
155 | * Load up our per-cpu offset. When the first (master) tile | 159 | * Load up our per-cpu offset. When the first (master) tile |
156 | * boots, this value is still zero, so we will load boot_pc | 160 | * boots, this value is still zero, so we will load boot_pc |
157 | * with start_kernel, and boot_sp with init_stack + THREAD_SIZE. | 161 | * with start_kernel, and boot_sp with at the top of init_stack. |
158 | * The master tile initializes the per-cpu offset array, so that | 162 | * The master tile initializes the per-cpu offset array, so that |
159 | * when subsequent (secondary) tiles boot, they will instead load | 163 | * when subsequent (secondary) tiles boot, they will instead load |
160 | * from their per-cpu versions of boot_sp and boot_pc. | 164 | * from their per-cpu versions of boot_sp and boot_pc. |
@@ -198,9 +202,9 @@ ENTRY(_start) | |||
198 | } | 202 | } |
199 | ld r0, r0 | 203 | ld r0, r0 |
200 | ld sp, r1 | 204 | ld sp, r1 |
201 | or r4, sp, r4 | 205 | shli r4, r4, CPU_SHIFT |
206 | bfins r4, sp, 0, CPU_SHIFT-1 | ||
202 | mtspr SPR_SYSTEM_SAVE_K_0, r4 /* save ksp0 + cpu */ | 207 | mtspr SPR_SYSTEM_SAVE_K_0, r4 /* save ksp0 + cpu */ |
203 | addi sp, sp, -STACK_TOP_DELTA | ||
204 | { | 208 | { |
205 | move lr, zero /* stop backtraces in the called function */ | 209 | move lr, zero /* stop backtraces in the called function */ |
206 | jr r0 | 210 | jr r0 |
diff --git a/arch/tile/kernel/hvglue.S b/arch/tile/kernel/hvglue.S new file mode 100644 index 000000000000..2ab456622391 --- /dev/null +++ b/arch/tile/kernel/hvglue.S | |||
@@ -0,0 +1,74 @@ | |||
1 | /* Hypervisor call vector addresses; see <hv/hypervisor.h> */ | ||
2 | .macro gensym sym, val, size | ||
3 | .org \val | ||
4 | .global _\sym | ||
5 | .type _\sym,function | ||
6 | _\sym: | ||
7 | .size _\sym,\size | ||
8 | #ifndef CONFIG_TILE_HVGLUE_TRACE | ||
9 | .globl \sym | ||
10 | .set \sym,_\sym | ||
11 | #endif | ||
12 | .endm | ||
13 | |||
14 | .section .hvglue,"x",@nobits | ||
15 | .align 8 | ||
16 | gensym hv_init, 0x20, 32 | ||
17 | gensym hv_install_context, 0x40, 32 | ||
18 | gensym hv_sysconf, 0x60, 32 | ||
19 | gensym hv_get_rtc, 0x80, 32 | ||
20 | gensym hv_set_rtc, 0xa0, 32 | ||
21 | gensym hv_flush_asid, 0xc0, 32 | ||
22 | gensym hv_flush_page, 0xe0, 32 | ||
23 | gensym hv_flush_pages, 0x100, 32 | ||
24 | gensym hv_restart, 0x120, 32 | ||
25 | gensym hv_halt, 0x140, 32 | ||
26 | gensym hv_power_off, 0x160, 32 | ||
27 | gensym hv_inquire_physical, 0x180, 32 | ||
28 | gensym hv_inquire_memory_controller, 0x1a0, 32 | ||
29 | gensym hv_inquire_virtual, 0x1c0, 32 | ||
30 | gensym hv_inquire_asid, 0x1e0, 32 | ||
31 | gensym hv_nanosleep, 0x200, 32 | ||
32 | gensym hv_console_read_if_ready, 0x220, 32 | ||
33 | gensym hv_console_write, 0x240, 32 | ||
34 | gensym hv_downcall_dispatch, 0x260, 32 | ||
35 | gensym hv_inquire_topology, 0x280, 32 | ||
36 | gensym hv_fs_findfile, 0x2a0, 32 | ||
37 | gensym hv_fs_fstat, 0x2c0, 32 | ||
38 | gensym hv_fs_pread, 0x2e0, 32 | ||
39 | gensym hv_physaddr_read64, 0x300, 32 | ||
40 | gensym hv_physaddr_write64, 0x320, 32 | ||
41 | gensym hv_get_command_line, 0x340, 32 | ||
42 | gensym hv_set_caching, 0x360, 32 | ||
43 | gensym hv_bzero_page, 0x380, 32 | ||
44 | gensym hv_register_message_state, 0x3a0, 32 | ||
45 | gensym hv_send_message, 0x3c0, 32 | ||
46 | gensym hv_receive_message, 0x3e0, 32 | ||
47 | gensym hv_inquire_context, 0x400, 32 | ||
48 | gensym hv_start_all_tiles, 0x420, 32 | ||
49 | gensym hv_dev_open, 0x440, 32 | ||
50 | gensym hv_dev_close, 0x460, 32 | ||
51 | gensym hv_dev_pread, 0x480, 32 | ||
52 | gensym hv_dev_pwrite, 0x4a0, 32 | ||
53 | gensym hv_dev_poll, 0x4c0, 32 | ||
54 | gensym hv_dev_poll_cancel, 0x4e0, 32 | ||
55 | gensym hv_dev_preada, 0x500, 32 | ||
56 | gensym hv_dev_pwritea, 0x520, 32 | ||
57 | gensym hv_flush_remote, 0x540, 32 | ||
58 | gensym hv_console_putc, 0x560, 32 | ||
59 | gensym hv_inquire_tiles, 0x580, 32 | ||
60 | gensym hv_confstr, 0x5a0, 32 | ||
61 | gensym hv_reexec, 0x5c0, 32 | ||
62 | gensym hv_set_command_line, 0x5e0, 32 | ||
63 | gensym hv_clear_intr, 0x600, 32 | ||
64 | gensym hv_enable_intr, 0x620, 32 | ||
65 | gensym hv_disable_intr, 0x640, 32 | ||
66 | gensym hv_raise_intr, 0x660, 32 | ||
67 | gensym hv_trigger_ipi, 0x680, 32 | ||
68 | gensym hv_store_mapping, 0x6a0, 32 | ||
69 | gensym hv_inquire_realpa, 0x6c0, 32 | ||
70 | gensym hv_flush_all, 0x6e0, 32 | ||
71 | gensym hv_get_ipi_pte, 0x700, 32 | ||
72 | gensym hv_set_pte_super_shift, 0x720, 32 | ||
73 | gensym hv_console_set_ipi, 0x7e0, 32 | ||
74 | gensym hv_glue_internals, 0x800, 30720 | ||
diff --git a/arch/tile/kernel/hvglue.lds b/arch/tile/kernel/hvglue.lds deleted file mode 100644 index d44c5a67a1ed..000000000000 --- a/arch/tile/kernel/hvglue.lds +++ /dev/null | |||
@@ -1,59 +0,0 @@ | |||
1 | /* Hypervisor call vector addresses; see <hv/hypervisor.h> */ | ||
2 | hv_init = TEXT_OFFSET + 0x10020; | ||
3 | hv_install_context = TEXT_OFFSET + 0x10040; | ||
4 | hv_sysconf = TEXT_OFFSET + 0x10060; | ||
5 | hv_get_rtc = TEXT_OFFSET + 0x10080; | ||
6 | hv_set_rtc = TEXT_OFFSET + 0x100a0; | ||
7 | hv_flush_asid = TEXT_OFFSET + 0x100c0; | ||
8 | hv_flush_page = TEXT_OFFSET + 0x100e0; | ||
9 | hv_flush_pages = TEXT_OFFSET + 0x10100; | ||
10 | hv_restart = TEXT_OFFSET + 0x10120; | ||
11 | hv_halt = TEXT_OFFSET + 0x10140; | ||
12 | hv_power_off = TEXT_OFFSET + 0x10160; | ||
13 | hv_inquire_physical = TEXT_OFFSET + 0x10180; | ||
14 | hv_inquire_memory_controller = TEXT_OFFSET + 0x101a0; | ||
15 | hv_inquire_virtual = TEXT_OFFSET + 0x101c0; | ||
16 | hv_inquire_asid = TEXT_OFFSET + 0x101e0; | ||
17 | hv_nanosleep = TEXT_OFFSET + 0x10200; | ||
18 | hv_console_read_if_ready = TEXT_OFFSET + 0x10220; | ||
19 | hv_console_write = TEXT_OFFSET + 0x10240; | ||
20 | hv_downcall_dispatch = TEXT_OFFSET + 0x10260; | ||
21 | hv_inquire_topology = TEXT_OFFSET + 0x10280; | ||
22 | hv_fs_findfile = TEXT_OFFSET + 0x102a0; | ||
23 | hv_fs_fstat = TEXT_OFFSET + 0x102c0; | ||
24 | hv_fs_pread = TEXT_OFFSET + 0x102e0; | ||
25 | hv_physaddr_read64 = TEXT_OFFSET + 0x10300; | ||
26 | hv_physaddr_write64 = TEXT_OFFSET + 0x10320; | ||
27 | hv_get_command_line = TEXT_OFFSET + 0x10340; | ||
28 | hv_set_caching = TEXT_OFFSET + 0x10360; | ||
29 | hv_bzero_page = TEXT_OFFSET + 0x10380; | ||
30 | hv_register_message_state = TEXT_OFFSET + 0x103a0; | ||
31 | hv_send_message = TEXT_OFFSET + 0x103c0; | ||
32 | hv_receive_message = TEXT_OFFSET + 0x103e0; | ||
33 | hv_inquire_context = TEXT_OFFSET + 0x10400; | ||
34 | hv_start_all_tiles = TEXT_OFFSET + 0x10420; | ||
35 | hv_dev_open = TEXT_OFFSET + 0x10440; | ||
36 | hv_dev_close = TEXT_OFFSET + 0x10460; | ||
37 | hv_dev_pread = TEXT_OFFSET + 0x10480; | ||
38 | hv_dev_pwrite = TEXT_OFFSET + 0x104a0; | ||
39 | hv_dev_poll = TEXT_OFFSET + 0x104c0; | ||
40 | hv_dev_poll_cancel = TEXT_OFFSET + 0x104e0; | ||
41 | hv_dev_preada = TEXT_OFFSET + 0x10500; | ||
42 | hv_dev_pwritea = TEXT_OFFSET + 0x10520; | ||
43 | hv_flush_remote = TEXT_OFFSET + 0x10540; | ||
44 | hv_console_putc = TEXT_OFFSET + 0x10560; | ||
45 | hv_inquire_tiles = TEXT_OFFSET + 0x10580; | ||
46 | hv_confstr = TEXT_OFFSET + 0x105a0; | ||
47 | hv_reexec = TEXT_OFFSET + 0x105c0; | ||
48 | hv_set_command_line = TEXT_OFFSET + 0x105e0; | ||
49 | hv_clear_intr = TEXT_OFFSET + 0x10600; | ||
50 | hv_enable_intr = TEXT_OFFSET + 0x10620; | ||
51 | hv_disable_intr = TEXT_OFFSET + 0x10640; | ||
52 | hv_raise_intr = TEXT_OFFSET + 0x10660; | ||
53 | hv_trigger_ipi = TEXT_OFFSET + 0x10680; | ||
54 | hv_store_mapping = TEXT_OFFSET + 0x106a0; | ||
55 | hv_inquire_realpa = TEXT_OFFSET + 0x106c0; | ||
56 | hv_flush_all = TEXT_OFFSET + 0x106e0; | ||
57 | hv_get_ipi_pte = TEXT_OFFSET + 0x10700; | ||
58 | hv_set_pte_super_shift = TEXT_OFFSET + 0x10720; | ||
59 | hv_glue_internals = TEXT_OFFSET + 0x10740; | ||
diff --git a/arch/tile/kernel/hvglue_trace.c b/arch/tile/kernel/hvglue_trace.c new file mode 100644 index 000000000000..85c74ad29312 --- /dev/null +++ b/arch/tile/kernel/hvglue_trace.c | |||
@@ -0,0 +1,266 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | /* | ||
16 | * Pull in the hypervisor header so we declare all the ABI functions | ||
17 | * with the underscore versions, then undef the names so that we can | ||
18 | * provide our own wrapper versions. | ||
19 | */ | ||
20 | #define hv_init _hv_init | ||
21 | #define hv_install_context _hv_install_context | ||
22 | #define hv_sysconf _hv_sysconf | ||
23 | #define hv_get_rtc _hv_get_rtc | ||
24 | #define hv_set_rtc _hv_set_rtc | ||
25 | #define hv_flush_asid _hv_flush_asid | ||
26 | #define hv_flush_page _hv_flush_page | ||
27 | #define hv_flush_pages _hv_flush_pages | ||
28 | #define hv_restart _hv_restart | ||
29 | #define hv_halt _hv_halt | ||
30 | #define hv_power_off _hv_power_off | ||
31 | #define hv_inquire_physical _hv_inquire_physical | ||
32 | #define hv_inquire_memory_controller _hv_inquire_memory_controller | ||
33 | #define hv_inquire_virtual _hv_inquire_virtual | ||
34 | #define hv_inquire_asid _hv_inquire_asid | ||
35 | #define hv_nanosleep _hv_nanosleep | ||
36 | #define hv_console_read_if_ready _hv_console_read_if_ready | ||
37 | #define hv_console_write _hv_console_write | ||
38 | #define hv_downcall_dispatch _hv_downcall_dispatch | ||
39 | #define hv_inquire_topology _hv_inquire_topology | ||
40 | #define hv_fs_findfile _hv_fs_findfile | ||
41 | #define hv_fs_fstat _hv_fs_fstat | ||
42 | #define hv_fs_pread _hv_fs_pread | ||
43 | #define hv_physaddr_read64 _hv_physaddr_read64 | ||
44 | #define hv_physaddr_write64 _hv_physaddr_write64 | ||
45 | #define hv_get_command_line _hv_get_command_line | ||
46 | #define hv_set_caching _hv_set_caching | ||
47 | #define hv_bzero_page _hv_bzero_page | ||
48 | #define hv_register_message_state _hv_register_message_state | ||
49 | #define hv_send_message _hv_send_message | ||
50 | #define hv_receive_message _hv_receive_message | ||
51 | #define hv_inquire_context _hv_inquire_context | ||
52 | #define hv_start_all_tiles _hv_start_all_tiles | ||
53 | #define hv_dev_open _hv_dev_open | ||
54 | #define hv_dev_close _hv_dev_close | ||
55 | #define hv_dev_pread _hv_dev_pread | ||
56 | #define hv_dev_pwrite _hv_dev_pwrite | ||
57 | #define hv_dev_poll _hv_dev_poll | ||
58 | #define hv_dev_poll_cancel _hv_dev_poll_cancel | ||
59 | #define hv_dev_preada _hv_dev_preada | ||
60 | #define hv_dev_pwritea _hv_dev_pwritea | ||
61 | #define hv_flush_remote _hv_flush_remote | ||
62 | #define hv_console_putc _hv_console_putc | ||
63 | #define hv_inquire_tiles _hv_inquire_tiles | ||
64 | #define hv_confstr _hv_confstr | ||
65 | #define hv_reexec _hv_reexec | ||
66 | #define hv_set_command_line _hv_set_command_line | ||
67 | #define hv_clear_intr _hv_clear_intr | ||
68 | #define hv_enable_intr _hv_enable_intr | ||
69 | #define hv_disable_intr _hv_disable_intr | ||
70 | #define hv_raise_intr _hv_raise_intr | ||
71 | #define hv_trigger_ipi _hv_trigger_ipi | ||
72 | #define hv_store_mapping _hv_store_mapping | ||
73 | #define hv_inquire_realpa _hv_inquire_realpa | ||
74 | #define hv_flush_all _hv_flush_all | ||
75 | #define hv_get_ipi_pte _hv_get_ipi_pte | ||
76 | #define hv_set_pte_super_shift _hv_set_pte_super_shift | ||
77 | #define hv_console_set_ipi _hv_console_set_ipi | ||
78 | #include <hv/hypervisor.h> | ||
79 | #undef hv_init | ||
80 | #undef hv_install_context | ||
81 | #undef hv_sysconf | ||
82 | #undef hv_get_rtc | ||
83 | #undef hv_set_rtc | ||
84 | #undef hv_flush_asid | ||
85 | #undef hv_flush_page | ||
86 | #undef hv_flush_pages | ||
87 | #undef hv_restart | ||
88 | #undef hv_halt | ||
89 | #undef hv_power_off | ||
90 | #undef hv_inquire_physical | ||
91 | #undef hv_inquire_memory_controller | ||
92 | #undef hv_inquire_virtual | ||
93 | #undef hv_inquire_asid | ||
94 | #undef hv_nanosleep | ||
95 | #undef hv_console_read_if_ready | ||
96 | #undef hv_console_write | ||
97 | #undef hv_downcall_dispatch | ||
98 | #undef hv_inquire_topology | ||
99 | #undef hv_fs_findfile | ||
100 | #undef hv_fs_fstat | ||
101 | #undef hv_fs_pread | ||
102 | #undef hv_physaddr_read64 | ||
103 | #undef hv_physaddr_write64 | ||
104 | #undef hv_get_command_line | ||
105 | #undef hv_set_caching | ||
106 | #undef hv_bzero_page | ||
107 | #undef hv_register_message_state | ||
108 | #undef hv_send_message | ||
109 | #undef hv_receive_message | ||
110 | #undef hv_inquire_context | ||
111 | #undef hv_start_all_tiles | ||
112 | #undef hv_dev_open | ||
113 | #undef hv_dev_close | ||
114 | #undef hv_dev_pread | ||
115 | #undef hv_dev_pwrite | ||
116 | #undef hv_dev_poll | ||
117 | #undef hv_dev_poll_cancel | ||
118 | #undef hv_dev_preada | ||
119 | #undef hv_dev_pwritea | ||
120 | #undef hv_flush_remote | ||
121 | #undef hv_console_putc | ||
122 | #undef hv_inquire_tiles | ||
123 | #undef hv_confstr | ||
124 | #undef hv_reexec | ||
125 | #undef hv_set_command_line | ||
126 | #undef hv_clear_intr | ||
127 | #undef hv_enable_intr | ||
128 | #undef hv_disable_intr | ||
129 | #undef hv_raise_intr | ||
130 | #undef hv_trigger_ipi | ||
131 | #undef hv_store_mapping | ||
132 | #undef hv_inquire_realpa | ||
133 | #undef hv_flush_all | ||
134 | #undef hv_get_ipi_pte | ||
135 | #undef hv_set_pte_super_shift | ||
136 | #undef hv_console_set_ipi | ||
137 | |||
138 | /* | ||
139 | * Provide macros based on <linux/syscalls.h> to provide a wrapper | ||
140 | * function that invokes the same function with an underscore prefix. | ||
141 | * We can't use the existing __SC_xxx macros because we need to | ||
142 | * support up to nine arguments rather than up to six, and also this | ||
143 | * way the file stands alone from possible changes in the | ||
144 | * implementation of <linux/syscalls.h>. | ||
145 | */ | ||
146 | #define HV_WRAP0(type, name) \ | ||
147 | type name(void); \ | ||
148 | type name(void) \ | ||
149 | { \ | ||
150 | return _##name(); \ | ||
151 | } | ||
152 | #define __HV_DECL1(t1, a1) t1 a1 | ||
153 | #define __HV_DECL2(t2, a2, ...) t2 a2, __HV_DECL1(__VA_ARGS__) | ||
154 | #define __HV_DECL3(t3, a3, ...) t3 a3, __HV_DECL2(__VA_ARGS__) | ||
155 | #define __HV_DECL4(t4, a4, ...) t4 a4, __HV_DECL3(__VA_ARGS__) | ||
156 | #define __HV_DECL5(t5, a5, ...) t5 a5, __HV_DECL4(__VA_ARGS__) | ||
157 | #define __HV_DECL6(t6, a6, ...) t6 a6, __HV_DECL5(__VA_ARGS__) | ||
158 | #define __HV_DECL7(t7, a7, ...) t7 a7, __HV_DECL6(__VA_ARGS__) | ||
159 | #define __HV_DECL8(t8, a8, ...) t8 a8, __HV_DECL7(__VA_ARGS__) | ||
160 | #define __HV_DECL9(t9, a9, ...) t9 a9, __HV_DECL8(__VA_ARGS__) | ||
161 | #define __HV_PASS1(t1, a1) a1 | ||
162 | #define __HV_PASS2(t2, a2, ...) a2, __HV_PASS1(__VA_ARGS__) | ||
163 | #define __HV_PASS3(t3, a3, ...) a3, __HV_PASS2(__VA_ARGS__) | ||
164 | #define __HV_PASS4(t4, a4, ...) a4, __HV_PASS3(__VA_ARGS__) | ||
165 | #define __HV_PASS5(t5, a5, ...) a5, __HV_PASS4(__VA_ARGS__) | ||
166 | #define __HV_PASS6(t6, a6, ...) a6, __HV_PASS5(__VA_ARGS__) | ||
167 | #define __HV_PASS7(t7, a7, ...) a7, __HV_PASS6(__VA_ARGS__) | ||
168 | #define __HV_PASS8(t8, a8, ...) a8, __HV_PASS7(__VA_ARGS__) | ||
169 | #define __HV_PASS9(t9, a9, ...) a9, __HV_PASS8(__VA_ARGS__) | ||
170 | #define HV_WRAPx(x, type, name, ...) \ | ||
171 | type name(__HV_DECL##x(__VA_ARGS__)); \ | ||
172 | type name(__HV_DECL##x(__VA_ARGS__)) \ | ||
173 | { \ | ||
174 | return _##name(__HV_PASS##x(__VA_ARGS__)); \ | ||
175 | } | ||
176 | #define HV_WRAP1(type, name, ...) HV_WRAPx(1, type, name, __VA_ARGS__) | ||
177 | #define HV_WRAP2(type, name, ...) HV_WRAPx(2, type, name, __VA_ARGS__) | ||
178 | #define HV_WRAP3(type, name, ...) HV_WRAPx(3, type, name, __VA_ARGS__) | ||
179 | #define HV_WRAP4(type, name, ...) HV_WRAPx(4, type, name, __VA_ARGS__) | ||
180 | #define HV_WRAP5(type, name, ...) HV_WRAPx(5, type, name, __VA_ARGS__) | ||
181 | #define HV_WRAP6(type, name, ...) HV_WRAPx(6, type, name, __VA_ARGS__) | ||
182 | #define HV_WRAP7(type, name, ...) HV_WRAPx(7, type, name, __VA_ARGS__) | ||
183 | #define HV_WRAP8(type, name, ...) HV_WRAPx(8, type, name, __VA_ARGS__) | ||
184 | #define HV_WRAP9(type, name, ...) HV_WRAPx(9, type, name, __VA_ARGS__) | ||
185 | |||
186 | /* List all the hypervisor API functions. */ | ||
187 | HV_WRAP4(void, hv_init, HV_VersionNumber, interface_version_number, | ||
188 | int, chip_num, int, chip_rev_num, int, client_pl) | ||
189 | HV_WRAP1(long, hv_sysconf, HV_SysconfQuery, query) | ||
190 | HV_WRAP3(int, hv_confstr, HV_ConfstrQuery, query, HV_VirtAddr, buf, int, len) | ||
191 | #if CHIP_HAS_IPI() | ||
192 | HV_WRAP3(int, hv_get_ipi_pte, HV_Coord, tile, int, pl, HV_PTE*, pte) | ||
193 | HV_WRAP3(int, hv_console_set_ipi, int, ipi, int, event, HV_Coord, coord); | ||
194 | #else | ||
195 | HV_WRAP1(void, hv_enable_intr, HV_IntrMask, enab_mask) | ||
196 | HV_WRAP1(void, hv_disable_intr, HV_IntrMask, disab_mask) | ||
197 | HV_WRAP1(void, hv_clear_intr, HV_IntrMask, clear_mask) | ||
198 | HV_WRAP1(void, hv_raise_intr, HV_IntrMask, raise_mask) | ||
199 | HV_WRAP2(HV_Errno, hv_trigger_ipi, HV_Coord, tile, int, interrupt) | ||
200 | #endif /* !CHIP_HAS_IPI() */ | ||
201 | HV_WRAP3(int, hv_store_mapping, HV_VirtAddr, va, unsigned int, len, | ||
202 | HV_PhysAddr, pa) | ||
203 | HV_WRAP2(HV_PhysAddr, hv_inquire_realpa, HV_PhysAddr, cpa, unsigned int, len) | ||
204 | HV_WRAP0(HV_RTCTime, hv_get_rtc) | ||
205 | HV_WRAP1(void, hv_set_rtc, HV_RTCTime, time) | ||
206 | HV_WRAP4(int, hv_install_context, HV_PhysAddr, page_table, HV_PTE, access, | ||
207 | HV_ASID, asid, __hv32, flags) | ||
208 | HV_WRAP2(int, hv_set_pte_super_shift, int, level, int, log2_count) | ||
209 | HV_WRAP0(HV_Context, hv_inquire_context) | ||
210 | HV_WRAP1(int, hv_flush_asid, HV_ASID, asid) | ||
211 | HV_WRAP2(int, hv_flush_page, HV_VirtAddr, address, HV_PageSize, page_size) | ||
212 | HV_WRAP3(int, hv_flush_pages, HV_VirtAddr, start, HV_PageSize, page_size, | ||
213 | unsigned long, size) | ||
214 | HV_WRAP1(int, hv_flush_all, int, preserve_global) | ||
215 | HV_WRAP2(void, hv_restart, HV_VirtAddr, cmd, HV_VirtAddr, args) | ||
216 | HV_WRAP0(void, hv_halt) | ||
217 | HV_WRAP0(void, hv_power_off) | ||
218 | HV_WRAP1(int, hv_reexec, HV_PhysAddr, entry) | ||
219 | HV_WRAP0(HV_Topology, hv_inquire_topology) | ||
220 | HV_WRAP3(HV_Errno, hv_inquire_tiles, HV_InqTileSet, set, HV_VirtAddr, cpumask, | ||
221 | int, length) | ||
222 | HV_WRAP1(HV_PhysAddrRange, hv_inquire_physical, int, idx) | ||
223 | HV_WRAP2(HV_MemoryControllerInfo, hv_inquire_memory_controller, HV_Coord, coord, | ||
224 | int, controller) | ||
225 | HV_WRAP1(HV_VirtAddrRange, hv_inquire_virtual, int, idx) | ||
226 | HV_WRAP1(HV_ASIDRange, hv_inquire_asid, int, idx) | ||
227 | HV_WRAP1(void, hv_nanosleep, int, nanosecs) | ||
228 | HV_WRAP0(int, hv_console_read_if_ready) | ||
229 | HV_WRAP1(void, hv_console_putc, int, byte) | ||
230 | HV_WRAP2(int, hv_console_write, HV_VirtAddr, bytes, int, len) | ||
231 | HV_WRAP0(void, hv_downcall_dispatch) | ||
232 | HV_WRAP1(int, hv_fs_findfile, HV_VirtAddr, filename) | ||
233 | HV_WRAP1(HV_FS_StatInfo, hv_fs_fstat, int, inode) | ||
234 | HV_WRAP4(int, hv_fs_pread, int, inode, HV_VirtAddr, buf, | ||
235 | int, length, int, offset) | ||
236 | HV_WRAP2(unsigned long long, hv_physaddr_read64, HV_PhysAddr, addr, | ||
237 | HV_PTE, access) | ||
238 | HV_WRAP3(void, hv_physaddr_write64, HV_PhysAddr, addr, HV_PTE, access, | ||
239 | unsigned long long, val) | ||
240 | HV_WRAP2(int, hv_get_command_line, HV_VirtAddr, buf, int, length) | ||
241 | HV_WRAP2(HV_Errno, hv_set_command_line, HV_VirtAddr, buf, int, length) | ||
242 | HV_WRAP1(void, hv_set_caching, unsigned long, bitmask) | ||
243 | HV_WRAP2(void, hv_bzero_page, HV_VirtAddr, va, unsigned int, size) | ||
244 | HV_WRAP1(HV_Errno, hv_register_message_state, HV_MsgState*, msgstate) | ||
245 | HV_WRAP4(int, hv_send_message, HV_Recipient *, recips, int, nrecip, | ||
246 | HV_VirtAddr, buf, int, buflen) | ||
247 | HV_WRAP3(HV_RcvMsgInfo, hv_receive_message, HV_MsgState, msgstate, | ||
248 | HV_VirtAddr, buf, int, buflen) | ||
249 | HV_WRAP0(void, hv_start_all_tiles) | ||
250 | HV_WRAP2(int, hv_dev_open, HV_VirtAddr, name, __hv32, flags) | ||
251 | HV_WRAP1(int, hv_dev_close, int, devhdl) | ||
252 | HV_WRAP5(int, hv_dev_pread, int, devhdl, __hv32, flags, HV_VirtAddr, va, | ||
253 | __hv32, len, __hv64, offset) | ||
254 | HV_WRAP5(int, hv_dev_pwrite, int, devhdl, __hv32, flags, HV_VirtAddr, va, | ||
255 | __hv32, len, __hv64, offset) | ||
256 | HV_WRAP3(int, hv_dev_poll, int, devhdl, __hv32, events, HV_IntArg, intarg) | ||
257 | HV_WRAP1(int, hv_dev_poll_cancel, int, devhdl) | ||
258 | HV_WRAP6(int, hv_dev_preada, int, devhdl, __hv32, flags, __hv32, sgl_len, | ||
259 | HV_SGL *, sglp, __hv64, offset, HV_IntArg, intarg) | ||
260 | HV_WRAP6(int, hv_dev_pwritea, int, devhdl, __hv32, flags, __hv32, sgl_len, | ||
261 | HV_SGL *, sglp, __hv64, offset, HV_IntArg, intarg) | ||
262 | HV_WRAP9(int, hv_flush_remote, HV_PhysAddr, cache_pa, | ||
263 | unsigned long, cache_control, unsigned long*, cache_cpumask, | ||
264 | HV_VirtAddr, tlb_va, unsigned long, tlb_length, | ||
265 | unsigned long, tlb_pgsize, unsigned long*, tlb_cpumask, | ||
266 | HV_Remote_ASID*, asids, int, asidcount) | ||
diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S index cb52d66343ed..088d5c141e68 100644 --- a/arch/tile/kernel/intvec_32.S +++ b/arch/tile/kernel/intvec_32.S | |||
@@ -28,20 +28,10 @@ | |||
28 | #include <arch/interrupts.h> | 28 | #include <arch/interrupts.h> |
29 | #include <arch/spr_def.h> | 29 | #include <arch/spr_def.h> |
30 | 30 | ||
31 | #ifdef CONFIG_PREEMPT | ||
32 | # error "No support for kernel preemption currently" | ||
33 | #endif | ||
34 | |||
35 | #define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg) | 31 | #define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg) |
36 | 32 | ||
37 | #define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR) | 33 | #define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR) |
38 | 34 | ||
39 | #if !CHIP_HAS_WH64() | ||
40 | /* By making this an empty macro, we can use wh64 in the code. */ | ||
41 | .macro wh64 reg | ||
42 | .endm | ||
43 | #endif | ||
44 | |||
45 | .macro push_reg reg, ptr=sp, delta=-4 | 35 | .macro push_reg reg, ptr=sp, delta=-4 |
46 | { | 36 | { |
47 | sw \ptr, \reg | 37 | sw \ptr, \reg |
@@ -189,7 +179,7 @@ intvec_\vecname: | |||
189 | * point sp at the top aligned address on the actual stack page. | 179 | * point sp at the top aligned address on the actual stack page. |
190 | */ | 180 | */ |
191 | mfspr r0, SPR_SYSTEM_SAVE_K_0 | 181 | mfspr r0, SPR_SYSTEM_SAVE_K_0 |
192 | mm r0, r0, zero, LOG2_THREAD_SIZE, 31 | 182 | mm r0, r0, zero, LOG2_NR_CPU_IDS, 31 |
193 | 183 | ||
194 | 0: | 184 | 0: |
195 | /* | 185 | /* |
@@ -207,6 +197,9 @@ intvec_\vecname: | |||
207 | * cache line 1: r14...r29 | 197 | * cache line 1: r14...r29 |
208 | * cache line 0: 2 x frame, r0..r13 | 198 | * cache line 0: 2 x frame, r0..r13 |
209 | */ | 199 | */ |
200 | #if STACK_TOP_DELTA != 64 | ||
201 | #error STACK_TOP_DELTA must be 64 for assumptions here and in task_pt_regs() | ||
202 | #endif | ||
210 | andi r0, r0, -64 | 203 | andi r0, r0, -64 |
211 | 204 | ||
212 | /* | 205 | /* |
@@ -326,18 +319,14 @@ intvec_\vecname: | |||
326 | movei r3, -1 /* not used, but set for consistency */ | 319 | movei r3, -1 /* not used, but set for consistency */ |
327 | } | 320 | } |
328 | .else | 321 | .else |
329 | #if CHIP_HAS_AUX_PERF_COUNTERS() | ||
330 | .ifc \c_routine, op_handle_aux_perf_interrupt | 322 | .ifc \c_routine, op_handle_aux_perf_interrupt |
331 | { | 323 | { |
332 | mfspr r2, AUX_PERF_COUNT_STS | 324 | mfspr r2, AUX_PERF_COUNT_STS |
333 | movei r3, -1 /* not used, but set for consistency */ | 325 | movei r3, -1 /* not used, but set for consistency */ |
334 | } | 326 | } |
335 | .else | 327 | .else |
336 | #endif | ||
337 | movei r3, 0 | 328 | movei r3, 0 |
338 | #if CHIP_HAS_AUX_PERF_COUNTERS() | ||
339 | .endif | 329 | .endif |
340 | #endif | ||
341 | .endif | 330 | .endif |
342 | .endif | 331 | .endif |
343 | .endif | 332 | .endif |
@@ -354,7 +343,7 @@ intvec_\vecname: | |||
354 | #ifdef __COLLECT_LINKER_FEEDBACK__ | 343 | #ifdef __COLLECT_LINKER_FEEDBACK__ |
355 | .pushsection .text.intvec_feedback,"ax" | 344 | .pushsection .text.intvec_feedback,"ax" |
356 | .org (\vecnum << 5) | 345 | .org (\vecnum << 5) |
357 | FEEDBACK_ENTER_EXPLICIT(intvec_\vecname, .intrpt1, 1 << 8) | 346 | FEEDBACK_ENTER_EXPLICIT(intvec_\vecname, .intrpt, 1 << 8) |
358 | jrp lr | 347 | jrp lr |
359 | .popsection | 348 | .popsection |
360 | #endif | 349 | #endif |
@@ -468,7 +457,7 @@ intvec_\vecname: | |||
468 | } | 457 | } |
469 | { | 458 | { |
470 | auli r21, r21, ha16(__per_cpu_offset) | 459 | auli r21, r21, ha16(__per_cpu_offset) |
471 | mm r20, r20, zero, 0, LOG2_THREAD_SIZE-1 | 460 | mm r20, r20, zero, 0, LOG2_NR_CPU_IDS-1 |
472 | } | 461 | } |
473 | s2a r20, r20, r21 | 462 | s2a r20, r20, r21 |
474 | lw tp, r20 | 463 | lw tp, r20 |
@@ -562,7 +551,6 @@ intvec_\vecname: | |||
562 | .endif | 551 | .endif |
563 | mtspr INTERRUPT_CRITICAL_SECTION, zero | 552 | mtspr INTERRUPT_CRITICAL_SECTION, zero |
564 | 553 | ||
565 | #if CHIP_HAS_WH64() | ||
566 | /* | 554 | /* |
567 | * Prepare the first 256 stack bytes to be rapidly accessible | 555 | * Prepare the first 256 stack bytes to be rapidly accessible |
568 | * without having to fetch the background data. We don't really | 556 | * without having to fetch the background data. We don't really |
@@ -583,7 +571,6 @@ intvec_\vecname: | |||
583 | addi r52, r52, -64 | 571 | addi r52, r52, -64 |
584 | } | 572 | } |
585 | wh64 r52 | 573 | wh64 r52 |
586 | #endif | ||
587 | 574 | ||
588 | #ifdef CONFIG_TRACE_IRQFLAGS | 575 | #ifdef CONFIG_TRACE_IRQFLAGS |
589 | .ifnc \function,handle_nmi | 576 | .ifnc \function,handle_nmi |
@@ -762,7 +749,7 @@ intvec_\vecname: | |||
762 | .macro dc_dispatch vecnum, vecname | 749 | .macro dc_dispatch vecnum, vecname |
763 | .org (\vecnum << 8) | 750 | .org (\vecnum << 8) |
764 | intvec_\vecname: | 751 | intvec_\vecname: |
765 | j hv_downcall_dispatch | 752 | j _hv_downcall_dispatch |
766 | ENDPROC(intvec_\vecname) | 753 | ENDPROC(intvec_\vecname) |
767 | .endm | 754 | .endm |
768 | 755 | ||
@@ -812,17 +799,34 @@ STD_ENTRY(interrupt_return) | |||
812 | } | 799 | } |
813 | lw r29, r29 | 800 | lw r29, r29 |
814 | andi r29, r29, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ | 801 | andi r29, r29, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ |
802 | bzt r29, .Lresume_userspace | ||
803 | |||
804 | #ifdef CONFIG_PREEMPT | ||
805 | /* Returning to kernel space. Check if we need preemption. */ | ||
806 | GET_THREAD_INFO(r29) | ||
807 | addli r28, r29, THREAD_INFO_FLAGS_OFFSET | ||
815 | { | 808 | { |
816 | bzt r29, .Lresume_userspace | 809 | lw r28, r28 |
817 | PTREGS_PTR(r29, PTREGS_OFFSET_PC) | 810 | addli r29, r29, THREAD_INFO_PREEMPT_COUNT_OFFSET |
818 | } | 811 | } |
812 | { | ||
813 | andi r28, r28, _TIF_NEED_RESCHED | ||
814 | lw r29, r29 | ||
815 | } | ||
816 | bzt r28, 1f | ||
817 | bnz r29, 1f | ||
818 | jal preempt_schedule_irq | ||
819 | FEEDBACK_REENTER(interrupt_return) | ||
820 | 1: | ||
821 | #endif | ||
819 | 822 | ||
820 | /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */ | 823 | /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */ |
821 | { | 824 | { |
822 | lw r28, r29 | 825 | PTREGS_PTR(r29, PTREGS_OFFSET_PC) |
823 | moveli r27, lo16(_cpu_idle_nap) | 826 | moveli r27, lo16(_cpu_idle_nap) |
824 | } | 827 | } |
825 | { | 828 | { |
829 | lw r28, r29 | ||
826 | auli r27, r27, ha16(_cpu_idle_nap) | 830 | auli r27, r27, ha16(_cpu_idle_nap) |
827 | } | 831 | } |
828 | { | 832 | { |
@@ -1420,7 +1424,6 @@ handle_ill: | |||
1420 | { | 1424 | { |
1421 | lw r0, r0 /* indirect thru thread_info to get task_info*/ | 1425 | lw r0, r0 /* indirect thru thread_info to get task_info*/ |
1422 | addi r1, sp, C_ABI_SAVE_AREA_SIZE /* put ptregs pointer into r1 */ | 1426 | addi r1, sp, C_ABI_SAVE_AREA_SIZE /* put ptregs pointer into r1 */ |
1423 | move r2, zero /* load error code into r2 */ | ||
1424 | } | 1427 | } |
1425 | 1428 | ||
1426 | jal send_sigtrap /* issue a SIGTRAP */ | 1429 | jal send_sigtrap /* issue a SIGTRAP */ |
@@ -1518,12 +1521,10 @@ STD_ENTRY(_sys_clone) | |||
1518 | __HEAD | 1521 | __HEAD |
1519 | .align 64 | 1522 | .align 64 |
1520 | /* Align much later jump on the start of a cache line. */ | 1523 | /* Align much later jump on the start of a cache line. */ |
1521 | #if !ATOMIC_LOCKS_FOUND_VIA_TABLE() | ||
1522 | nop | 1524 | nop |
1523 | #if PAGE_SIZE >= 0x10000 | 1525 | #if PAGE_SIZE >= 0x10000 |
1524 | nop | 1526 | nop |
1525 | #endif | 1527 | #endif |
1526 | #endif | ||
1527 | ENTRY(sys_cmpxchg) | 1528 | ENTRY(sys_cmpxchg) |
1528 | 1529 | ||
1529 | /* | 1530 | /* |
@@ -1557,45 +1558,6 @@ ENTRY(sys_cmpxchg) | |||
1557 | # error Code here assumes PAGE_OFFSET can be loaded with just hi16() | 1558 | # error Code here assumes PAGE_OFFSET can be loaded with just hi16() |
1558 | #endif | 1559 | #endif |
1559 | 1560 | ||
1560 | #if ATOMIC_LOCKS_FOUND_VIA_TABLE() | ||
1561 | { | ||
1562 | /* Check for unaligned input. */ | ||
1563 | bnz sp, .Lcmpxchg_badaddr | ||
1564 | mm r25, r0, zero, 3, PAGE_SHIFT-1 | ||
1565 | } | ||
1566 | { | ||
1567 | crc32_32 r25, zero, r25 | ||
1568 | moveli r21, lo16(atomic_lock_ptr) | ||
1569 | } | ||
1570 | { | ||
1571 | auli r21, r21, ha16(atomic_lock_ptr) | ||
1572 | auli r23, zero, hi16(PAGE_OFFSET) /* hugepage-aligned */ | ||
1573 | } | ||
1574 | { | ||
1575 | shri r20, r25, 32 - ATOMIC_HASH_L1_SHIFT | ||
1576 | slt_u r23, r0, r23 | ||
1577 | lw r26, r0 /* see comment in the "#else" for the "lw r26". */ | ||
1578 | } | ||
1579 | { | ||
1580 | s2a r21, r20, r21 | ||
1581 | bbns r23, .Lcmpxchg_badaddr | ||
1582 | } | ||
1583 | { | ||
1584 | lw r21, r21 | ||
1585 | seqi r23, TREG_SYSCALL_NR_NAME, __NR_FAST_cmpxchg64 | ||
1586 | andi r25, r25, ATOMIC_HASH_L2_SIZE - 1 | ||
1587 | } | ||
1588 | { | ||
1589 | /* Branch away at this point if we're doing a 64-bit cmpxchg. */ | ||
1590 | bbs r23, .Lcmpxchg64 | ||
1591 | andi r23, r0, 7 /* Precompute alignment for cmpxchg64. */ | ||
1592 | } | ||
1593 | { | ||
1594 | s2a ATOMIC_LOCK_REG_NAME, r25, r21 | ||
1595 | j .Lcmpxchg32_tns /* see comment in the #else for the jump. */ | ||
1596 | } | ||
1597 | |||
1598 | #else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */ | ||
1599 | { | 1561 | { |
1600 | /* Check for unaligned input. */ | 1562 | /* Check for unaligned input. */ |
1601 | bnz sp, .Lcmpxchg_badaddr | 1563 | bnz sp, .Lcmpxchg_badaddr |
@@ -1609,7 +1571,7 @@ ENTRY(sys_cmpxchg) | |||
1609 | * Because of C pointer arithmetic, we want to compute this: | 1571 | * Because of C pointer arithmetic, we want to compute this: |
1610 | * | 1572 | * |
1611 | * ((char*)atomic_locks + | 1573 | * ((char*)atomic_locks + |
1612 | * (((r0 >> 3) & (1 << (ATOMIC_HASH_SIZE - 1))) << 2)) | 1574 | * (((r0 >> 3) & ((1 << ATOMIC_HASH_SHIFT) - 1)) << 2)) |
1613 | * | 1575 | * |
1614 | * Instead of two shifts we just ">> 1", and use 'mm' | 1576 | * Instead of two shifts we just ">> 1", and use 'mm' |
1615 | * to ignore the low and high bits we don't want. | 1577 | * to ignore the low and high bits we don't want. |
@@ -1620,12 +1582,9 @@ ENTRY(sys_cmpxchg) | |||
1620 | 1582 | ||
1621 | /* | 1583 | /* |
1622 | * Ensure that the TLB is loaded before we take out the lock. | 1584 | * Ensure that the TLB is loaded before we take out the lock. |
1623 | * On tilepro, this will start fetching the value all the way | 1585 | * This will start fetching the value all the way into our L1 |
1624 | * into our L1 as well (and if it gets modified before we | 1586 | * as well (and if it gets modified before we grab the lock, |
1625 | * grab the lock, it will be invalidated from our cache | 1587 | * it will be invalidated from our cache before we reload it). |
1626 | * before we reload it). On tile64, we'll start fetching it | ||
1627 | * into our L1 if we're the home, and if we're not, we'll | ||
1628 | * still at least start fetching it into the home's L2. | ||
1629 | */ | 1588 | */ |
1630 | lw r26, r0 | 1589 | lw r26, r0 |
1631 | } | 1590 | } |
@@ -1668,8 +1627,6 @@ ENTRY(sys_cmpxchg) | |||
1668 | j .Lcmpxchg32_tns | 1627 | j .Lcmpxchg32_tns |
1669 | } | 1628 | } |
1670 | 1629 | ||
1671 | #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */ | ||
1672 | |||
1673 | /* Symbol for do_page_fault_ics() to use to compare against the PC. */ | 1630 | /* Symbol for do_page_fault_ics() to use to compare against the PC. */ |
1674 | .global __sys_cmpxchg_grab_lock | 1631 | .global __sys_cmpxchg_grab_lock |
1675 | __sys_cmpxchg_grab_lock: | 1632 | __sys_cmpxchg_grab_lock: |
@@ -1807,9 +1764,6 @@ __sys_cmpxchg_grab_lock: | |||
1807 | .align 64 | 1764 | .align 64 |
1808 | .Lcmpxchg64: | 1765 | .Lcmpxchg64: |
1809 | { | 1766 | { |
1810 | #if ATOMIC_LOCKS_FOUND_VIA_TABLE() | ||
1811 | s2a ATOMIC_LOCK_REG_NAME, r25, r21 | ||
1812 | #endif | ||
1813 | bzt r23, .Lcmpxchg64_tns | 1767 | bzt r23, .Lcmpxchg64_tns |
1814 | } | 1768 | } |
1815 | j .Lcmpxchg_badaddr | 1769 | j .Lcmpxchg_badaddr |
@@ -1875,8 +1829,8 @@ int_unalign: | |||
1875 | push_extra_callee_saves r0 | 1829 | push_extra_callee_saves r0 |
1876 | j do_trap | 1830 | j do_trap |
1877 | 1831 | ||
1878 | /* Include .intrpt1 array of interrupt vectors */ | 1832 | /* Include .intrpt array of interrupt vectors */ |
1879 | .section ".intrpt1", "ax" | 1833 | .section ".intrpt", "ax" |
1880 | 1834 | ||
1881 | #define op_handle_perf_interrupt bad_intr | 1835 | #define op_handle_perf_interrupt bad_intr |
1882 | #define op_handle_aux_perf_interrupt bad_intr | 1836 | #define op_handle_aux_perf_interrupt bad_intr |
@@ -1944,10 +1898,8 @@ int_unalign: | |||
1944 | do_page_fault | 1898 | do_page_fault |
1945 | int_hand INT_SN_CPL, SN_CPL, bad_intr | 1899 | int_hand INT_SN_CPL, SN_CPL, bad_intr |
1946 | int_hand INT_DOUBLE_FAULT, DOUBLE_FAULT, do_trap | 1900 | int_hand INT_DOUBLE_FAULT, DOUBLE_FAULT, do_trap |
1947 | #if CHIP_HAS_AUX_PERF_COUNTERS() | ||
1948 | int_hand INT_AUX_PERF_COUNT, AUX_PERF_COUNT, \ | 1901 | int_hand INT_AUX_PERF_COUNT, AUX_PERF_COUNT, \ |
1949 | op_handle_aux_perf_interrupt, handle_nmi | 1902 | op_handle_aux_perf_interrupt, handle_nmi |
1950 | #endif | ||
1951 | 1903 | ||
1952 | /* Synthetic interrupt delivered only by the simulator */ | 1904 | /* Synthetic interrupt delivered only by the simulator */ |
1953 | int_hand INT_BREAKPOINT, BREAKPOINT, do_breakpoint | 1905 | int_hand INT_BREAKPOINT, BREAKPOINT, do_breakpoint |
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S index 85d483957027..ec755d3f3734 100644 --- a/arch/tile/kernel/intvec_64.S +++ b/arch/tile/kernel/intvec_64.S | |||
@@ -17,25 +17,33 @@ | |||
17 | #include <linux/linkage.h> | 17 | #include <linux/linkage.h> |
18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
19 | #include <linux/unistd.h> | 19 | #include <linux/unistd.h> |
20 | #include <linux/init.h> | ||
20 | #include <asm/ptrace.h> | 21 | #include <asm/ptrace.h> |
21 | #include <asm/thread_info.h> | 22 | #include <asm/thread_info.h> |
22 | #include <asm/irqflags.h> | 23 | #include <asm/irqflags.h> |
23 | #include <asm/asm-offsets.h> | 24 | #include <asm/asm-offsets.h> |
24 | #include <asm/types.h> | 25 | #include <asm/types.h> |
26 | #include <asm/traps.h> | ||
25 | #include <asm/signal.h> | 27 | #include <asm/signal.h> |
26 | #include <hv/hypervisor.h> | 28 | #include <hv/hypervisor.h> |
27 | #include <arch/abi.h> | 29 | #include <arch/abi.h> |
28 | #include <arch/interrupts.h> | 30 | #include <arch/interrupts.h> |
29 | #include <arch/spr_def.h> | 31 | #include <arch/spr_def.h> |
30 | 32 | ||
31 | #ifdef CONFIG_PREEMPT | ||
32 | # error "No support for kernel preemption currently" | ||
33 | #endif | ||
34 | |||
35 | #define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg) | 33 | #define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg) |
36 | 34 | ||
37 | #define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR) | 35 | #define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR) |
38 | 36 | ||
37 | #if CONFIG_KERNEL_PL == 1 || CONFIG_KERNEL_PL == 2 | ||
38 | /* | ||
39 | * Set "result" non-zero if ex1 holds the PL of the kernel | ||
40 | * (with or without ICS being set). Note this works only | ||
41 | * because we never find the PL at level 3. | ||
42 | */ | ||
43 | # define IS_KERNEL_EX1(result, ex1) andi result, ex1, CONFIG_KERNEL_PL | ||
44 | #else | ||
45 | # error Recode IS_KERNEL_EX1 for CONFIG_KERNEL_PL | ||
46 | #endif | ||
39 | 47 | ||
40 | .macro push_reg reg, ptr=sp, delta=-8 | 48 | .macro push_reg reg, ptr=sp, delta=-8 |
41 | { | 49 | { |
@@ -98,6 +106,185 @@ | |||
98 | } | 106 | } |
99 | .endm | 107 | .endm |
100 | 108 | ||
109 | /* | ||
110 | * Unalign data exception fast handling: In order to handle | ||
111 | * unaligned data access, a fast JIT version is generated and stored | ||
112 | * in a specific area in user space. We first need to do a quick poke | ||
113 | * to see if the JIT is available. We use certain bits in the fault | ||
114 | * PC (3 to 9 is used for 16KB page size) as index to address the JIT | ||
115 | * code area. The first 64bit word is the fault PC, and the 2nd one is | ||
116 | * the fault bundle itself. If these 2 words both match, then we | ||
117 | * directly "iret" to JIT code. If not, a slow path is invoked to | ||
118 | * generate new JIT code. Note: the current JIT code WILL be | ||
119 | * overwritten if it existed. So, ideally we can handle 128 unalign | ||
120 | * fixups via JIT. For lookup efficiency and to effectively support | ||
121 | * tight loops with multiple unaligned reference, a simple | ||
122 | * direct-mapped cache is used. | ||
123 | * | ||
124 | * SPR_EX_CONTEXT_K_0 is modified to return to JIT code. | ||
125 | * SPR_EX_CONTEXT_K_1 has ICS set. | ||
126 | * SPR_EX_CONTEXT_0_0 is setup to user program's next PC. | ||
127 | * SPR_EX_CONTEXT_0_1 = 0. | ||
128 | */ | ||
129 | .macro int_hand_unalign_fast vecnum, vecname | ||
130 | .org (\vecnum << 8) | ||
131 | intvec_\vecname: | ||
132 | /* Put r3 in SPR_SYSTEM_SAVE_K_1. */ | ||
133 | mtspr SPR_SYSTEM_SAVE_K_1, r3 | ||
134 | |||
135 | mfspr r3, SPR_EX_CONTEXT_K_1 | ||
136 | /* | ||
137 | * Examine if exception comes from user without ICS set. | ||
138 | * If not, just go directly to the slow path. | ||
139 | */ | ||
140 | bnez r3, hand_unalign_slow_nonuser | ||
141 | |||
142 | mfspr r3, SPR_SYSTEM_SAVE_K_0 | ||
143 | |||
144 | /* Get &thread_info->unalign_jit_tmp[0] in r3. */ | ||
145 | bfexts r3, r3, 0, CPU_SHIFT-1 | ||
146 | mm r3, zero, LOG2_THREAD_SIZE, 63 | ||
147 | addli r3, r3, THREAD_INFO_UNALIGN_JIT_TMP_OFFSET | ||
148 | |||
149 | /* | ||
150 | * Save r0, r1, r2 into thread_info array r3 points to | ||
151 | * from low to high memory in order. | ||
152 | */ | ||
153 | st_add r3, r0, 8 | ||
154 | st_add r3, r1, 8 | ||
155 | { | ||
156 | st_add r3, r2, 8 | ||
157 | andi r2, sp, 7 | ||
158 | } | ||
159 | |||
160 | /* Save stored r3 value so we can revert it on a page fault. */ | ||
161 | mfspr r1, SPR_SYSTEM_SAVE_K_1 | ||
162 | st r3, r1 | ||
163 | |||
164 | { | ||
165 | /* Generate a SIGBUS if sp is not 8-byte aligned. */ | ||
166 | bnez r2, hand_unalign_slow_badsp | ||
167 | } | ||
168 | |||
169 | /* | ||
170 | * Get the thread_info in r0; load r1 with pc. Set the low bit of sp | ||
171 | * as an indicator to the page fault code in case we fault. | ||
172 | */ | ||
173 | { | ||
174 | ori sp, sp, 1 | ||
175 | mfspr r1, SPR_EX_CONTEXT_K_0 | ||
176 | } | ||
177 | |||
178 | /* Add the jit_info offset in thread_info; extract r1 [3:9] into r2. */ | ||
179 | { | ||
180 | addli r0, r3, THREAD_INFO_UNALIGN_JIT_BASE_OFFSET - \ | ||
181 | (THREAD_INFO_UNALIGN_JIT_TMP_OFFSET + (3 * 8)) | ||
182 | bfextu r2, r1, 3, (2 + PAGE_SHIFT - UNALIGN_JIT_SHIFT) | ||
183 | } | ||
184 | |||
185 | /* Load the jit_info; multiply r2 by 128. */ | ||
186 | { | ||
187 | ld r0, r0 | ||
188 | shli r2, r2, UNALIGN_JIT_SHIFT | ||
189 | } | ||
190 | |||
191 | /* | ||
192 | * If r0 is NULL, the JIT page is not mapped, so go to slow path; | ||
193 | * add offset r2 to r0 at the same time. | ||
194 | */ | ||
195 | { | ||
196 | beqz r0, hand_unalign_slow | ||
197 | add r2, r0, r2 | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * We are loading from userspace (both the JIT info PC and | ||
202 | * instruction word, and the instruction word we executed) | ||
203 | * and since either could fault while holding the interrupt | ||
204 | * critical section, we must tag this region and check it in | ||
205 | * do_page_fault() to handle it properly. | ||
206 | */ | ||
207 | ENTRY(__start_unalign_asm_code) | ||
208 | |||
209 | /* Load first word of JIT in r0 and increment r2 by 8. */ | ||
210 | ld_add r0, r2, 8 | ||
211 | |||
212 | /* | ||
213 | * Compare the PC with the 1st word in JIT; load the fault bundle | ||
214 | * into r1. | ||
215 | */ | ||
216 | { | ||
217 | cmpeq r0, r0, r1 | ||
218 | ld r1, r1 | ||
219 | } | ||
220 | |||
221 | /* Go to slow path if PC doesn't match. */ | ||
222 | beqz r0, hand_unalign_slow | ||
223 | |||
224 | /* | ||
225 | * Load the 2nd word of JIT, which is supposed to be the fault | ||
226 | * bundle for a cache hit. Increment r2; after this bundle r2 will | ||
227 | * point to the potential start of the JIT code we want to run. | ||
228 | */ | ||
229 | ld_add r0, r2, 8 | ||
230 | |||
231 | /* No further accesses to userspace are done after this point. */ | ||
232 | ENTRY(__end_unalign_asm_code) | ||
233 | |||
234 | /* Compare the real bundle with what is saved in the JIT area. */ | ||
235 | { | ||
236 | cmpeq r0, r1, r0 | ||
237 | mtspr SPR_EX_CONTEXT_0_1, zero | ||
238 | } | ||
239 | |||
240 | /* Go to slow path if the fault bundle does not match. */ | ||
241 | beqz r0, hand_unalign_slow | ||
242 | |||
243 | /* | ||
244 | * A cache hit is found. | ||
245 | * r2 points to start of JIT code (3rd word). | ||
246 | * r0 is the fault pc. | ||
247 | * r1 is the fault bundle. | ||
248 | * Reset the low bit of sp. | ||
249 | */ | ||
250 | { | ||
251 | mfspr r0, SPR_EX_CONTEXT_K_0 | ||
252 | andi sp, sp, ~1 | ||
253 | } | ||
254 | |||
255 | /* Write r2 into EX_CONTEXT_K_0 and increment PC. */ | ||
256 | { | ||
257 | mtspr SPR_EX_CONTEXT_K_0, r2 | ||
258 | addi r0, r0, 8 | ||
259 | } | ||
260 | |||
261 | /* | ||
262 | * Set ICS on kernel EX_CONTEXT_K_1 in order to "iret" to | ||
263 | * user with ICS set. This way, if the JIT fixup causes another | ||
264 | * unalign exception (which shouldn't be possible) the user | ||
265 | * process will be terminated with SIGBUS. Also, our fixup will | ||
266 | * run without interleaving with external interrupts. | ||
267 | * Each fixup is at most 14 bundles, so it won't hold ICS for long. | ||
268 | */ | ||
269 | { | ||
270 | movei r1, PL_ICS_EX1(USER_PL, 1) | ||
271 | mtspr SPR_EX_CONTEXT_0_0, r0 | ||
272 | } | ||
273 | |||
274 | { | ||
275 | mtspr SPR_EX_CONTEXT_K_1, r1 | ||
276 | addi r3, r3, -(3 * 8) | ||
277 | } | ||
278 | |||
279 | /* Restore r0..r3. */ | ||
280 | ld_add r0, r3, 8 | ||
281 | ld_add r1, r3, 8 | ||
282 | ld_add r2, r3, 8 | ||
283 | ld r3, r3 | ||
284 | |||
285 | iret | ||
286 | ENDPROC(intvec_\vecname) | ||
287 | .endm | ||
101 | 288 | ||
102 | #ifdef __COLLECT_LINKER_FEEDBACK__ | 289 | #ifdef __COLLECT_LINKER_FEEDBACK__ |
103 | .pushsection .text.intvec_feedback,"ax" | 290 | .pushsection .text.intvec_feedback,"ax" |
@@ -118,15 +305,21 @@ intvec_feedback: | |||
118 | * The "processing" argument specifies the code for processing | 305 | * The "processing" argument specifies the code for processing |
119 | * the interrupt. Defaults to "handle_interrupt". | 306 | * the interrupt. Defaults to "handle_interrupt". |
120 | */ | 307 | */ |
121 | .macro int_hand vecnum, vecname, c_routine, processing=handle_interrupt | 308 | .macro __int_hand vecnum, vecname, c_routine,processing=handle_interrupt |
122 | .org (\vecnum << 8) | ||
123 | intvec_\vecname: | 309 | intvec_\vecname: |
124 | /* Temporarily save a register so we have somewhere to work. */ | 310 | /* Temporarily save a register so we have somewhere to work. */ |
125 | 311 | ||
126 | mtspr SPR_SYSTEM_SAVE_K_1, r0 | 312 | mtspr SPR_SYSTEM_SAVE_K_1, r0 |
127 | mfspr r0, SPR_EX_CONTEXT_K_1 | 313 | mfspr r0, SPR_EX_CONTEXT_K_1 |
128 | 314 | ||
129 | andi r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ | 315 | /* |
316 | * The unalign data fastpath code sets the low bit in sp to | ||
317 | * force us to reset it here on fault. | ||
318 | */ | ||
319 | { | ||
320 | blbs sp, 2f | ||
321 | IS_KERNEL_EX1(r0, r0) | ||
322 | } | ||
130 | 323 | ||
131 | .ifc \vecnum, INT_DOUBLE_FAULT | 324 | .ifc \vecnum, INT_DOUBLE_FAULT |
132 | /* | 325 | /* |
@@ -176,15 +369,15 @@ intvec_\vecname: | |||
176 | } | 369 | } |
177 | .endif | 370 | .endif |
178 | 371 | ||
179 | 372 | 2: | |
180 | /* | 373 | /* |
181 | * SYSTEM_SAVE_K_0 holds the cpu number in the low bits, and | 374 | * SYSTEM_SAVE_K_0 holds the cpu number in the high bits, and |
182 | * the current stack top in the higher bits. So we recover | 375 | * the current stack top in the lower bits. So we recover |
183 | * our stack top by just masking off the low bits, then | 376 | * our starting stack value by sign-extending the low bits, then |
184 | * point sp at the top aligned address on the actual stack page. | 377 | * point sp at the top aligned address on the actual stack page. |
185 | */ | 378 | */ |
186 | mfspr r0, SPR_SYSTEM_SAVE_K_0 | 379 | mfspr r0, SPR_SYSTEM_SAVE_K_0 |
187 | mm r0, zero, LOG2_THREAD_SIZE, 63 | 380 | bfexts r0, r0, 0, CPU_SHIFT-1 |
188 | 381 | ||
189 | 0: | 382 | 0: |
190 | /* | 383 | /* |
@@ -206,6 +399,9 @@ intvec_\vecname: | |||
206 | * cache line 1: r6...r13 | 399 | * cache line 1: r6...r13 |
207 | * cache line 0: 2 x frame, r0..r5 | 400 | * cache line 0: 2 x frame, r0..r5 |
208 | */ | 401 | */ |
402 | #if STACK_TOP_DELTA != 64 | ||
403 | #error STACK_TOP_DELTA must be 64 for assumptions here and in task_pt_regs() | ||
404 | #endif | ||
209 | andi r0, r0, -64 | 405 | andi r0, r0, -64 |
210 | 406 | ||
211 | /* | 407 | /* |
@@ -305,7 +501,7 @@ intvec_\vecname: | |||
305 | mfspr r3, SPR_SYSTEM_SAVE_K_2 /* info about page fault */ | 501 | mfspr r3, SPR_SYSTEM_SAVE_K_2 /* info about page fault */ |
306 | .else | 502 | .else |
307 | .ifc \vecnum, INT_ILL_TRANS | 503 | .ifc \vecnum, INT_ILL_TRANS |
308 | mfspr r2, ILL_TRANS_REASON | 504 | mfspr r2, ILL_VA_PC |
309 | .else | 505 | .else |
310 | .ifc \vecnum, INT_DOUBLE_FAULT | 506 | .ifc \vecnum, INT_DOUBLE_FAULT |
311 | mfspr r2, SPR_SYSTEM_SAVE_K_2 /* double fault info from HV */ | 507 | mfspr r2, SPR_SYSTEM_SAVE_K_2 /* double fault info from HV */ |
@@ -315,12 +511,10 @@ intvec_\vecname: | |||
315 | .else | 511 | .else |
316 | .ifc \c_routine, op_handle_perf_interrupt | 512 | .ifc \c_routine, op_handle_perf_interrupt |
317 | mfspr r2, PERF_COUNT_STS | 513 | mfspr r2, PERF_COUNT_STS |
318 | #if CHIP_HAS_AUX_PERF_COUNTERS() | ||
319 | .else | 514 | .else |
320 | .ifc \c_routine, op_handle_aux_perf_interrupt | 515 | .ifc \c_routine, op_handle_aux_perf_interrupt |
321 | mfspr r2, AUX_PERF_COUNT_STS | 516 | mfspr r2, AUX_PERF_COUNT_STS |
322 | .endif | 517 | .endif |
323 | #endif | ||
324 | .endif | 518 | .endif |
325 | .endif | 519 | .endif |
326 | .endif | 520 | .endif |
@@ -339,7 +533,7 @@ intvec_\vecname: | |||
339 | #ifdef __COLLECT_LINKER_FEEDBACK__ | 533 | #ifdef __COLLECT_LINKER_FEEDBACK__ |
340 | .pushsection .text.intvec_feedback,"ax" | 534 | .pushsection .text.intvec_feedback,"ax" |
341 | .org (\vecnum << 5) | 535 | .org (\vecnum << 5) |
342 | FEEDBACK_ENTER_EXPLICIT(intvec_\vecname, .intrpt1, 1 << 8) | 536 | FEEDBACK_ENTER_EXPLICIT(intvec_\vecname, .intrpt, 1 << 8) |
343 | jrp lr | 537 | jrp lr |
344 | .popsection | 538 | .popsection |
345 | #endif | 539 | #endif |
@@ -455,11 +649,12 @@ intvec_\vecname: | |||
455 | /* | 649 | /* |
456 | * If we will be returning to the kernel, we will need to | 650 | * If we will be returning to the kernel, we will need to |
457 | * reset the interrupt masks to the state they had before. | 651 | * reset the interrupt masks to the state they had before. |
458 | * Set DISABLE_IRQ in flags iff we came from PL1 with irqs disabled. | 652 | * Set DISABLE_IRQ in flags iff we came from kernel pl with |
653 | * irqs disabled. | ||
459 | */ | 654 | */ |
460 | mfspr r32, SPR_EX_CONTEXT_K_1 | 655 | mfspr r32, SPR_EX_CONTEXT_K_1 |
461 | { | 656 | { |
462 | andi r32, r32, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ | 657 | IS_KERNEL_EX1(r22, r22) |
463 | PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS) | 658 | PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS) |
464 | } | 659 | } |
465 | beqzt r32, 1f /* zero if from user space */ | 660 | beqzt r32, 1f /* zero if from user space */ |
@@ -503,7 +698,7 @@ intvec_\vecname: | |||
503 | } | 698 | } |
504 | { | 699 | { |
505 | shl16insli r21, r21, hw1(__per_cpu_offset) | 700 | shl16insli r21, r21, hw1(__per_cpu_offset) |
506 | bfextu r20, r20, 0, LOG2_THREAD_SIZE-1 | 701 | bfextu r20, r20, CPU_SHIFT, 63 |
507 | } | 702 | } |
508 | shl16insli r21, r21, hw0(__per_cpu_offset) | 703 | shl16insli r21, r21, hw0(__per_cpu_offset) |
509 | shl3add r20, r20, r21 | 704 | shl3add r20, r20, r21 |
@@ -585,7 +780,7 @@ intvec_\vecname: | |||
585 | .macro dc_dispatch vecnum, vecname | 780 | .macro dc_dispatch vecnum, vecname |
586 | .org (\vecnum << 8) | 781 | .org (\vecnum << 8) |
587 | intvec_\vecname: | 782 | intvec_\vecname: |
588 | j hv_downcall_dispatch | 783 | j _hv_downcall_dispatch |
589 | ENDPROC(intvec_\vecname) | 784 | ENDPROC(intvec_\vecname) |
590 | .endm | 785 | .endm |
591 | 786 | ||
@@ -626,14 +821,36 @@ STD_ENTRY(interrupt_return) | |||
626 | PTREGS_PTR(r29, PTREGS_OFFSET_EX1) | 821 | PTREGS_PTR(r29, PTREGS_OFFSET_EX1) |
627 | } | 822 | } |
628 | ld r29, r29 | 823 | ld r29, r29 |
629 | andi r29, r29, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ | 824 | IS_KERNEL_EX1(r29, r29) |
630 | { | 825 | { |
631 | beqzt r29, .Lresume_userspace | 826 | beqzt r29, .Lresume_userspace |
632 | PTREGS_PTR(r29, PTREGS_OFFSET_PC) | 827 | move r29, sp |
828 | } | ||
829 | |||
830 | #ifdef CONFIG_PREEMPT | ||
831 | /* Returning to kernel space. Check if we need preemption. */ | ||
832 | EXTRACT_THREAD_INFO(r29) | ||
833 | addli r28, r29, THREAD_INFO_FLAGS_OFFSET | ||
834 | { | ||
835 | ld r28, r28 | ||
836 | addli r29, r29, THREAD_INFO_PREEMPT_COUNT_OFFSET | ||
837 | } | ||
838 | { | ||
839 | andi r28, r28, _TIF_NEED_RESCHED | ||
840 | ld4s r29, r29 | ||
633 | } | 841 | } |
842 | beqzt r28, 1f | ||
843 | bnez r29, 1f | ||
844 | jal preempt_schedule_irq | ||
845 | FEEDBACK_REENTER(interrupt_return) | ||
846 | 1: | ||
847 | #endif | ||
634 | 848 | ||
635 | /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */ | 849 | /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */ |
636 | moveli r27, hw2_last(_cpu_idle_nap) | 850 | { |
851 | moveli r27, hw2_last(_cpu_idle_nap) | ||
852 | PTREGS_PTR(r29, PTREGS_OFFSET_PC) | ||
853 | } | ||
637 | { | 854 | { |
638 | ld r28, r29 | 855 | ld r28, r29 |
639 | shl16insli r27, r27, hw1(_cpu_idle_nap) | 856 | shl16insli r27, r27, hw1(_cpu_idle_nap) |
@@ -728,7 +945,7 @@ STD_ENTRY(interrupt_return) | |||
728 | PTREGS_PTR(r32, PTREGS_OFFSET_FLAGS) | 945 | PTREGS_PTR(r32, PTREGS_OFFSET_FLAGS) |
729 | } | 946 | } |
730 | { | 947 | { |
731 | andi r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK | 948 | IS_KERNEL_EX1(r0, r0) |
732 | ld r32, r32 | 949 | ld r32, r32 |
733 | } | 950 | } |
734 | bnez r0, 1f | 951 | bnez r0, 1f |
@@ -799,7 +1016,7 @@ STD_ENTRY(interrupt_return) | |||
799 | pop_reg r21, sp, PTREGS_OFFSET_REG(31) - PTREGS_OFFSET_PC | 1016 | pop_reg r21, sp, PTREGS_OFFSET_REG(31) - PTREGS_OFFSET_PC |
800 | { | 1017 | { |
801 | mtspr SPR_EX_CONTEXT_K_1, lr | 1018 | mtspr SPR_EX_CONTEXT_K_1, lr |
802 | andi lr, lr, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ | 1019 | IS_KERNEL_EX1(lr, lr) |
803 | } | 1020 | } |
804 | { | 1021 | { |
805 | mtspr SPR_EX_CONTEXT_K_0, r21 | 1022 | mtspr SPR_EX_CONTEXT_K_0, r21 |
@@ -1223,10 +1440,31 @@ STD_ENTRY(_sys_clone) | |||
1223 | j sys_clone | 1440 | j sys_clone |
1224 | STD_ENDPROC(_sys_clone) | 1441 | STD_ENDPROC(_sys_clone) |
1225 | 1442 | ||
1226 | /* The single-step support may need to read all the registers. */ | 1443 | /* |
1444 | * Recover r3, r2, r1 and r0 here saved by unalign fast vector. | ||
1445 | * The vector area limit is 32 bundles, so we handle the reload here. | ||
1446 | * r0, r1, r2 are in thread_info from low to high memory in order. | ||
1447 | * r3 points to location the original r3 was saved. | ||
1448 | * We put this code in the __HEAD section so it can be reached | ||
1449 | * via a conditional branch from the fast path. | ||
1450 | */ | ||
1451 | __HEAD | ||
1452 | hand_unalign_slow: | ||
1453 | andi sp, sp, ~1 | ||
1454 | hand_unalign_slow_badsp: | ||
1455 | addi r3, r3, -(3 * 8) | ||
1456 | ld_add r0, r3, 8 | ||
1457 | ld_add r1, r3, 8 | ||
1458 | ld r2, r3 | ||
1459 | hand_unalign_slow_nonuser: | ||
1460 | mfspr r3, SPR_SYSTEM_SAVE_K_1 | ||
1461 | __int_hand INT_UNALIGN_DATA, UNALIGN_DATA_SLOW, int_unalign | ||
1462 | |||
1463 | /* The unaligned data support needs to read all the registers. */ | ||
1227 | int_unalign: | 1464 | int_unalign: |
1228 | push_extra_callee_saves r0 | 1465 | push_extra_callee_saves r0 |
1229 | j do_trap | 1466 | j do_unaligned |
1467 | ENDPROC(hand_unalign_slow) | ||
1230 | 1468 | ||
1231 | /* Fill the return address stack with nonzero entries. */ | 1469 | /* Fill the return address stack with nonzero entries. */ |
1232 | STD_ENTRY(fill_ra_stack) | 1470 | STD_ENTRY(fill_ra_stack) |
@@ -1240,8 +1478,15 @@ STD_ENTRY(fill_ra_stack) | |||
1240 | 4: jrp r0 | 1478 | 4: jrp r0 |
1241 | STD_ENDPROC(fill_ra_stack) | 1479 | STD_ENDPROC(fill_ra_stack) |
1242 | 1480 | ||
1243 | /* Include .intrpt1 array of interrupt vectors */ | 1481 | .macro int_hand vecnum, vecname, c_routine, processing=handle_interrupt |
1244 | .section ".intrpt1", "ax" | 1482 | .org (\vecnum << 8) |
1483 | __int_hand \vecnum, \vecname, \c_routine, \processing | ||
1484 | .endm | ||
1485 | |||
1486 | /* Include .intrpt array of interrupt vectors */ | ||
1487 | .section ".intrpt", "ax" | ||
1488 | .global intrpt_start | ||
1489 | intrpt_start: | ||
1245 | 1490 | ||
1246 | #define op_handle_perf_interrupt bad_intr | 1491 | #define op_handle_perf_interrupt bad_intr |
1247 | #define op_handle_aux_perf_interrupt bad_intr | 1492 | #define op_handle_aux_perf_interrupt bad_intr |
@@ -1272,7 +1517,7 @@ STD_ENTRY(fill_ra_stack) | |||
1272 | int_hand INT_SWINT_1, SWINT_1, SYSCALL, handle_syscall | 1517 | int_hand INT_SWINT_1, SWINT_1, SYSCALL, handle_syscall |
1273 | int_hand INT_SWINT_0, SWINT_0, do_trap | 1518 | int_hand INT_SWINT_0, SWINT_0, do_trap |
1274 | int_hand INT_ILL_TRANS, ILL_TRANS, do_trap | 1519 | int_hand INT_ILL_TRANS, ILL_TRANS, do_trap |
1275 | int_hand INT_UNALIGN_DATA, UNALIGN_DATA, int_unalign | 1520 | int_hand_unalign_fast INT_UNALIGN_DATA, UNALIGN_DATA |
1276 | int_hand INT_DTLB_MISS, DTLB_MISS, do_page_fault | 1521 | int_hand INT_DTLB_MISS, DTLB_MISS, do_page_fault |
1277 | int_hand INT_DTLB_ACCESS, DTLB_ACCESS, do_page_fault | 1522 | int_hand INT_DTLB_ACCESS, DTLB_ACCESS, do_page_fault |
1278 | int_hand INT_IDN_FIREWALL, IDN_FIREWALL, do_hardwall_trap | 1523 | int_hand INT_IDN_FIREWALL, IDN_FIREWALL, do_hardwall_trap |
diff --git a/arch/tile/kernel/irq.c b/arch/tile/kernel/irq.c index 3ccf2cd7182e..0586fdb9352d 100644 --- a/arch/tile/kernel/irq.c +++ b/arch/tile/kernel/irq.c | |||
@@ -55,7 +55,8 @@ static DEFINE_PER_CPU(int, irq_depth); | |||
55 | 55 | ||
56 | /* State for allocating IRQs on Gx. */ | 56 | /* State for allocating IRQs on Gx. */ |
57 | #if CHIP_HAS_IPI() | 57 | #if CHIP_HAS_IPI() |
58 | static unsigned long available_irqs = ~(1UL << IRQ_RESCHEDULE); | 58 | static unsigned long available_irqs = ((1UL << NR_IRQS) - 1) & |
59 | (~(1UL << IRQ_RESCHEDULE)); | ||
59 | static DEFINE_SPINLOCK(available_irqs_lock); | 60 | static DEFINE_SPINLOCK(available_irqs_lock); |
60 | #endif | 61 | #endif |
61 | 62 | ||
@@ -73,7 +74,8 @@ static DEFINE_SPINLOCK(available_irqs_lock); | |||
73 | 74 | ||
74 | /* | 75 | /* |
75 | * The interrupt handling path, implemented in terms of HV interrupt | 76 | * The interrupt handling path, implemented in terms of HV interrupt |
76 | * emulation on TILE64 and TILEPro, and IPI hardware on TILE-Gx. | 77 | * emulation on TILEPro, and IPI hardware on TILE-Gx. |
78 | * Entered with interrupts disabled. | ||
77 | */ | 79 | */ |
78 | void tile_dev_intr(struct pt_regs *regs, int intnum) | 80 | void tile_dev_intr(struct pt_regs *regs, int intnum) |
79 | { | 81 | { |
@@ -233,7 +235,7 @@ void tile_irq_activate(unsigned int irq, int tile_irq_type) | |||
233 | { | 235 | { |
234 | /* | 236 | /* |
235 | * We use handle_level_irq() by default because the pending | 237 | * We use handle_level_irq() by default because the pending |
236 | * interrupt vector (whether modeled by the HV on TILE64 and | 238 | * interrupt vector (whether modeled by the HV on |
237 | * TILEPro or implemented in hardware on TILE-Gx) has | 239 | * TILEPro or implemented in hardware on TILE-Gx) has |
238 | * level-style semantics for each bit. An interrupt fires | 240 | * level-style semantics for each bit. An interrupt fires |
239 | * whenever a bit is high, not just at edges. | 241 | * whenever a bit is high, not just at edges. |
diff --git a/arch/tile/kernel/kgdb.c b/arch/tile/kernel/kgdb.c new file mode 100644 index 000000000000..4cd88381a83e --- /dev/null +++ b/arch/tile/kernel/kgdb.c | |||
@@ -0,0 +1,499 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * TILE-Gx KGDB support. | ||
15 | */ | ||
16 | |||
17 | #include <linux/ptrace.h> | ||
18 | #include <linux/kgdb.h> | ||
19 | #include <linux/kdebug.h> | ||
20 | #include <linux/uaccess.h> | ||
21 | #include <linux/module.h> | ||
22 | #include <asm/cacheflush.h> | ||
23 | |||
24 | static tile_bundle_bits singlestep_insn = TILEGX_BPT_BUNDLE | DIE_SSTEPBP; | ||
25 | static unsigned long stepped_addr; | ||
26 | static tile_bundle_bits stepped_instr; | ||
27 | |||
28 | struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { | ||
29 | { "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0])}, | ||
30 | { "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1])}, | ||
31 | { "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2])}, | ||
32 | { "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3])}, | ||
33 | { "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4])}, | ||
34 | { "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5])}, | ||
35 | { "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6])}, | ||
36 | { "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7])}, | ||
37 | { "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8])}, | ||
38 | { "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9])}, | ||
39 | { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10])}, | ||
40 | { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11])}, | ||
41 | { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12])}, | ||
42 | { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13])}, | ||
43 | { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14])}, | ||
44 | { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15])}, | ||
45 | { "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16])}, | ||
46 | { "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17])}, | ||
47 | { "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18])}, | ||
48 | { "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19])}, | ||
49 | { "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20])}, | ||
50 | { "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21])}, | ||
51 | { "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22])}, | ||
52 | { "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23])}, | ||
53 | { "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24])}, | ||
54 | { "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25])}, | ||
55 | { "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26])}, | ||
56 | { "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27])}, | ||
57 | { "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28])}, | ||
58 | { "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29])}, | ||
59 | { "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30])}, | ||
60 | { "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31])}, | ||
61 | { "r32", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[32])}, | ||
62 | { "r33", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[33])}, | ||
63 | { "r34", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[34])}, | ||
64 | { "r35", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[35])}, | ||
65 | { "r36", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[36])}, | ||
66 | { "r37", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[37])}, | ||
67 | { "r38", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[38])}, | ||
68 | { "r39", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[39])}, | ||
69 | { "r40", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[40])}, | ||
70 | { "r41", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[41])}, | ||
71 | { "r42", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[42])}, | ||
72 | { "r43", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[43])}, | ||
73 | { "r44", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[44])}, | ||
74 | { "r45", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[45])}, | ||
75 | { "r46", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[46])}, | ||
76 | { "r47", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[47])}, | ||
77 | { "r48", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[48])}, | ||
78 | { "r49", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[49])}, | ||
79 | { "r50", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[50])}, | ||
80 | { "r51", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[51])}, | ||
81 | { "r52", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[52])}, | ||
82 | { "tp", GDB_SIZEOF_REG, offsetof(struct pt_regs, tp)}, | ||
83 | { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, sp)}, | ||
84 | { "lr", GDB_SIZEOF_REG, offsetof(struct pt_regs, lr)}, | ||
85 | { "sn", GDB_SIZEOF_REG, -1}, | ||
86 | { "idn0", GDB_SIZEOF_REG, -1}, | ||
87 | { "idn1", GDB_SIZEOF_REG, -1}, | ||
88 | { "udn0", GDB_SIZEOF_REG, -1}, | ||
89 | { "udn1", GDB_SIZEOF_REG, -1}, | ||
90 | { "udn2", GDB_SIZEOF_REG, -1}, | ||
91 | { "udn3", GDB_SIZEOF_REG, -1}, | ||
92 | { "zero", GDB_SIZEOF_REG, -1}, | ||
93 | { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, pc)}, | ||
94 | { "faultnum", GDB_SIZEOF_REG, offsetof(struct pt_regs, faultnum)}, | ||
95 | }; | ||
96 | |||
97 | char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) | ||
98 | { | ||
99 | if (regno >= DBG_MAX_REG_NUM || regno < 0) | ||
100 | return NULL; | ||
101 | |||
102 | if (dbg_reg_def[regno].offset != -1) | ||
103 | memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, | ||
104 | dbg_reg_def[regno].size); | ||
105 | else | ||
106 | memset(mem, 0, dbg_reg_def[regno].size); | ||
107 | return dbg_reg_def[regno].name; | ||
108 | } | ||
109 | |||
110 | int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) | ||
111 | { | ||
112 | if (regno >= DBG_MAX_REG_NUM || regno < 0) | ||
113 | return -EINVAL; | ||
114 | |||
115 | if (dbg_reg_def[regno].offset != -1) | ||
116 | memcpy((void *)regs + dbg_reg_def[regno].offset, mem, | ||
117 | dbg_reg_def[regno].size); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * Similar to pt_regs_to_gdb_regs() except that process is sleeping and so | ||
123 | * we may not be able to get all the info. | ||
124 | */ | ||
125 | void | ||
126 | sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) | ||
127 | { | ||
128 | int reg; | ||
129 | struct pt_regs *thread_regs; | ||
130 | unsigned long *ptr = gdb_regs; | ||
131 | |||
132 | if (task == NULL) | ||
133 | return; | ||
134 | |||
135 | /* Initialize to zero. */ | ||
136 | memset(gdb_regs, 0, NUMREGBYTES); | ||
137 | |||
138 | thread_regs = task_pt_regs(task); | ||
139 | for (reg = 0; reg <= TREG_LAST_GPR; reg++) | ||
140 | *(ptr++) = thread_regs->regs[reg]; | ||
141 | |||
142 | gdb_regs[TILEGX_PC_REGNUM] = thread_regs->pc; | ||
143 | gdb_regs[TILEGX_FAULTNUM_REGNUM] = thread_regs->faultnum; | ||
144 | } | ||
145 | |||
146 | void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) | ||
147 | { | ||
148 | regs->pc = pc; | ||
149 | } | ||
150 | |||
151 | static void kgdb_call_nmi_hook(void *ignored) | ||
152 | { | ||
153 | kgdb_nmicallback(raw_smp_processor_id(), NULL); | ||
154 | } | ||
155 | |||
156 | void kgdb_roundup_cpus(unsigned long flags) | ||
157 | { | ||
158 | local_irq_enable(); | ||
159 | smp_call_function(kgdb_call_nmi_hook, NULL, 0); | ||
160 | local_irq_disable(); | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Convert a kernel address to the writable kernel text mapping. | ||
165 | */ | ||
166 | static unsigned long writable_address(unsigned long addr) | ||
167 | { | ||
168 | unsigned long ret = 0; | ||
169 | |||
170 | if (core_kernel_text(addr)) | ||
171 | ret = addr - MEM_SV_START + PAGE_OFFSET; | ||
172 | else if (is_module_text_address(addr)) | ||
173 | ret = addr; | ||
174 | else | ||
175 | pr_err("Unknown virtual address 0x%lx\n", addr); | ||
176 | |||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * Calculate the new address for after a step. | ||
182 | */ | ||
183 | static unsigned long get_step_address(struct pt_regs *regs) | ||
184 | { | ||
185 | int src_reg; | ||
186 | int jump_off; | ||
187 | int br_off; | ||
188 | unsigned long addr; | ||
189 | unsigned int opcode; | ||
190 | tile_bundle_bits bundle; | ||
191 | |||
192 | /* Move to the next instruction by default. */ | ||
193 | addr = regs->pc + TILEGX_BUNDLE_SIZE_IN_BYTES; | ||
194 | bundle = *(unsigned long *)instruction_pointer(regs); | ||
195 | |||
196 | /* 0: X mode, Otherwise: Y mode. */ | ||
197 | if (bundle & TILEGX_BUNDLE_MODE_MASK) { | ||
198 | if (get_Opcode_Y1(bundle) == RRR_1_OPCODE_Y1 && | ||
199 | get_RRROpcodeExtension_Y1(bundle) == | ||
200 | UNARY_RRR_1_OPCODE_Y1) { | ||
201 | opcode = get_UnaryOpcodeExtension_Y1(bundle); | ||
202 | |||
203 | switch (opcode) { | ||
204 | case JALR_UNARY_OPCODE_Y1: | ||
205 | case JALRP_UNARY_OPCODE_Y1: | ||
206 | case JR_UNARY_OPCODE_Y1: | ||
207 | case JRP_UNARY_OPCODE_Y1: | ||
208 | src_reg = get_SrcA_Y1(bundle); | ||
209 | dbg_get_reg(src_reg, &addr, regs); | ||
210 | break; | ||
211 | } | ||
212 | } | ||
213 | } else if (get_Opcode_X1(bundle) == RRR_0_OPCODE_X1) { | ||
214 | if (get_RRROpcodeExtension_X1(bundle) == | ||
215 | UNARY_RRR_0_OPCODE_X1) { | ||
216 | opcode = get_UnaryOpcodeExtension_X1(bundle); | ||
217 | |||
218 | switch (opcode) { | ||
219 | case JALR_UNARY_OPCODE_X1: | ||
220 | case JALRP_UNARY_OPCODE_X1: | ||
221 | case JR_UNARY_OPCODE_X1: | ||
222 | case JRP_UNARY_OPCODE_X1: | ||
223 | src_reg = get_SrcA_X1(bundle); | ||
224 | dbg_get_reg(src_reg, &addr, regs); | ||
225 | break; | ||
226 | } | ||
227 | } | ||
228 | } else if (get_Opcode_X1(bundle) == JUMP_OPCODE_X1) { | ||
229 | opcode = get_JumpOpcodeExtension_X1(bundle); | ||
230 | |||
231 | switch (opcode) { | ||
232 | case JAL_JUMP_OPCODE_X1: | ||
233 | case J_JUMP_OPCODE_X1: | ||
234 | jump_off = sign_extend(get_JumpOff_X1(bundle), 27); | ||
235 | addr = regs->pc + | ||
236 | (jump_off << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES); | ||
237 | break; | ||
238 | } | ||
239 | } else if (get_Opcode_X1(bundle) == BRANCH_OPCODE_X1) { | ||
240 | br_off = 0; | ||
241 | opcode = get_BrType_X1(bundle); | ||
242 | |||
243 | switch (opcode) { | ||
244 | case BEQZT_BRANCH_OPCODE_X1: | ||
245 | case BEQZ_BRANCH_OPCODE_X1: | ||
246 | if (get_SrcA_X1(bundle) == 0) | ||
247 | br_off = get_BrOff_X1(bundle); | ||
248 | break; | ||
249 | case BGEZT_BRANCH_OPCODE_X1: | ||
250 | case BGEZ_BRANCH_OPCODE_X1: | ||
251 | if (get_SrcA_X1(bundle) >= 0) | ||
252 | br_off = get_BrOff_X1(bundle); | ||
253 | break; | ||
254 | case BGTZT_BRANCH_OPCODE_X1: | ||
255 | case BGTZ_BRANCH_OPCODE_X1: | ||
256 | if (get_SrcA_X1(bundle) > 0) | ||
257 | br_off = get_BrOff_X1(bundle); | ||
258 | break; | ||
259 | case BLBCT_BRANCH_OPCODE_X1: | ||
260 | case BLBC_BRANCH_OPCODE_X1: | ||
261 | if (!(get_SrcA_X1(bundle) & 1)) | ||
262 | br_off = get_BrOff_X1(bundle); | ||
263 | break; | ||
264 | case BLBST_BRANCH_OPCODE_X1: | ||
265 | case BLBS_BRANCH_OPCODE_X1: | ||
266 | if (get_SrcA_X1(bundle) & 1) | ||
267 | br_off = get_BrOff_X1(bundle); | ||
268 | break; | ||
269 | case BLEZT_BRANCH_OPCODE_X1: | ||
270 | case BLEZ_BRANCH_OPCODE_X1: | ||
271 | if (get_SrcA_X1(bundle) <= 0) | ||
272 | br_off = get_BrOff_X1(bundle); | ||
273 | break; | ||
274 | case BLTZT_BRANCH_OPCODE_X1: | ||
275 | case BLTZ_BRANCH_OPCODE_X1: | ||
276 | if (get_SrcA_X1(bundle) < 0) | ||
277 | br_off = get_BrOff_X1(bundle); | ||
278 | break; | ||
279 | case BNEZT_BRANCH_OPCODE_X1: | ||
280 | case BNEZ_BRANCH_OPCODE_X1: | ||
281 | if (get_SrcA_X1(bundle) != 0) | ||
282 | br_off = get_BrOff_X1(bundle); | ||
283 | break; | ||
284 | } | ||
285 | |||
286 | if (br_off != 0) { | ||
287 | br_off = sign_extend(br_off, 17); | ||
288 | addr = regs->pc + | ||
289 | (br_off << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | return addr; | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * Replace the next instruction after the current instruction with a | ||
298 | * breakpoint instruction. | ||
299 | */ | ||
300 | static void do_single_step(struct pt_regs *regs) | ||
301 | { | ||
302 | unsigned long addr_wr; | ||
303 | |||
304 | /* Determine where the target instruction will send us to. */ | ||
305 | stepped_addr = get_step_address(regs); | ||
306 | probe_kernel_read((char *)&stepped_instr, (char *)stepped_addr, | ||
307 | BREAK_INSTR_SIZE); | ||
308 | |||
309 | addr_wr = writable_address(stepped_addr); | ||
310 | probe_kernel_write((char *)addr_wr, (char *)&singlestep_insn, | ||
311 | BREAK_INSTR_SIZE); | ||
312 | smp_wmb(); | ||
313 | flush_icache_range(stepped_addr, stepped_addr + BREAK_INSTR_SIZE); | ||
314 | } | ||
315 | |||
316 | static void undo_single_step(struct pt_regs *regs) | ||
317 | { | ||
318 | unsigned long addr_wr; | ||
319 | |||
320 | if (stepped_instr == 0) | ||
321 | return; | ||
322 | |||
323 | addr_wr = writable_address(stepped_addr); | ||
324 | probe_kernel_write((char *)addr_wr, (char *)&stepped_instr, | ||
325 | BREAK_INSTR_SIZE); | ||
326 | stepped_instr = 0; | ||
327 | smp_wmb(); | ||
328 | flush_icache_range(stepped_addr, stepped_addr + BREAK_INSTR_SIZE); | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | * Calls linux_debug_hook before the kernel dies. If KGDB is enabled, | ||
333 | * then try to fall into the debugger. | ||
334 | */ | ||
335 | static int | ||
336 | kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) | ||
337 | { | ||
338 | int ret; | ||
339 | unsigned long flags; | ||
340 | struct die_args *args = (struct die_args *)ptr; | ||
341 | struct pt_regs *regs = args->regs; | ||
342 | |||
343 | #ifdef CONFIG_KPROBES | ||
344 | /* | ||
345 | * Return immediately if the kprobes fault notifier has set | ||
346 | * DIE_PAGE_FAULT. | ||
347 | */ | ||
348 | if (cmd == DIE_PAGE_FAULT) | ||
349 | return NOTIFY_DONE; | ||
350 | #endif /* CONFIG_KPROBES */ | ||
351 | |||
352 | switch (cmd) { | ||
353 | case DIE_BREAK: | ||
354 | case DIE_COMPILED_BPT: | ||
355 | break; | ||
356 | case DIE_SSTEPBP: | ||
357 | local_irq_save(flags); | ||
358 | kgdb_handle_exception(0, SIGTRAP, 0, regs); | ||
359 | local_irq_restore(flags); | ||
360 | return NOTIFY_STOP; | ||
361 | default: | ||
362 | /* Userspace events, ignore. */ | ||
363 | if (user_mode(regs)) | ||
364 | return NOTIFY_DONE; | ||
365 | } | ||
366 | |||
367 | local_irq_save(flags); | ||
368 | ret = kgdb_handle_exception(args->trapnr, args->signr, args->err, regs); | ||
369 | local_irq_restore(flags); | ||
370 | if (ret) | ||
371 | return NOTIFY_DONE; | ||
372 | |||
373 | return NOTIFY_STOP; | ||
374 | } | ||
375 | |||
376 | static struct notifier_block kgdb_notifier = { | ||
377 | .notifier_call = kgdb_notify, | ||
378 | }; | ||
379 | |||
380 | /* | ||
381 | * kgdb_arch_handle_exception - Handle architecture specific GDB packets. | ||
382 | * @vector: The error vector of the exception that happened. | ||
383 | * @signo: The signal number of the exception that happened. | ||
384 | * @err_code: The error code of the exception that happened. | ||
385 | * @remcom_in_buffer: The buffer of the packet we have read. | ||
386 | * @remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into. | ||
387 | * @regs: The &struct pt_regs of the current process. | ||
388 | * | ||
389 | * This function MUST handle the 'c' and 's' command packets, | ||
390 | * as well packets to set / remove a hardware breakpoint, if used. | ||
391 | * If there are additional packets which the hardware needs to handle, | ||
392 | * they are handled here. The code should return -1 if it wants to | ||
393 | * process more packets, and a %0 or %1 if it wants to exit from the | ||
394 | * kgdb callback. | ||
395 | */ | ||
396 | int kgdb_arch_handle_exception(int vector, int signo, int err_code, | ||
397 | char *remcom_in_buffer, char *remcom_out_buffer, | ||
398 | struct pt_regs *regs) | ||
399 | { | ||
400 | char *ptr; | ||
401 | unsigned long address; | ||
402 | |||
403 | /* Undo any stepping we may have done. */ | ||
404 | undo_single_step(regs); | ||
405 | |||
406 | switch (remcom_in_buffer[0]) { | ||
407 | case 'c': | ||
408 | case 's': | ||
409 | case 'D': | ||
410 | case 'k': | ||
411 | /* | ||
412 | * Try to read optional parameter, pc unchanged if no parm. | ||
413 | * If this was a compiled-in breakpoint, we need to move | ||
414 | * to the next instruction or we will just breakpoint | ||
415 | * over and over again. | ||
416 | */ | ||
417 | ptr = &remcom_in_buffer[1]; | ||
418 | if (kgdb_hex2long(&ptr, &address)) | ||
419 | regs->pc = address; | ||
420 | else if (*(unsigned long *)regs->pc == compiled_bpt) | ||
421 | regs->pc += BREAK_INSTR_SIZE; | ||
422 | |||
423 | if (remcom_in_buffer[0] == 's') { | ||
424 | do_single_step(regs); | ||
425 | kgdb_single_step = 1; | ||
426 | atomic_set(&kgdb_cpu_doing_single_step, | ||
427 | raw_smp_processor_id()); | ||
428 | } else | ||
429 | atomic_set(&kgdb_cpu_doing_single_step, -1); | ||
430 | |||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | return -1; /* this means that we do not want to exit from the handler */ | ||
435 | } | ||
436 | |||
437 | struct kgdb_arch arch_kgdb_ops; | ||
438 | |||
439 | /* | ||
440 | * kgdb_arch_init - Perform any architecture specific initalization. | ||
441 | * | ||
442 | * This function will handle the initalization of any architecture | ||
443 | * specific callbacks. | ||
444 | */ | ||
445 | int kgdb_arch_init(void) | ||
446 | { | ||
447 | tile_bundle_bits bundle = TILEGX_BPT_BUNDLE; | ||
448 | |||
449 | memcpy(arch_kgdb_ops.gdb_bpt_instr, &bundle, BREAK_INSTR_SIZE); | ||
450 | return register_die_notifier(&kgdb_notifier); | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * kgdb_arch_exit - Perform any architecture specific uninitalization. | ||
455 | * | ||
456 | * This function will handle the uninitalization of any architecture | ||
457 | * specific callbacks, for dynamic registration and unregistration. | ||
458 | */ | ||
459 | void kgdb_arch_exit(void) | ||
460 | { | ||
461 | unregister_die_notifier(&kgdb_notifier); | ||
462 | } | ||
463 | |||
464 | int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) | ||
465 | { | ||
466 | int err; | ||
467 | unsigned long addr_wr = writable_address(bpt->bpt_addr); | ||
468 | |||
469 | if (addr_wr == 0) | ||
470 | return -1; | ||
471 | |||
472 | err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, | ||
473 | BREAK_INSTR_SIZE); | ||
474 | if (err) | ||
475 | return err; | ||
476 | |||
477 | err = probe_kernel_write((char *)addr_wr, arch_kgdb_ops.gdb_bpt_instr, | ||
478 | BREAK_INSTR_SIZE); | ||
479 | smp_wmb(); | ||
480 | flush_icache_range((unsigned long)bpt->bpt_addr, | ||
481 | (unsigned long)bpt->bpt_addr + BREAK_INSTR_SIZE); | ||
482 | return err; | ||
483 | } | ||
484 | |||
485 | int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) | ||
486 | { | ||
487 | int err; | ||
488 | unsigned long addr_wr = writable_address(bpt->bpt_addr); | ||
489 | |||
490 | if (addr_wr == 0) | ||
491 | return -1; | ||
492 | |||
493 | err = probe_kernel_write((char *)addr_wr, (char *)bpt->saved_instr, | ||
494 | BREAK_INSTR_SIZE); | ||
495 | smp_wmb(); | ||
496 | flush_icache_range((unsigned long)bpt->bpt_addr, | ||
497 | (unsigned long)bpt->bpt_addr + BREAK_INSTR_SIZE); | ||
498 | return err; | ||
499 | } | ||
diff --git a/arch/tile/kernel/kprobes.c b/arch/tile/kernel/kprobes.c new file mode 100644 index 000000000000..27cdcacbe81d --- /dev/null +++ b/arch/tile/kernel/kprobes.c | |||
@@ -0,0 +1,528 @@ | |||
1 | /* | ||
2 | * arch/tile/kernel/kprobes.c | ||
3 | * Kprobes on TILE-Gx | ||
4 | * | ||
5 | * Some portions copied from the MIPS version. | ||
6 | * | ||
7 | * Copyright (C) IBM Corporation, 2002, 2004 | ||
8 | * Copyright 2006 Sony Corp. | ||
9 | * Copyright 2010 Cavium Networks | ||
10 | * | ||
11 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation, version 2. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, but | ||
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
20 | * NON INFRINGEMENT. See the GNU General Public License for | ||
21 | * more details. | ||
22 | */ | ||
23 | |||
24 | #include <linux/kprobes.h> | ||
25 | #include <linux/kdebug.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/uaccess.h> | ||
29 | #include <asm/cacheflush.h> | ||
30 | |||
31 | #include <arch/opcode.h> | ||
32 | |||
33 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; | ||
34 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | ||
35 | |||
36 | tile_bundle_bits breakpoint_insn = TILEGX_BPT_BUNDLE; | ||
37 | tile_bundle_bits breakpoint2_insn = TILEGX_BPT_BUNDLE | DIE_SSTEPBP; | ||
38 | |||
39 | /* | ||
40 | * Check whether instruction is branch or jump, or if executing it | ||
41 | * has different results depending on where it is executed (e.g. lnk). | ||
42 | */ | ||
43 | static int __kprobes insn_has_control(kprobe_opcode_t insn) | ||
44 | { | ||
45 | if (get_Mode(insn) != 0) { /* Y-format bundle */ | ||
46 | if (get_Opcode_Y1(insn) != RRR_1_OPCODE_Y1 || | ||
47 | get_RRROpcodeExtension_Y1(insn) != UNARY_RRR_1_OPCODE_Y1) | ||
48 | return 0; | ||
49 | |||
50 | switch (get_UnaryOpcodeExtension_Y1(insn)) { | ||
51 | case JALRP_UNARY_OPCODE_Y1: | ||
52 | case JALR_UNARY_OPCODE_Y1: | ||
53 | case JRP_UNARY_OPCODE_Y1: | ||
54 | case JR_UNARY_OPCODE_Y1: | ||
55 | case LNK_UNARY_OPCODE_Y1: | ||
56 | return 1; | ||
57 | default: | ||
58 | return 0; | ||
59 | } | ||
60 | } | ||
61 | |||
62 | switch (get_Opcode_X1(insn)) { | ||
63 | case BRANCH_OPCODE_X1: /* branch instructions */ | ||
64 | case JUMP_OPCODE_X1: /* jump instructions: j and jal */ | ||
65 | return 1; | ||
66 | |||
67 | case RRR_0_OPCODE_X1: /* other jump instructions */ | ||
68 | if (get_RRROpcodeExtension_X1(insn) != UNARY_RRR_0_OPCODE_X1) | ||
69 | return 0; | ||
70 | switch (get_UnaryOpcodeExtension_X1(insn)) { | ||
71 | case JALRP_UNARY_OPCODE_X1: | ||
72 | case JALR_UNARY_OPCODE_X1: | ||
73 | case JRP_UNARY_OPCODE_X1: | ||
74 | case JR_UNARY_OPCODE_X1: | ||
75 | case LNK_UNARY_OPCODE_X1: | ||
76 | return 1; | ||
77 | default: | ||
78 | return 0; | ||
79 | } | ||
80 | default: | ||
81 | return 0; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | int __kprobes arch_prepare_kprobe(struct kprobe *p) | ||
86 | { | ||
87 | unsigned long addr = (unsigned long)p->addr; | ||
88 | |||
89 | if (addr & (sizeof(kprobe_opcode_t) - 1)) | ||
90 | return -EINVAL; | ||
91 | |||
92 | if (insn_has_control(*p->addr)) { | ||
93 | pr_notice("Kprobes for control instructions are not " | ||
94 | "supported\n"); | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | |||
98 | /* insn: must be on special executable page on tile. */ | ||
99 | p->ainsn.insn = get_insn_slot(); | ||
100 | if (!p->ainsn.insn) | ||
101 | return -ENOMEM; | ||
102 | |||
103 | /* | ||
104 | * In the kprobe->ainsn.insn[] array we store the original | ||
105 | * instruction at index zero and a break trap instruction at | ||
106 | * index one. | ||
107 | */ | ||
108 | memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t)); | ||
109 | p->ainsn.insn[1] = breakpoint2_insn; | ||
110 | p->opcode = *p->addr; | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | void __kprobes arch_arm_kprobe(struct kprobe *p) | ||
116 | { | ||
117 | unsigned long addr_wr; | ||
118 | |||
119 | /* Operate on writable kernel text mapping. */ | ||
120 | addr_wr = (unsigned long)p->addr - MEM_SV_START + PAGE_OFFSET; | ||
121 | |||
122 | if (probe_kernel_write((void *)addr_wr, &breakpoint_insn, | ||
123 | sizeof(breakpoint_insn))) | ||
124 | pr_err("%s: failed to enable kprobe\n", __func__); | ||
125 | |||
126 | smp_wmb(); | ||
127 | flush_insn_slot(p); | ||
128 | } | ||
129 | |||
130 | void __kprobes arch_disarm_kprobe(struct kprobe *kp) | ||
131 | { | ||
132 | unsigned long addr_wr; | ||
133 | |||
134 | /* Operate on writable kernel text mapping. */ | ||
135 | addr_wr = (unsigned long)kp->addr - MEM_SV_START + PAGE_OFFSET; | ||
136 | |||
137 | if (probe_kernel_write((void *)addr_wr, &kp->opcode, | ||
138 | sizeof(kp->opcode))) | ||
139 | pr_err("%s: failed to enable kprobe\n", __func__); | ||
140 | |||
141 | smp_wmb(); | ||
142 | flush_insn_slot(kp); | ||
143 | } | ||
144 | |||
145 | void __kprobes arch_remove_kprobe(struct kprobe *p) | ||
146 | { | ||
147 | if (p->ainsn.insn) { | ||
148 | free_insn_slot(p->ainsn.insn, 0); | ||
149 | p->ainsn.insn = NULL; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) | ||
154 | { | ||
155 | kcb->prev_kprobe.kp = kprobe_running(); | ||
156 | kcb->prev_kprobe.status = kcb->kprobe_status; | ||
157 | kcb->prev_kprobe.saved_pc = kcb->kprobe_saved_pc; | ||
158 | } | ||
159 | |||
160 | static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) | ||
161 | { | ||
162 | __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); | ||
163 | kcb->kprobe_status = kcb->prev_kprobe.status; | ||
164 | kcb->kprobe_saved_pc = kcb->prev_kprobe.saved_pc; | ||
165 | } | ||
166 | |||
167 | static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, | ||
168 | struct kprobe_ctlblk *kcb) | ||
169 | { | ||
170 | __this_cpu_write(current_kprobe, p); | ||
171 | kcb->kprobe_saved_pc = regs->pc; | ||
172 | } | ||
173 | |||
174 | static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
175 | { | ||
176 | /* Single step inline if the instruction is a break. */ | ||
177 | if (p->opcode == breakpoint_insn || | ||
178 | p->opcode == breakpoint2_insn) | ||
179 | regs->pc = (unsigned long)p->addr; | ||
180 | else | ||
181 | regs->pc = (unsigned long)&p->ainsn.insn[0]; | ||
182 | } | ||
183 | |||
184 | static int __kprobes kprobe_handler(struct pt_regs *regs) | ||
185 | { | ||
186 | struct kprobe *p; | ||
187 | int ret = 0; | ||
188 | kprobe_opcode_t *addr; | ||
189 | struct kprobe_ctlblk *kcb; | ||
190 | |||
191 | addr = (kprobe_opcode_t *)regs->pc; | ||
192 | |||
193 | /* | ||
194 | * We don't want to be preempted for the entire | ||
195 | * duration of kprobe processing. | ||
196 | */ | ||
197 | preempt_disable(); | ||
198 | kcb = get_kprobe_ctlblk(); | ||
199 | |||
200 | /* Check we're not actually recursing. */ | ||
201 | if (kprobe_running()) { | ||
202 | p = get_kprobe(addr); | ||
203 | if (p) { | ||
204 | if (kcb->kprobe_status == KPROBE_HIT_SS && | ||
205 | p->ainsn.insn[0] == breakpoint_insn) { | ||
206 | goto no_kprobe; | ||
207 | } | ||
208 | /* | ||
209 | * We have reentered the kprobe_handler(), since | ||
210 | * another probe was hit while within the handler. | ||
211 | * We here save the original kprobes variables and | ||
212 | * just single step on the instruction of the new probe | ||
213 | * without calling any user handlers. | ||
214 | */ | ||
215 | save_previous_kprobe(kcb); | ||
216 | set_current_kprobe(p, regs, kcb); | ||
217 | kprobes_inc_nmissed_count(p); | ||
218 | prepare_singlestep(p, regs); | ||
219 | kcb->kprobe_status = KPROBE_REENTER; | ||
220 | return 1; | ||
221 | } else { | ||
222 | if (*addr != breakpoint_insn) { | ||
223 | /* | ||
224 | * The breakpoint instruction was removed by | ||
225 | * another cpu right after we hit, no further | ||
226 | * handling of this interrupt is appropriate. | ||
227 | */ | ||
228 | ret = 1; | ||
229 | goto no_kprobe; | ||
230 | } | ||
231 | p = __this_cpu_read(current_kprobe); | ||
232 | if (p->break_handler && p->break_handler(p, regs)) | ||
233 | goto ss_probe; | ||
234 | } | ||
235 | goto no_kprobe; | ||
236 | } | ||
237 | |||
238 | p = get_kprobe(addr); | ||
239 | if (!p) { | ||
240 | if (*addr != breakpoint_insn) { | ||
241 | /* | ||
242 | * The breakpoint instruction was removed right | ||
243 | * after we hit it. Another cpu has removed | ||
244 | * either a probepoint or a debugger breakpoint | ||
245 | * at this address. In either case, no further | ||
246 | * handling of this interrupt is appropriate. | ||
247 | */ | ||
248 | ret = 1; | ||
249 | } | ||
250 | /* Not one of ours: let kernel handle it. */ | ||
251 | goto no_kprobe; | ||
252 | } | ||
253 | |||
254 | set_current_kprobe(p, regs, kcb); | ||
255 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; | ||
256 | |||
257 | if (p->pre_handler && p->pre_handler(p, regs)) { | ||
258 | /* Handler has already set things up, so skip ss setup. */ | ||
259 | return 1; | ||
260 | } | ||
261 | |||
262 | ss_probe: | ||
263 | prepare_singlestep(p, regs); | ||
264 | kcb->kprobe_status = KPROBE_HIT_SS; | ||
265 | return 1; | ||
266 | |||
267 | no_kprobe: | ||
268 | preempt_enable_no_resched(); | ||
269 | return ret; | ||
270 | } | ||
271 | |||
272 | /* | ||
273 | * Called after single-stepping. p->addr is the address of the | ||
274 | * instruction that has been replaced by the breakpoint. To avoid the | ||
275 | * SMP problems that can occur when we temporarily put back the | ||
276 | * original opcode to single-step, we single-stepped a copy of the | ||
277 | * instruction. The address of this copy is p->ainsn.insn. | ||
278 | * | ||
279 | * This function prepares to return from the post-single-step | ||
280 | * breakpoint trap. | ||
281 | */ | ||
282 | static void __kprobes resume_execution(struct kprobe *p, | ||
283 | struct pt_regs *regs, | ||
284 | struct kprobe_ctlblk *kcb) | ||
285 | { | ||
286 | unsigned long orig_pc = kcb->kprobe_saved_pc; | ||
287 | regs->pc = orig_pc + 8; | ||
288 | } | ||
289 | |||
290 | static inline int post_kprobe_handler(struct pt_regs *regs) | ||
291 | { | ||
292 | struct kprobe *cur = kprobe_running(); | ||
293 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
294 | |||
295 | if (!cur) | ||
296 | return 0; | ||
297 | |||
298 | if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { | ||
299 | kcb->kprobe_status = KPROBE_HIT_SSDONE; | ||
300 | cur->post_handler(cur, regs, 0); | ||
301 | } | ||
302 | |||
303 | resume_execution(cur, regs, kcb); | ||
304 | |||
305 | /* Restore back the original saved kprobes variables and continue. */ | ||
306 | if (kcb->kprobe_status == KPROBE_REENTER) { | ||
307 | restore_previous_kprobe(kcb); | ||
308 | goto out; | ||
309 | } | ||
310 | reset_current_kprobe(); | ||
311 | out: | ||
312 | preempt_enable_no_resched(); | ||
313 | |||
314 | return 1; | ||
315 | } | ||
316 | |||
317 | static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) | ||
318 | { | ||
319 | struct kprobe *cur = kprobe_running(); | ||
320 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
321 | |||
322 | if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) | ||
323 | return 1; | ||
324 | |||
325 | if (kcb->kprobe_status & KPROBE_HIT_SS) { | ||
326 | /* | ||
327 | * We are here because the instruction being single | ||
328 | * stepped caused a page fault. We reset the current | ||
329 | * kprobe and the ip points back to the probe address | ||
330 | * and allow the page fault handler to continue as a | ||
331 | * normal page fault. | ||
332 | */ | ||
333 | resume_execution(cur, regs, kcb); | ||
334 | reset_current_kprobe(); | ||
335 | preempt_enable_no_resched(); | ||
336 | } | ||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | /* | ||
341 | * Wrapper routine for handling exceptions. | ||
342 | */ | ||
343 | int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | ||
344 | unsigned long val, void *data) | ||
345 | { | ||
346 | struct die_args *args = (struct die_args *)data; | ||
347 | int ret = NOTIFY_DONE; | ||
348 | |||
349 | switch (val) { | ||
350 | case DIE_BREAK: | ||
351 | if (kprobe_handler(args->regs)) | ||
352 | ret = NOTIFY_STOP; | ||
353 | break; | ||
354 | case DIE_SSTEPBP: | ||
355 | if (post_kprobe_handler(args->regs)) | ||
356 | ret = NOTIFY_STOP; | ||
357 | break; | ||
358 | case DIE_PAGE_FAULT: | ||
359 | /* kprobe_running() needs smp_processor_id(). */ | ||
360 | preempt_disable(); | ||
361 | |||
362 | if (kprobe_running() | ||
363 | && kprobe_fault_handler(args->regs, args->trapnr)) | ||
364 | ret = NOTIFY_STOP; | ||
365 | preempt_enable(); | ||
366 | break; | ||
367 | default: | ||
368 | break; | ||
369 | } | ||
370 | return ret; | ||
371 | } | ||
372 | |||
373 | int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | ||
374 | { | ||
375 | struct jprobe *jp = container_of(p, struct jprobe, kp); | ||
376 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
377 | |||
378 | kcb->jprobe_saved_regs = *regs; | ||
379 | kcb->jprobe_saved_sp = regs->sp; | ||
380 | |||
381 | memcpy(kcb->jprobes_stack, (void *)kcb->jprobe_saved_sp, | ||
382 | MIN_JPROBES_STACK_SIZE(kcb->jprobe_saved_sp)); | ||
383 | |||
384 | regs->pc = (unsigned long)(jp->entry); | ||
385 | |||
386 | return 1; | ||
387 | } | ||
388 | |||
389 | /* Defined in the inline asm below. */ | ||
390 | void jprobe_return_end(void); | ||
391 | |||
392 | void __kprobes jprobe_return(void) | ||
393 | { | ||
394 | asm volatile( | ||
395 | "bpt\n\t" | ||
396 | ".globl jprobe_return_end\n" | ||
397 | "jprobe_return_end:\n"); | ||
398 | } | ||
399 | |||
400 | int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) | ||
401 | { | ||
402 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | ||
403 | |||
404 | if (regs->pc >= (unsigned long)jprobe_return && | ||
405 | regs->pc <= (unsigned long)jprobe_return_end) { | ||
406 | *regs = kcb->jprobe_saved_regs; | ||
407 | memcpy((void *)kcb->jprobe_saved_sp, kcb->jprobes_stack, | ||
408 | MIN_JPROBES_STACK_SIZE(kcb->jprobe_saved_sp)); | ||
409 | preempt_enable_no_resched(); | ||
410 | |||
411 | return 1; | ||
412 | } | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | * Function return probe trampoline: | ||
418 | * - init_kprobes() establishes a probepoint here | ||
419 | * - When the probed function returns, this probe causes the | ||
420 | * handlers to fire | ||
421 | */ | ||
422 | static void __used kretprobe_trampoline_holder(void) | ||
423 | { | ||
424 | asm volatile( | ||
425 | "nop\n\t" | ||
426 | ".global kretprobe_trampoline\n" | ||
427 | "kretprobe_trampoline:\n\t" | ||
428 | "nop\n\t" | ||
429 | : : : "memory"); | ||
430 | } | ||
431 | |||
432 | void kretprobe_trampoline(void); | ||
433 | |||
434 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, | ||
435 | struct pt_regs *regs) | ||
436 | { | ||
437 | ri->ret_addr = (kprobe_opcode_t *) regs->lr; | ||
438 | |||
439 | /* Replace the return addr with trampoline addr */ | ||
440 | regs->lr = (unsigned long)kretprobe_trampoline; | ||
441 | } | ||
442 | |||
443 | /* | ||
444 | * Called when the probe at kretprobe trampoline is hit. | ||
445 | */ | ||
446 | static int __kprobes trampoline_probe_handler(struct kprobe *p, | ||
447 | struct pt_regs *regs) | ||
448 | { | ||
449 | struct kretprobe_instance *ri = NULL; | ||
450 | struct hlist_head *head, empty_rp; | ||
451 | struct hlist_node *tmp; | ||
452 | unsigned long flags, orig_ret_address = 0; | ||
453 | unsigned long trampoline_address = (unsigned long)kretprobe_trampoline; | ||
454 | |||
455 | INIT_HLIST_HEAD(&empty_rp); | ||
456 | kretprobe_hash_lock(current, &head, &flags); | ||
457 | |||
458 | /* | ||
459 | * It is possible to have multiple instances associated with a given | ||
460 | * task either because multiple functions in the call path have | ||
461 | * a return probe installed on them, and/or more than one return | ||
462 | * return probe was registered for a target function. | ||
463 | * | ||
464 | * We can handle this because: | ||
465 | * - instances are always inserted at the head of the list | ||
466 | * - when multiple return probes are registered for the same | ||
467 | * function, the first instance's ret_addr will point to the | ||
468 | * real return address, and all the rest will point to | ||
469 | * kretprobe_trampoline | ||
470 | */ | ||
471 | hlist_for_each_entry_safe(ri, tmp, head, hlist) { | ||
472 | if (ri->task != current) | ||
473 | /* another task is sharing our hash bucket */ | ||
474 | continue; | ||
475 | |||
476 | if (ri->rp && ri->rp->handler) | ||
477 | ri->rp->handler(ri, regs); | ||
478 | |||
479 | orig_ret_address = (unsigned long)ri->ret_addr; | ||
480 | recycle_rp_inst(ri, &empty_rp); | ||
481 | |||
482 | if (orig_ret_address != trampoline_address) { | ||
483 | /* | ||
484 | * This is the real return address. Any other | ||
485 | * instances associated with this task are for | ||
486 | * other calls deeper on the call stack | ||
487 | */ | ||
488 | break; | ||
489 | } | ||
490 | } | ||
491 | |||
492 | kretprobe_assert(ri, orig_ret_address, trampoline_address); | ||
493 | instruction_pointer(regs) = orig_ret_address; | ||
494 | |||
495 | reset_current_kprobe(); | ||
496 | kretprobe_hash_unlock(current, &flags); | ||
497 | preempt_enable_no_resched(); | ||
498 | |||
499 | hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { | ||
500 | hlist_del(&ri->hlist); | ||
501 | kfree(ri); | ||
502 | } | ||
503 | /* | ||
504 | * By returning a non-zero value, we are telling | ||
505 | * kprobe_handler() that we don't want the post_handler | ||
506 | * to run (and have re-enabled preemption) | ||
507 | */ | ||
508 | return 1; | ||
509 | } | ||
510 | |||
511 | int __kprobes arch_trampoline_kprobe(struct kprobe *p) | ||
512 | { | ||
513 | if (p->addr == (kprobe_opcode_t *)kretprobe_trampoline) | ||
514 | return 1; | ||
515 | |||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | static struct kprobe trampoline_p = { | ||
520 | .addr = (kprobe_opcode_t *)kretprobe_trampoline, | ||
521 | .pre_handler = trampoline_probe_handler | ||
522 | }; | ||
523 | |||
524 | int __init arch_init_kprobes(void) | ||
525 | { | ||
526 | register_kprobe(&trampoline_p); | ||
527 | return 0; | ||
528 | } | ||
diff --git a/arch/tile/kernel/mcount_64.S b/arch/tile/kernel/mcount_64.S new file mode 100644 index 000000000000..70d7bb0c4d8f --- /dev/null +++ b/arch/tile/kernel/mcount_64.S | |||
@@ -0,0 +1,224 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * TILE-Gx specific __mcount support | ||
15 | */ | ||
16 | |||
17 | #include <linux/linkage.h> | ||
18 | #include <asm/ftrace.h> | ||
19 | |||
20 | #define REGSIZE 8 | ||
21 | |||
22 | .text | ||
23 | .global __mcount | ||
24 | |||
25 | .macro MCOUNT_SAVE_REGS | ||
26 | addli sp, sp, -REGSIZE | ||
27 | { | ||
28 | st sp, lr | ||
29 | addli r29, sp, - (12 * REGSIZE) | ||
30 | } | ||
31 | { | ||
32 | addli sp, sp, - (13 * REGSIZE) | ||
33 | st r29, sp | ||
34 | } | ||
35 | addli r29, r29, REGSIZE | ||
36 | { st r29, r0; addli r29, r29, REGSIZE } | ||
37 | { st r29, r1; addli r29, r29, REGSIZE } | ||
38 | { st r29, r2; addli r29, r29, REGSIZE } | ||
39 | { st r29, r3; addli r29, r29, REGSIZE } | ||
40 | { st r29, r4; addli r29, r29, REGSIZE } | ||
41 | { st r29, r5; addli r29, r29, REGSIZE } | ||
42 | { st r29, r6; addli r29, r29, REGSIZE } | ||
43 | { st r29, r7; addli r29, r29, REGSIZE } | ||
44 | { st r29, r8; addli r29, r29, REGSIZE } | ||
45 | { st r29, r9; addli r29, r29, REGSIZE } | ||
46 | { st r29, r10; addli r29, r29, REGSIZE } | ||
47 | .endm | ||
48 | |||
49 | .macro MCOUNT_RESTORE_REGS | ||
50 | addli r29, sp, (2 * REGSIZE) | ||
51 | { ld r0, r29; addli r29, r29, REGSIZE } | ||
52 | { ld r1, r29; addli r29, r29, REGSIZE } | ||
53 | { ld r2, r29; addli r29, r29, REGSIZE } | ||
54 | { ld r3, r29; addli r29, r29, REGSIZE } | ||
55 | { ld r4, r29; addli r29, r29, REGSIZE } | ||
56 | { ld r5, r29; addli r29, r29, REGSIZE } | ||
57 | { ld r6, r29; addli r29, r29, REGSIZE } | ||
58 | { ld r7, r29; addli r29, r29, REGSIZE } | ||
59 | { ld r8, r29; addli r29, r29, REGSIZE } | ||
60 | { ld r9, r29; addli r29, r29, REGSIZE } | ||
61 | { ld r10, r29; addli lr, sp, (13 * REGSIZE) } | ||
62 | { ld lr, lr; addli sp, sp, (14 * REGSIZE) } | ||
63 | .endm | ||
64 | |||
65 | .macro RETURN_BACK | ||
66 | { move r12, lr; move lr, r10 } | ||
67 | jrp r12 | ||
68 | .endm | ||
69 | |||
70 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
71 | |||
72 | .align 64 | ||
73 | STD_ENTRY(__mcount) | ||
74 | __mcount: | ||
75 | j ftrace_stub | ||
76 | STD_ENDPROC(__mcount) | ||
77 | |||
78 | .align 64 | ||
79 | STD_ENTRY(ftrace_caller) | ||
80 | moveli r11, hw2_last(function_trace_stop) | ||
81 | { shl16insli r11, r11, hw1(function_trace_stop); move r12, lr } | ||
82 | { shl16insli r11, r11, hw0(function_trace_stop); move lr, r10 } | ||
83 | ld r11, r11 | ||
84 | beqz r11, 1f | ||
85 | jrp r12 | ||
86 | |||
87 | 1: | ||
88 | { move r10, lr; move lr, r12 } | ||
89 | MCOUNT_SAVE_REGS | ||
90 | |||
91 | /* arg1: self return address */ | ||
92 | /* arg2: parent's return address */ | ||
93 | { move r0, lr; move r1, r10 } | ||
94 | |||
95 | .global ftrace_call | ||
96 | ftrace_call: | ||
97 | /* | ||
98 | * a placeholder for the call to a real tracing function, i.e. | ||
99 | * ftrace_trace_function() | ||
100 | */ | ||
101 | nop | ||
102 | |||
103 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
104 | .global ftrace_graph_call | ||
105 | ftrace_graph_call: | ||
106 | /* | ||
107 | * a placeholder for the call to a real tracing function, i.e. | ||
108 | * ftrace_graph_caller() | ||
109 | */ | ||
110 | nop | ||
111 | #endif | ||
112 | MCOUNT_RESTORE_REGS | ||
113 | .global ftrace_stub | ||
114 | ftrace_stub: | ||
115 | RETURN_BACK | ||
116 | STD_ENDPROC(ftrace_caller) | ||
117 | |||
118 | #else /* ! CONFIG_DYNAMIC_FTRACE */ | ||
119 | |||
120 | .align 64 | ||
121 | STD_ENTRY(__mcount) | ||
122 | moveli r11, hw2_last(function_trace_stop) | ||
123 | { shl16insli r11, r11, hw1(function_trace_stop); move r12, lr } | ||
124 | { shl16insli r11, r11, hw0(function_trace_stop); move lr, r10 } | ||
125 | ld r11, r11 | ||
126 | beqz r11, 1f | ||
127 | jrp r12 | ||
128 | |||
129 | 1: | ||
130 | { move r10, lr; move lr, r12 } | ||
131 | { | ||
132 | moveli r11, hw2_last(ftrace_trace_function) | ||
133 | moveli r13, hw2_last(ftrace_stub) | ||
134 | } | ||
135 | { | ||
136 | shl16insli r11, r11, hw1(ftrace_trace_function) | ||
137 | shl16insli r13, r13, hw1(ftrace_stub) | ||
138 | } | ||
139 | { | ||
140 | shl16insli r11, r11, hw0(ftrace_trace_function) | ||
141 | shl16insli r13, r13, hw0(ftrace_stub) | ||
142 | } | ||
143 | |||
144 | ld r11, r11 | ||
145 | sub r14, r13, r11 | ||
146 | bnez r14, static_trace | ||
147 | |||
148 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
149 | moveli r15, hw2_last(ftrace_graph_return) | ||
150 | shl16insli r15, r15, hw1(ftrace_graph_return) | ||
151 | shl16insli r15, r15, hw0(ftrace_graph_return) | ||
152 | ld r15, r15 | ||
153 | sub r15, r15, r13 | ||
154 | bnez r15, ftrace_graph_caller | ||
155 | |||
156 | { | ||
157 | moveli r16, hw2_last(ftrace_graph_entry) | ||
158 | moveli r17, hw2_last(ftrace_graph_entry_stub) | ||
159 | } | ||
160 | { | ||
161 | shl16insli r16, r16, hw1(ftrace_graph_entry) | ||
162 | shl16insli r17, r17, hw1(ftrace_graph_entry_stub) | ||
163 | } | ||
164 | { | ||
165 | shl16insli r16, r16, hw0(ftrace_graph_entry) | ||
166 | shl16insli r17, r17, hw0(ftrace_graph_entry_stub) | ||
167 | } | ||
168 | ld r16, r16 | ||
169 | sub r17, r16, r17 | ||
170 | bnez r17, ftrace_graph_caller | ||
171 | |||
172 | #endif | ||
173 | RETURN_BACK | ||
174 | |||
175 | static_trace: | ||
176 | MCOUNT_SAVE_REGS | ||
177 | |||
178 | /* arg1: self return address */ | ||
179 | /* arg2: parent's return address */ | ||
180 | { move r0, lr; move r1, r10 } | ||
181 | |||
182 | /* call ftrace_trace_function() */ | ||
183 | jalr r11 | ||
184 | |||
185 | MCOUNT_RESTORE_REGS | ||
186 | |||
187 | .global ftrace_stub | ||
188 | ftrace_stub: | ||
189 | RETURN_BACK | ||
190 | STD_ENDPROC(__mcount) | ||
191 | |||
192 | #endif /* ! CONFIG_DYNAMIC_FTRACE */ | ||
193 | |||
194 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
195 | |||
196 | STD_ENTRY(ftrace_graph_caller) | ||
197 | ftrace_graph_caller: | ||
198 | #ifndef CONFIG_DYNAMIC_FTRACE | ||
199 | MCOUNT_SAVE_REGS | ||
200 | #endif | ||
201 | |||
202 | /* arg1: Get the location of the parent's return address */ | ||
203 | addi r0, sp, 12 * REGSIZE | ||
204 | /* arg2: Get self return address */ | ||
205 | move r1, lr | ||
206 | |||
207 | jal prepare_ftrace_return | ||
208 | |||
209 | MCOUNT_RESTORE_REGS | ||
210 | RETURN_BACK | ||
211 | STD_ENDPROC(ftrace_graph_caller) | ||
212 | |||
213 | .global return_to_handler | ||
214 | return_to_handler: | ||
215 | MCOUNT_SAVE_REGS | ||
216 | |||
217 | jal ftrace_return_to_handler | ||
218 | /* restore the real parent address */ | ||
219 | move r11, r0 | ||
220 | |||
221 | MCOUNT_RESTORE_REGS | ||
222 | jr r11 | ||
223 | |||
224 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
diff --git a/arch/tile/kernel/pci-dma.c b/arch/tile/kernel/pci-dma.c index b9fe80ec1089..09b58703ac26 100644 --- a/arch/tile/kernel/pci-dma.c +++ b/arch/tile/kernel/pci-dma.c | |||
@@ -36,8 +36,9 @@ static void *tile_dma_alloc_coherent(struct device *dev, size_t size, | |||
36 | dma_addr_t *dma_handle, gfp_t gfp, | 36 | dma_addr_t *dma_handle, gfp_t gfp, |
37 | struct dma_attrs *attrs) | 37 | struct dma_attrs *attrs) |
38 | { | 38 | { |
39 | u64 dma_mask = dev->coherent_dma_mask ?: DMA_BIT_MASK(32); | 39 | u64 dma_mask = (dev && dev->coherent_dma_mask) ? |
40 | int node = dev_to_node(dev); | 40 | dev->coherent_dma_mask : DMA_BIT_MASK(32); |
41 | int node = dev ? dev_to_node(dev) : 0; | ||
41 | int order = get_order(size); | 42 | int order = get_order(size); |
42 | struct page *pg; | 43 | struct page *pg; |
43 | dma_addr_t addr; | 44 | dma_addr_t addr; |
@@ -256,7 +257,7 @@ static void tile_dma_unmap_page(struct device *dev, dma_addr_t dma_address, | |||
256 | BUG_ON(!valid_dma_direction(direction)); | 257 | BUG_ON(!valid_dma_direction(direction)); |
257 | 258 | ||
258 | __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)), | 259 | __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)), |
259 | dma_address & PAGE_OFFSET, size, direction); | 260 | dma_address & (PAGE_SIZE - 1), size, direction); |
260 | } | 261 | } |
261 | 262 | ||
262 | static void tile_dma_sync_single_for_cpu(struct device *dev, | 263 | static void tile_dma_sync_single_for_cpu(struct device *dev, |
@@ -357,7 +358,7 @@ static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size, | |||
357 | 358 | ||
358 | addr = page_to_phys(pg); | 359 | addr = page_to_phys(pg); |
359 | 360 | ||
360 | *dma_handle = phys_to_dma(dev, addr); | 361 | *dma_handle = addr + get_dma_offset(dev); |
361 | 362 | ||
362 | return page_address(pg); | 363 | return page_address(pg); |
363 | } | 364 | } |
@@ -387,7 +388,7 @@ static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist, | |||
387 | sg->dma_address = sg_phys(sg); | 388 | sg->dma_address = sg_phys(sg); |
388 | __dma_prep_pa_range(sg->dma_address, sg->length, direction); | 389 | __dma_prep_pa_range(sg->dma_address, sg->length, direction); |
389 | 390 | ||
390 | sg->dma_address = phys_to_dma(dev, sg->dma_address); | 391 | sg->dma_address = sg->dma_address + get_dma_offset(dev); |
391 | #ifdef CONFIG_NEED_SG_DMA_LENGTH | 392 | #ifdef CONFIG_NEED_SG_DMA_LENGTH |
392 | sg->dma_length = sg->length; | 393 | sg->dma_length = sg->length; |
393 | #endif | 394 | #endif |
@@ -422,7 +423,7 @@ static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page, | |||
422 | BUG_ON(offset + size > PAGE_SIZE); | 423 | BUG_ON(offset + size > PAGE_SIZE); |
423 | __dma_prep_page(page, offset, size, direction); | 424 | __dma_prep_page(page, offset, size, direction); |
424 | 425 | ||
425 | return phys_to_dma(dev, page_to_pa(page) + offset); | 426 | return page_to_pa(page) + offset + get_dma_offset(dev); |
426 | } | 427 | } |
427 | 428 | ||
428 | static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address, | 429 | static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address, |
@@ -432,10 +433,10 @@ static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address, | |||
432 | { | 433 | { |
433 | BUG_ON(!valid_dma_direction(direction)); | 434 | BUG_ON(!valid_dma_direction(direction)); |
434 | 435 | ||
435 | dma_address = dma_to_phys(dev, dma_address); | 436 | dma_address -= get_dma_offset(dev); |
436 | 437 | ||
437 | __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)), | 438 | __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)), |
438 | dma_address & PAGE_OFFSET, size, direction); | 439 | dma_address & (PAGE_SIZE - 1), size, direction); |
439 | } | 440 | } |
440 | 441 | ||
441 | static void tile_pci_dma_sync_single_for_cpu(struct device *dev, | 442 | static void tile_pci_dma_sync_single_for_cpu(struct device *dev, |
@@ -445,7 +446,7 @@ static void tile_pci_dma_sync_single_for_cpu(struct device *dev, | |||
445 | { | 446 | { |
446 | BUG_ON(!valid_dma_direction(direction)); | 447 | BUG_ON(!valid_dma_direction(direction)); |
447 | 448 | ||
448 | dma_handle = dma_to_phys(dev, dma_handle); | 449 | dma_handle -= get_dma_offset(dev); |
449 | 450 | ||
450 | __dma_complete_pa_range(dma_handle, size, direction); | 451 | __dma_complete_pa_range(dma_handle, size, direction); |
451 | } | 452 | } |
@@ -456,7 +457,7 @@ static void tile_pci_dma_sync_single_for_device(struct device *dev, | |||
456 | enum dma_data_direction | 457 | enum dma_data_direction |
457 | direction) | 458 | direction) |
458 | { | 459 | { |
459 | dma_handle = dma_to_phys(dev, dma_handle); | 460 | dma_handle -= get_dma_offset(dev); |
460 | 461 | ||
461 | __dma_prep_pa_range(dma_handle, size, direction); | 462 | __dma_prep_pa_range(dma_handle, size, direction); |
462 | } | 463 | } |
@@ -558,22 +559,47 @@ static struct dma_map_ops pci_swiotlb_dma_ops = { | |||
558 | .mapping_error = swiotlb_dma_mapping_error, | 559 | .mapping_error = swiotlb_dma_mapping_error, |
559 | }; | 560 | }; |
560 | 561 | ||
562 | static struct dma_map_ops pci_hybrid_dma_ops = { | ||
563 | .alloc = tile_swiotlb_alloc_coherent, | ||
564 | .free = tile_swiotlb_free_coherent, | ||
565 | .map_page = tile_pci_dma_map_page, | ||
566 | .unmap_page = tile_pci_dma_unmap_page, | ||
567 | .map_sg = tile_pci_dma_map_sg, | ||
568 | .unmap_sg = tile_pci_dma_unmap_sg, | ||
569 | .sync_single_for_cpu = tile_pci_dma_sync_single_for_cpu, | ||
570 | .sync_single_for_device = tile_pci_dma_sync_single_for_device, | ||
571 | .sync_sg_for_cpu = tile_pci_dma_sync_sg_for_cpu, | ||
572 | .sync_sg_for_device = tile_pci_dma_sync_sg_for_device, | ||
573 | .mapping_error = tile_pci_dma_mapping_error, | ||
574 | .dma_supported = tile_pci_dma_supported | ||
575 | }; | ||
576 | |||
561 | struct dma_map_ops *gx_legacy_pci_dma_map_ops = &pci_swiotlb_dma_ops; | 577 | struct dma_map_ops *gx_legacy_pci_dma_map_ops = &pci_swiotlb_dma_ops; |
578 | struct dma_map_ops *gx_hybrid_pci_dma_map_ops = &pci_hybrid_dma_ops; | ||
562 | #else | 579 | #else |
563 | struct dma_map_ops *gx_legacy_pci_dma_map_ops; | 580 | struct dma_map_ops *gx_legacy_pci_dma_map_ops; |
581 | struct dma_map_ops *gx_hybrid_pci_dma_map_ops; | ||
564 | #endif | 582 | #endif |
565 | EXPORT_SYMBOL(gx_legacy_pci_dma_map_ops); | 583 | EXPORT_SYMBOL(gx_legacy_pci_dma_map_ops); |
584 | EXPORT_SYMBOL(gx_hybrid_pci_dma_map_ops); | ||
566 | 585 | ||
567 | #ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK | 586 | #ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK |
568 | int dma_set_coherent_mask(struct device *dev, u64 mask) | 587 | int dma_set_coherent_mask(struct device *dev, u64 mask) |
569 | { | 588 | { |
570 | struct dma_map_ops *dma_ops = get_dma_ops(dev); | 589 | struct dma_map_ops *dma_ops = get_dma_ops(dev); |
571 | 590 | ||
572 | /* Handle legacy PCI devices with limited memory addressability. */ | 591 | /* |
573 | if (((dma_ops == gx_pci_dma_map_ops) || | 592 | * For PCI devices with 64-bit DMA addressing capability, promote |
574 | (dma_ops == gx_legacy_pci_dma_map_ops)) && | 593 | * the dma_ops to full capability for both streams and consistent |
575 | (mask <= DMA_BIT_MASK(32))) { | 594 | * memory access. For 32-bit capable devices, limit the consistent |
576 | if (mask > dev->archdata.max_direct_dma_addr) | 595 | * memory DMA range to max_direct_dma_addr. |
596 | */ | ||
597 | if (dma_ops == gx_pci_dma_map_ops || | ||
598 | dma_ops == gx_hybrid_pci_dma_map_ops || | ||
599 | dma_ops == gx_legacy_pci_dma_map_ops) { | ||
600 | if (mask == DMA_BIT_MASK(64)) | ||
601 | set_dma_ops(dev, gx_pci_dma_map_ops); | ||
602 | else if (mask > dev->archdata.max_direct_dma_addr) | ||
577 | mask = dev->archdata.max_direct_dma_addr; | 603 | mask = dev->archdata.max_direct_dma_addr; |
578 | } | 604 | } |
579 | 605 | ||
@@ -584,3 +610,21 @@ int dma_set_coherent_mask(struct device *dev, u64 mask) | |||
584 | } | 610 | } |
585 | EXPORT_SYMBOL(dma_set_coherent_mask); | 611 | EXPORT_SYMBOL(dma_set_coherent_mask); |
586 | #endif | 612 | #endif |
613 | |||
614 | #ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK | ||
615 | /* | ||
616 | * The generic dma_get_required_mask() uses the highest physical address | ||
617 | * (max_pfn) to provide the hint to the PCI drivers regarding 32-bit or | ||
618 | * 64-bit DMA configuration. Since TILEGx has I/O TLB/MMU, allowing the | ||
619 | * DMAs to use the full 64-bit PCI address space and not limited by | ||
620 | * the physical memory space, we always let the PCI devices use | ||
621 | * 64-bit DMA if they have that capability, by returning the 64-bit | ||
622 | * DMA mask here. The device driver has the option to use 32-bit DMA if | ||
623 | * the device is not capable of 64-bit DMA. | ||
624 | */ | ||
625 | u64 dma_get_required_mask(struct device *dev) | ||
626 | { | ||
627 | return DMA_BIT_MASK(64); | ||
628 | } | ||
629 | EXPORT_SYMBOL_GPL(dma_get_required_mask); | ||
630 | #endif | ||
diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c index 67237d34c2e2..b7180e6e900d 100644 --- a/arch/tile/kernel/pci.c +++ b/arch/tile/kernel/pci.c | |||
@@ -20,7 +20,6 @@ | |||
20 | #include <linux/capability.h> | 20 | #include <linux/capability.h> |
21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
22 | #include <linux/errno.h> | 22 | #include <linux/errno.h> |
23 | #include <linux/bootmem.h> | ||
24 | #include <linux/irq.h> | 23 | #include <linux/irq.h> |
25 | #include <linux/io.h> | 24 | #include <linux/io.h> |
26 | #include <linux/uaccess.h> | 25 | #include <linux/uaccess.h> |
@@ -52,6 +51,8 @@ | |||
52 | * | 51 | * |
53 | */ | 52 | */ |
54 | 53 | ||
54 | static int pci_probe = 1; | ||
55 | |||
55 | /* | 56 | /* |
56 | * This flag tells if the platform is TILEmpower that needs | 57 | * This flag tells if the platform is TILEmpower that needs |
57 | * special configuration for the PLX switch chip. | 58 | * special configuration for the PLX switch chip. |
@@ -144,6 +145,11 @@ int __init tile_pci_init(void) | |||
144 | { | 145 | { |
145 | int i; | 146 | int i; |
146 | 147 | ||
148 | if (!pci_probe) { | ||
149 | pr_info("PCI: disabled by boot argument\n"); | ||
150 | return 0; | ||
151 | } | ||
152 | |||
147 | pr_info("PCI: Searching for controllers...\n"); | 153 | pr_info("PCI: Searching for controllers...\n"); |
148 | 154 | ||
149 | /* Re-init number of PCIe controllers to support hot-plug feature. */ | 155 | /* Re-init number of PCIe controllers to support hot-plug feature. */ |
@@ -192,7 +198,6 @@ int __init tile_pci_init(void) | |||
192 | controller->hv_cfg_fd[0] = hv_cfg_fd0; | 198 | controller->hv_cfg_fd[0] = hv_cfg_fd0; |
193 | controller->hv_cfg_fd[1] = hv_cfg_fd1; | 199 | controller->hv_cfg_fd[1] = hv_cfg_fd1; |
194 | controller->hv_mem_fd = hv_mem_fd; | 200 | controller->hv_mem_fd = hv_mem_fd; |
195 | controller->first_busno = 0; | ||
196 | controller->last_busno = 0xff; | 201 | controller->last_busno = 0xff; |
197 | controller->ops = &tile_cfg_ops; | 202 | controller->ops = &tile_cfg_ops; |
198 | 203 | ||
@@ -283,7 +288,7 @@ int __init pcibios_init(void) | |||
283 | * known to require at least 20ms here, but we use a more | 288 | * known to require at least 20ms here, but we use a more |
284 | * conservative value. | 289 | * conservative value. |
285 | */ | 290 | */ |
286 | mdelay(250); | 291 | msleep(250); |
287 | 292 | ||
288 | /* Scan all of the recorded PCI controllers. */ | 293 | /* Scan all of the recorded PCI controllers. */ |
289 | for (i = 0; i < TILE_NUM_PCIE; i++) { | 294 | for (i = 0; i < TILE_NUM_PCIE; i++) { |
@@ -304,18 +309,10 @@ int __init pcibios_init(void) | |||
304 | 309 | ||
305 | pr_info("PCI: initializing controller #%d\n", i); | 310 | pr_info("PCI: initializing controller #%d\n", i); |
306 | 311 | ||
307 | /* | ||
308 | * This comes from the generic Linux PCI driver. | ||
309 | * | ||
310 | * It reads the PCI tree for this bus into the Linux | ||
311 | * data structures. | ||
312 | * | ||
313 | * This is inlined in linux/pci.h and calls into | ||
314 | * pci_scan_bus_parented() in probe.c. | ||
315 | */ | ||
316 | pci_add_resource(&resources, &ioport_resource); | 312 | pci_add_resource(&resources, &ioport_resource); |
317 | pci_add_resource(&resources, &iomem_resource); | 313 | pci_add_resource(&resources, &iomem_resource); |
318 | bus = pci_scan_root_bus(NULL, 0, controller->ops, controller, &resources); | 314 | bus = pci_scan_root_bus(NULL, 0, controller->ops, |
315 | controller, &resources); | ||
319 | controller->root_bus = bus; | 316 | controller->root_bus = bus; |
320 | controller->last_busno = bus->busn_res.end; | 317 | controller->last_busno = bus->busn_res.end; |
321 | } | 318 | } |
@@ -388,6 +385,16 @@ void pcibios_set_master(struct pci_dev *dev) | |||
388 | /* No special bus mastering setup handling. */ | 385 | /* No special bus mastering setup handling. */ |
389 | } | 386 | } |
390 | 387 | ||
388 | /* Process any "pci=" kernel boot arguments. */ | ||
389 | char *__init pcibios_setup(char *str) | ||
390 | { | ||
391 | if (!strcmp(str, "off")) { | ||
392 | pci_probe = 0; | ||
393 | return NULL; | ||
394 | } | ||
395 | return str; | ||
396 | } | ||
397 | |||
391 | /* | 398 | /* |
392 | * Enable memory and/or address decoding, as appropriate, for the | 399 | * Enable memory and/or address decoding, as appropriate, for the |
393 | * device described by the 'dev' struct. | 400 | * device described by the 'dev' struct. |
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c index 6640e7bbeaa2..a97a6452b812 100644 --- a/arch/tile/kernel/pci_gx.c +++ b/arch/tile/kernel/pci_gx.c | |||
@@ -69,19 +69,32 @@ static int pcie_rc[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES]; | |||
69 | * a HW PCIe link-training bug. The exact delay is specified with | 69 | * a HW PCIe link-training bug. The exact delay is specified with |
70 | * a kernel boot argument in the form of "pcie_rc_delay=T,P,S", | 70 | * a kernel boot argument in the form of "pcie_rc_delay=T,P,S", |
71 | * where T is the TRIO instance number, P is the port number and S is | 71 | * where T is the TRIO instance number, P is the port number and S is |
72 | * the delay in seconds. If the delay is not provided, the value | 72 | * the delay in seconds. If the argument is specified, but the delay is |
73 | * will be DEFAULT_RC_DELAY. | 73 | * not provided, the value will be DEFAULT_RC_DELAY. |
74 | */ | 74 | */ |
75 | static int rc_delay[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES]; | 75 | static int rc_delay[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES]; |
76 | 76 | ||
77 | /* Default number of seconds that the PCIe RC port probe can be delayed. */ | 77 | /* Default number of seconds that the PCIe RC port probe can be delayed. */ |
78 | #define DEFAULT_RC_DELAY 10 | 78 | #define DEFAULT_RC_DELAY 10 |
79 | 79 | ||
80 | /* Max number of seconds that the PCIe RC port probe can be delayed. */ | 80 | /* The PCI I/O space size in each PCI domain. */ |
81 | #define MAX_RC_DELAY 20 | 81 | #define IO_SPACE_SIZE 0x10000 |
82 | |||
83 | /* Provide shorter versions of some very long constant names. */ | ||
84 | #define AUTO_CONFIG_RC \ | ||
85 | TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC | ||
86 | #define AUTO_CONFIG_RC_G1 \ | ||
87 | TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC_G1 | ||
88 | #define AUTO_CONFIG_EP \ | ||
89 | TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT | ||
90 | #define AUTO_CONFIG_EP_G1 \ | ||
91 | TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT_G1 | ||
82 | 92 | ||
83 | /* Array of the PCIe ports configuration info obtained from the BIB. */ | 93 | /* Array of the PCIe ports configuration info obtained from the BIB. */ |
84 | struct pcie_port_property pcie_ports[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES]; | 94 | struct pcie_trio_ports_property pcie_ports[TILEGX_NUM_TRIO]; |
95 | |||
96 | /* Number of configured TRIO instances. */ | ||
97 | int num_trio_shims; | ||
85 | 98 | ||
86 | /* All drivers share the TRIO contexts defined here. */ | 99 | /* All drivers share the TRIO contexts defined here. */ |
87 | gxio_trio_context_t trio_contexts[TILEGX_NUM_TRIO]; | 100 | gxio_trio_context_t trio_contexts[TILEGX_NUM_TRIO]; |
@@ -89,24 +102,21 @@ gxio_trio_context_t trio_contexts[TILEGX_NUM_TRIO]; | |||
89 | /* Pointer to an array of PCIe RC controllers. */ | 102 | /* Pointer to an array of PCIe RC controllers. */ |
90 | struct pci_controller pci_controllers[TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES]; | 103 | struct pci_controller pci_controllers[TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES]; |
91 | int num_rc_controllers; | 104 | int num_rc_controllers; |
92 | static int num_ep_controllers; | ||
93 | 105 | ||
94 | static struct pci_ops tile_cfg_ops; | 106 | static struct pci_ops tile_cfg_ops; |
95 | 107 | ||
96 | /* Mask of CPUs that should receive PCIe interrupts. */ | 108 | /* Mask of CPUs that should receive PCIe interrupts. */ |
97 | static struct cpumask intr_cpus_map; | 109 | static struct cpumask intr_cpus_map; |
98 | 110 | ||
99 | /* | 111 | /* We don't need to worry about the alignment of resources. */ |
100 | * We don't need to worry about the alignment of resources. | ||
101 | */ | ||
102 | resource_size_t pcibios_align_resource(void *data, const struct resource *res, | 112 | resource_size_t pcibios_align_resource(void *data, const struct resource *res, |
103 | resource_size_t size, resource_size_t align) | 113 | resource_size_t size, |
114 | resource_size_t align) | ||
104 | { | 115 | { |
105 | return res->start; | 116 | return res->start; |
106 | } | 117 | } |
107 | EXPORT_SYMBOL(pcibios_align_resource); | 118 | EXPORT_SYMBOL(pcibios_align_resource); |
108 | 119 | ||
109 | |||
110 | /* | 120 | /* |
111 | * Pick a CPU to receive and handle the PCIe interrupts, based on the IRQ #. | 121 | * Pick a CPU to receive and handle the PCIe interrupts, based on the IRQ #. |
112 | * For now, we simply send interrupts to non-dataplane CPUs. | 122 | * For now, we simply send interrupts to non-dataplane CPUs. |
@@ -134,24 +144,19 @@ static int tile_irq_cpu(int irq) | |||
134 | return cpu; | 144 | return cpu; |
135 | } | 145 | } |
136 | 146 | ||
137 | /* | 147 | /* Open a file descriptor to the TRIO shim. */ |
138 | * Open a file descriptor to the TRIO shim. | ||
139 | */ | ||
140 | static int tile_pcie_open(int trio_index) | 148 | static int tile_pcie_open(int trio_index) |
141 | { | 149 | { |
142 | gxio_trio_context_t *context = &trio_contexts[trio_index]; | 150 | gxio_trio_context_t *context = &trio_contexts[trio_index]; |
143 | int ret; | 151 | int ret; |
152 | int mac; | ||
144 | 153 | ||
145 | /* | 154 | /* This opens a file descriptor to the TRIO shim. */ |
146 | * This opens a file descriptor to the TRIO shim. | ||
147 | */ | ||
148 | ret = gxio_trio_init(context, trio_index); | 155 | ret = gxio_trio_init(context, trio_index); |
149 | if (ret < 0) | 156 | if (ret < 0) |
150 | return ret; | 157 | goto gxio_trio_init_failure; |
151 | 158 | ||
152 | /* | 159 | /* Allocate an ASID for the kernel. */ |
153 | * Allocate an ASID for the kernel. | ||
154 | */ | ||
155 | ret = gxio_trio_alloc_asids(context, 1, 0, 0); | 160 | ret = gxio_trio_alloc_asids(context, 1, 0, 0); |
156 | if (ret < 0) { | 161 | if (ret < 0) { |
157 | pr_err("PCI: ASID alloc failure on TRIO %d, give up\n", | 162 | pr_err("PCI: ASID alloc failure on TRIO %d, give up\n", |
@@ -189,31 +194,97 @@ static int tile_pcie_open(int trio_index) | |||
189 | } | 194 | } |
190 | #endif | 195 | #endif |
191 | 196 | ||
197 | /* Get the properties of the PCIe ports on this TRIO instance. */ | ||
198 | ret = gxio_trio_get_port_property(context, &pcie_ports[trio_index]); | ||
199 | if (ret < 0) { | ||
200 | pr_err("PCI: PCIE_GET_PORT_PROPERTY failure, error %d," | ||
201 | " on TRIO %d\n", ret, trio_index); | ||
202 | goto get_port_property_failure; | ||
203 | } | ||
204 | |||
205 | context->mmio_base_mac = | ||
206 | iorpc_ioremap(context->fd, 0, HV_TRIO_CONFIG_IOREMAP_SIZE); | ||
207 | if (context->mmio_base_mac == NULL) { | ||
208 | pr_err("PCI: TRIO config space mapping failure, error %d," | ||
209 | " on TRIO %d\n", ret, trio_index); | ||
210 | ret = -ENOMEM; | ||
211 | |||
212 | goto trio_mmio_mapping_failure; | ||
213 | } | ||
214 | |||
215 | /* Check the port strap state which will override the BIB setting. */ | ||
216 | for (mac = 0; mac < TILEGX_TRIO_PCIES; mac++) { | ||
217 | TRIO_PCIE_INTFC_PORT_CONFIG_t port_config; | ||
218 | unsigned int reg_offset; | ||
219 | |||
220 | /* Ignore ports that are not specified in the BIB. */ | ||
221 | if (!pcie_ports[trio_index].ports[mac].allow_rc && | ||
222 | !pcie_ports[trio_index].ports[mac].allow_ep) | ||
223 | continue; | ||
224 | |||
225 | reg_offset = | ||
226 | (TRIO_PCIE_INTFC_PORT_CONFIG << | ||
227 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | | ||
228 | (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE << | ||
229 | TRIO_CFG_REGION_ADDR__INTFC_SHIFT) | | ||
230 | (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); | ||
231 | |||
232 | port_config.word = | ||
233 | __gxio_mmio_read(context->mmio_base_mac + reg_offset); | ||
234 | |||
235 | if (port_config.strap_state != AUTO_CONFIG_RC && | ||
236 | port_config.strap_state != AUTO_CONFIG_RC_G1) { | ||
237 | /* | ||
238 | * If this is really intended to be an EP port, record | ||
239 | * it so that the endpoint driver will know about it. | ||
240 | */ | ||
241 | if (port_config.strap_state == AUTO_CONFIG_EP || | ||
242 | port_config.strap_state == AUTO_CONFIG_EP_G1) | ||
243 | pcie_ports[trio_index].ports[mac].allow_ep = 1; | ||
244 | } | ||
245 | } | ||
246 | |||
192 | return ret; | 247 | return ret; |
193 | 248 | ||
249 | trio_mmio_mapping_failure: | ||
250 | get_port_property_failure: | ||
194 | asid_alloc_failure: | 251 | asid_alloc_failure: |
195 | #ifdef USE_SHARED_PCIE_CONFIG_REGION | 252 | #ifdef USE_SHARED_PCIE_CONFIG_REGION |
196 | pio_alloc_failure: | 253 | pio_alloc_failure: |
197 | #endif | 254 | #endif |
198 | hv_dev_close(context->fd); | 255 | hv_dev_close(context->fd); |
256 | gxio_trio_init_failure: | ||
257 | context->fd = -1; | ||
199 | 258 | ||
200 | return ret; | 259 | return ret; |
201 | } | 260 | } |
202 | 261 | ||
203 | static void | 262 | static int __init tile_trio_init(void) |
204 | tilegx_legacy_irq_ack(struct irq_data *d) | 263 | { |
264 | int i; | ||
265 | |||
266 | /* We loop over all the TRIO shims. */ | ||
267 | for (i = 0; i < TILEGX_NUM_TRIO; i++) { | ||
268 | if (tile_pcie_open(i) < 0) | ||
269 | continue; | ||
270 | num_trio_shims++; | ||
271 | } | ||
272 | |||
273 | return 0; | ||
274 | } | ||
275 | postcore_initcall(tile_trio_init); | ||
276 | |||
277 | static void tilegx_legacy_irq_ack(struct irq_data *d) | ||
205 | { | 278 | { |
206 | __insn_mtspr(SPR_IPI_EVENT_RESET_K, 1UL << d->irq); | 279 | __insn_mtspr(SPR_IPI_EVENT_RESET_K, 1UL << d->irq); |
207 | } | 280 | } |
208 | 281 | ||
209 | static void | 282 | static void tilegx_legacy_irq_mask(struct irq_data *d) |
210 | tilegx_legacy_irq_mask(struct irq_data *d) | ||
211 | { | 283 | { |
212 | __insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq); | 284 | __insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq); |
213 | } | 285 | } |
214 | 286 | ||
215 | static void | 287 | static void tilegx_legacy_irq_unmask(struct irq_data *d) |
216 | tilegx_legacy_irq_unmask(struct irq_data *d) | ||
217 | { | 288 | { |
218 | __insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq); | 289 | __insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq); |
219 | } | 290 | } |
@@ -234,8 +305,7 @@ static struct irq_chip tilegx_legacy_irq_chip = { | |||
234 | * to Linux which just calls handle_level_irq() after clearing the | 305 | * to Linux which just calls handle_level_irq() after clearing the |
235 | * MAC INTx Assert status bit associated with this interrupt. | 306 | * MAC INTx Assert status bit associated with this interrupt. |
236 | */ | 307 | */ |
237 | static void | 308 | static void trio_handle_level_irq(unsigned int irq, struct irq_desc *desc) |
238 | trio_handle_level_irq(unsigned int irq, struct irq_desc *desc) | ||
239 | { | 309 | { |
240 | struct pci_controller *controller = irq_desc_get_handler_data(desc); | 310 | struct pci_controller *controller = irq_desc_get_handler_data(desc); |
241 | gxio_trio_context_t *trio_context = controller->trio; | 311 | gxio_trio_context_t *trio_context = controller->trio; |
@@ -301,9 +371,7 @@ static int tile_init_irqs(struct pci_controller *controller) | |||
301 | goto free_irqs; | 371 | goto free_irqs; |
302 | } | 372 | } |
303 | 373 | ||
304 | /* | 374 | /* Register the IRQ handler with the kernel. */ |
305 | * Register the IRQ handler with the kernel. | ||
306 | */ | ||
307 | irq_set_chip_and_handler(irq, &tilegx_legacy_irq_chip, | 375 | irq_set_chip_and_handler(irq, &tilegx_legacy_irq_chip, |
308 | trio_handle_level_irq); | 376 | trio_handle_level_irq); |
309 | irq_set_chip_data(irq, (void *)(uint64_t)i); | 377 | irq_set_chip_data(irq, (void *)(uint64_t)i); |
@@ -320,14 +388,39 @@ free_irqs: | |||
320 | } | 388 | } |
321 | 389 | ||
322 | /* | 390 | /* |
391 | * Return 1 if the port is strapped to operate in RC mode. | ||
392 | */ | ||
393 | static int | ||
394 | strapped_for_rc(gxio_trio_context_t *trio_context, int mac) | ||
395 | { | ||
396 | TRIO_PCIE_INTFC_PORT_CONFIG_t port_config; | ||
397 | unsigned int reg_offset; | ||
398 | |||
399 | /* Check the port configuration. */ | ||
400 | reg_offset = | ||
401 | (TRIO_PCIE_INTFC_PORT_CONFIG << | ||
402 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | | ||
403 | (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE << | ||
404 | TRIO_CFG_REGION_ADDR__INTFC_SHIFT) | | ||
405 | (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); | ||
406 | port_config.word = | ||
407 | __gxio_mmio_read(trio_context->mmio_base_mac + reg_offset); | ||
408 | |||
409 | if (port_config.strap_state == AUTO_CONFIG_RC || | ||
410 | port_config.strap_state == AUTO_CONFIG_RC_G1) | ||
411 | return 1; | ||
412 | else | ||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | /* | ||
323 | * Find valid controllers and fill in pci_controller structs for each | 417 | * Find valid controllers and fill in pci_controller structs for each |
324 | * of them. | 418 | * of them. |
325 | * | 419 | * |
326 | * Returns the number of controllers discovered. | 420 | * Return the number of controllers discovered. |
327 | */ | 421 | */ |
328 | int __init tile_pci_init(void) | 422 | int __init tile_pci_init(void) |
329 | { | 423 | { |
330 | int num_trio_shims = 0; | ||
331 | int ctl_index = 0; | 424 | int ctl_index = 0; |
332 | int i, j; | 425 | int i, j; |
333 | 426 | ||
@@ -338,64 +431,62 @@ int __init tile_pci_init(void) | |||
338 | 431 | ||
339 | pr_info("PCI: Searching for controllers...\n"); | 432 | pr_info("PCI: Searching for controllers...\n"); |
340 | 433 | ||
341 | /* | ||
342 | * We loop over all the TRIO shims. | ||
343 | */ | ||
344 | for (i = 0; i < TILEGX_NUM_TRIO; i++) { | ||
345 | int ret; | ||
346 | |||
347 | ret = tile_pcie_open(i); | ||
348 | if (ret < 0) | ||
349 | continue; | ||
350 | |||
351 | num_trio_shims++; | ||
352 | } | ||
353 | |||
354 | if (num_trio_shims == 0 || sim_is_simulator()) | 434 | if (num_trio_shims == 0 || sim_is_simulator()) |
355 | return 0; | 435 | return 0; |
356 | 436 | ||
357 | /* | 437 | /* |
358 | * Now determine which PCIe ports are configured to operate in RC mode. | 438 | * Now determine which PCIe ports are configured to operate in RC |
359 | * We look at the Board Information Block first and then see if there | 439 | * mode. There is a differece in the port configuration capability |
360 | * are any overriding configuration by the HW strapping pin. | 440 | * between the Gx36 and Gx72 devices. |
441 | * | ||
442 | * The Gx36 has configuration capability for each of the 3 PCIe | ||
443 | * interfaces (disable, auto endpoint, auto RC, etc.). | ||
444 | * On the Gx72, you can only select one of the 3 PCIe interfaces per | ||
445 | * TRIO to train automatically. Further, the allowable training modes | ||
446 | * are reduced to four options (auto endpoint, auto RC, stream x1, | ||
447 | * stream x4). | ||
448 | * | ||
449 | * For Gx36 ports, it must be allowed to be in RC mode by the | ||
450 | * Board Information Block, and the hardware strapping pins must be | ||
451 | * set to RC mode. | ||
452 | * | ||
453 | * For Gx72 ports, the port will operate in RC mode if either of the | ||
454 | * following is true: | ||
455 | * 1. It is allowed to be in RC mode by the Board Information Block, | ||
456 | * and the BIB doesn't allow the EP mode. | ||
457 | * 2. It is allowed to be in either the RC or the EP mode by the BIB, | ||
458 | * and the hardware strapping pin is set to RC mode. | ||
361 | */ | 459 | */ |
362 | for (i = 0; i < TILEGX_NUM_TRIO; i++) { | 460 | for (i = 0; i < TILEGX_NUM_TRIO; i++) { |
363 | gxio_trio_context_t *context = &trio_contexts[i]; | 461 | gxio_trio_context_t *context = &trio_contexts[i]; |
364 | int ret; | ||
365 | 462 | ||
366 | if (context->fd < 0) | 463 | if (context->fd < 0) |
367 | continue; | 464 | continue; |
368 | 465 | ||
369 | ret = hv_dev_pread(context->fd, 0, | ||
370 | (HV_VirtAddr)&pcie_ports[i][0], | ||
371 | sizeof(struct pcie_port_property) * TILEGX_TRIO_PCIES, | ||
372 | GXIO_TRIO_OP_GET_PORT_PROPERTY); | ||
373 | if (ret < 0) { | ||
374 | pr_err("PCI: PCIE_GET_PORT_PROPERTY failure, error %d," | ||
375 | " on TRIO %d\n", ret, i); | ||
376 | continue; | ||
377 | } | ||
378 | |||
379 | for (j = 0; j < TILEGX_TRIO_PCIES; j++) { | 466 | for (j = 0; j < TILEGX_TRIO_PCIES; j++) { |
380 | if (pcie_ports[i][j].allow_rc) { | 467 | int is_rc = 0; |
468 | |||
469 | if (pcie_ports[i].is_gx72 && | ||
470 | pcie_ports[i].ports[j].allow_rc) { | ||
471 | if (!pcie_ports[i].ports[j].allow_ep || | ||
472 | strapped_for_rc(context, j)) | ||
473 | is_rc = 1; | ||
474 | } else if (pcie_ports[i].ports[j].allow_rc && | ||
475 | strapped_for_rc(context, j)) { | ||
476 | is_rc = 1; | ||
477 | } | ||
478 | if (is_rc) { | ||
381 | pcie_rc[i][j] = 1; | 479 | pcie_rc[i][j] = 1; |
382 | num_rc_controllers++; | 480 | num_rc_controllers++; |
383 | } | 481 | } |
384 | else if (pcie_ports[i][j].allow_ep) { | ||
385 | num_ep_controllers++; | ||
386 | } | ||
387 | } | 482 | } |
388 | } | 483 | } |
389 | 484 | ||
390 | /* | 485 | /* Return if no PCIe ports are configured to operate in RC mode. */ |
391 | * Return if no PCIe ports are configured to operate in RC mode. | ||
392 | */ | ||
393 | if (num_rc_controllers == 0) | 486 | if (num_rc_controllers == 0) |
394 | return 0; | 487 | return 0; |
395 | 488 | ||
396 | /* | 489 | /* Set the TRIO pointer and MAC index for each PCIe RC port. */ |
397 | * Set the TRIO pointer and MAC index for each PCIe RC port. | ||
398 | */ | ||
399 | for (i = 0; i < TILEGX_NUM_TRIO; i++) { | 490 | for (i = 0; i < TILEGX_NUM_TRIO; i++) { |
400 | for (j = 0; j < TILEGX_TRIO_PCIES; j++) { | 491 | for (j = 0; j < TILEGX_TRIO_PCIES; j++) { |
401 | if (pcie_rc[i][j]) { | 492 | if (pcie_rc[i][j]) { |
@@ -411,26 +502,32 @@ int __init tile_pci_init(void) | |||
411 | } | 502 | } |
412 | 503 | ||
413 | out: | 504 | out: |
414 | /* | 505 | /* Configure each PCIe RC port. */ |
415 | * Configure each PCIe RC port. | ||
416 | */ | ||
417 | for (i = 0; i < num_rc_controllers; i++) { | 506 | for (i = 0; i < num_rc_controllers; i++) { |
418 | /* | ||
419 | * Configure the PCIe MAC to run in RC mode. | ||
420 | */ | ||
421 | 507 | ||
508 | /* Configure the PCIe MAC to run in RC mode. */ | ||
422 | struct pci_controller *controller = &pci_controllers[i]; | 509 | struct pci_controller *controller = &pci_controllers[i]; |
423 | 510 | ||
424 | controller->index = i; | 511 | controller->index = i; |
425 | controller->ops = &tile_cfg_ops; | 512 | controller->ops = &tile_cfg_ops; |
426 | 513 | ||
514 | controller->io_space.start = PCIBIOS_MIN_IO + | ||
515 | (i * IO_SPACE_SIZE); | ||
516 | controller->io_space.end = controller->io_space.start + | ||
517 | IO_SPACE_SIZE - 1; | ||
518 | BUG_ON(controller->io_space.end > IO_SPACE_LIMIT); | ||
519 | controller->io_space.flags = IORESOURCE_IO; | ||
520 | snprintf(controller->io_space_name, | ||
521 | sizeof(controller->io_space_name), | ||
522 | "PCI I/O domain %d", i); | ||
523 | controller->io_space.name = controller->io_space_name; | ||
524 | |||
427 | /* | 525 | /* |
428 | * The PCI memory resource is located above the PA space. | 526 | * The PCI memory resource is located above the PA space. |
429 | * For every host bridge, the BAR window or the MMIO aperture | 527 | * For every host bridge, the BAR window or the MMIO aperture |
430 | * is in range [3GB, 4GB - 1] of a 4GB space beyond the | 528 | * is in range [3GB, 4GB - 1] of a 4GB space beyond the |
431 | * PA space. | 529 | * PA space. |
432 | */ | 530 | */ |
433 | |||
434 | controller->mem_offset = TILE_PCI_MEM_START + | 531 | controller->mem_offset = TILE_PCI_MEM_START + |
435 | (i * TILE_PCI_BAR_WINDOW_TOP); | 532 | (i * TILE_PCI_BAR_WINDOW_TOP); |
436 | controller->mem_space.start = controller->mem_offset + | 533 | controller->mem_space.start = controller->mem_offset + |
@@ -458,7 +555,6 @@ static int tile_map_irq(const struct pci_dev *dev, u8 device, u8 pin) | |||
458 | return controller->irq_intx_table[pin - 1]; | 555 | return controller->irq_intx_table[pin - 1]; |
459 | } | 556 | } |
460 | 557 | ||
461 | |||
462 | static void fixup_read_and_payload_sizes(struct pci_controller *controller) | 558 | static void fixup_read_and_payload_sizes(struct pci_controller *controller) |
463 | { | 559 | { |
464 | gxio_trio_context_t *trio_context = controller->trio; | 560 | gxio_trio_context_t *trio_context = controller->trio; |
@@ -472,9 +568,7 @@ static void fixup_read_and_payload_sizes(struct pci_controller *controller) | |||
472 | 568 | ||
473 | mac = controller->mac; | 569 | mac = controller->mac; |
474 | 570 | ||
475 | /* | 571 | /* Set our max read request size to be 4KB. */ |
476 | * Set our max read request size to be 4KB. | ||
477 | */ | ||
478 | reg_offset = | 572 | reg_offset = |
479 | (TRIO_PCIE_RC_DEVICE_CONTROL << | 573 | (TRIO_PCIE_RC_DEVICE_CONTROL << |
480 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | | 574 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | |
@@ -483,10 +577,10 @@ static void fixup_read_and_payload_sizes(struct pci_controller *controller) | |||
483 | (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); | 577 | (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); |
484 | 578 | ||
485 | dev_control.word = __gxio_mmio_read32(trio_context->mmio_base_mac + | 579 | dev_control.word = __gxio_mmio_read32(trio_context->mmio_base_mac + |
486 | reg_offset); | 580 | reg_offset); |
487 | dev_control.max_read_req_sz = 5; | 581 | dev_control.max_read_req_sz = 5; |
488 | __gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset, | 582 | __gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset, |
489 | dev_control.word); | 583 | dev_control.word); |
490 | 584 | ||
491 | /* | 585 | /* |
492 | * Set the max payload size supported by this Gx PCIe MAC. | 586 | * Set the max payload size supported by this Gx PCIe MAC. |
@@ -502,10 +596,10 @@ static void fixup_read_and_payload_sizes(struct pci_controller *controller) | |||
502 | (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); | 596 | (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); |
503 | 597 | ||
504 | rc_dev_cap.word = __gxio_mmio_read32(trio_context->mmio_base_mac + | 598 | rc_dev_cap.word = __gxio_mmio_read32(trio_context->mmio_base_mac + |
505 | reg_offset); | 599 | reg_offset); |
506 | rc_dev_cap.mps_sup = 1; | 600 | rc_dev_cap.mps_sup = 1; |
507 | __gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset, | 601 | __gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset, |
508 | rc_dev_cap.word); | 602 | rc_dev_cap.word); |
509 | 603 | ||
510 | /* Configure PCI Express MPS setting. */ | 604 | /* Configure PCI Express MPS setting. */ |
511 | list_for_each_entry(child, &root_bus->children, node) | 605 | list_for_each_entry(child, &root_bus->children, node) |
@@ -528,7 +622,7 @@ static void fixup_read_and_payload_sizes(struct pci_controller *controller) | |||
528 | dev_control.max_payload_size, | 622 | dev_control.max_payload_size, |
529 | dev_control.max_read_req_sz, | 623 | dev_control.max_read_req_sz, |
530 | mac); | 624 | mac); |
531 | if (err < 0) { | 625 | if (err < 0) { |
532 | pr_err("PCI: PCIE_CONFIGURE_MAC_MPS_MRS failure, " | 626 | pr_err("PCI: PCIE_CONFIGURE_MAC_MPS_MRS failure, " |
533 | "MAC %d on TRIO %d\n", | 627 | "MAC %d on TRIO %d\n", |
534 | mac, controller->trio_index); | 628 | mac, controller->trio_index); |
@@ -565,21 +659,14 @@ static int setup_pcie_rc_delay(char *str) | |||
565 | if (!isdigit(*str)) | 659 | if (!isdigit(*str)) |
566 | return -EINVAL; | 660 | return -EINVAL; |
567 | delay = simple_strtoul(str, (char **)&str, 10); | 661 | delay = simple_strtoul(str, (char **)&str, 10); |
568 | if (delay > MAX_RC_DELAY) | ||
569 | return -EINVAL; | ||
570 | } | 662 | } |
571 | 663 | ||
572 | rc_delay[trio_index][mac] = delay ? : DEFAULT_RC_DELAY; | 664 | rc_delay[trio_index][mac] = delay ? : DEFAULT_RC_DELAY; |
573 | pr_info("Delaying PCIe RC link training for %u sec" | ||
574 | " on MAC %lu on TRIO %lu\n", rc_delay[trio_index][mac], | ||
575 | mac, trio_index); | ||
576 | return 0; | 665 | return 0; |
577 | } | 666 | } |
578 | early_param("pcie_rc_delay", setup_pcie_rc_delay); | 667 | early_param("pcie_rc_delay", setup_pcie_rc_delay); |
579 | 668 | ||
580 | /* | 669 | /* PCI initialization entry point, called by subsys_initcall. */ |
581 | * PCI initialization entry point, called by subsys_initcall. | ||
582 | */ | ||
583 | int __init pcibios_init(void) | 670 | int __init pcibios_init(void) |
584 | { | 671 | { |
585 | resource_size_t offset; | 672 | resource_size_t offset; |
@@ -589,35 +676,10 @@ int __init pcibios_init(void) | |||
589 | 676 | ||
590 | tile_pci_init(); | 677 | tile_pci_init(); |
591 | 678 | ||
592 | if (num_rc_controllers == 0 && num_ep_controllers == 0) | 679 | if (num_rc_controllers == 0) |
593 | return 0; | 680 | return 0; |
594 | 681 | ||
595 | /* | 682 | /* |
596 | * We loop over all the TRIO shims and set up the MMIO mappings. | ||
597 | */ | ||
598 | for (i = 0; i < TILEGX_NUM_TRIO; i++) { | ||
599 | gxio_trio_context_t *context = &trio_contexts[i]; | ||
600 | |||
601 | if (context->fd < 0) | ||
602 | continue; | ||
603 | |||
604 | /* | ||
605 | * Map in the MMIO space for the MAC. | ||
606 | */ | ||
607 | offset = 0; | ||
608 | context->mmio_base_mac = | ||
609 | iorpc_ioremap(context->fd, offset, | ||
610 | HV_TRIO_CONFIG_IOREMAP_SIZE); | ||
611 | if (context->mmio_base_mac == NULL) { | ||
612 | pr_err("PCI: MAC map failure on TRIO %d\n", i); | ||
613 | |||
614 | hv_dev_close(context->fd); | ||
615 | context->fd = -1; | ||
616 | continue; | ||
617 | } | ||
618 | } | ||
619 | |||
620 | /* | ||
621 | * Delay a bit in case devices aren't ready. Some devices are | 683 | * Delay a bit in case devices aren't ready. Some devices are |
622 | * known to require at least 20ms here, but we use a more | 684 | * known to require at least 20ms here, but we use a more |
623 | * conservative value. | 685 | * conservative value. |
@@ -628,7 +690,6 @@ int __init pcibios_init(void) | |||
628 | for (next_busno = 0, i = 0; i < num_rc_controllers; i++) { | 690 | for (next_busno = 0, i = 0; i < num_rc_controllers; i++) { |
629 | struct pci_controller *controller = &pci_controllers[i]; | 691 | struct pci_controller *controller = &pci_controllers[i]; |
630 | gxio_trio_context_t *trio_context = controller->trio; | 692 | gxio_trio_context_t *trio_context = controller->trio; |
631 | TRIO_PCIE_INTFC_PORT_CONFIG_t port_config; | ||
632 | TRIO_PCIE_INTFC_PORT_STATUS_t port_status; | 693 | TRIO_PCIE_INTFC_PORT_STATUS_t port_status; |
633 | TRIO_PCIE_INTFC_TX_FIFO_CTL_t tx_fifo_ctl; | 694 | TRIO_PCIE_INTFC_TX_FIFO_CTL_t tx_fifo_ctl; |
634 | struct pci_bus *bus; | 695 | struct pci_bus *bus; |
@@ -645,75 +706,64 @@ int __init pcibios_init(void) | |||
645 | mac = controller->mac; | 706 | mac = controller->mac; |
646 | 707 | ||
647 | /* | 708 | /* |
648 | * Check the port strap state which will override the BIB | 709 | * Check for PCIe link-up status to decide if we need |
649 | * setting. | 710 | * to force the link to come up. |
650 | */ | 711 | */ |
651 | |||
652 | reg_offset = | 712 | reg_offset = |
653 | (TRIO_PCIE_INTFC_PORT_CONFIG << | 713 | (TRIO_PCIE_INTFC_PORT_STATUS << |
654 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | | 714 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | |
655 | (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE << | 715 | (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE << |
656 | TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | | 716 | TRIO_CFG_REGION_ADDR__INTFC_SHIFT) | |
657 | (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); | 717 | (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); |
658 | 718 | ||
659 | port_config.word = | 719 | port_status.word = |
660 | __gxio_mmio_read(trio_context->mmio_base_mac + | 720 | __gxio_mmio_read(trio_context->mmio_base_mac + |
661 | reg_offset); | 721 | reg_offset); |
662 | 722 | if (!port_status.dl_up) { | |
663 | if ((port_config.strap_state != | 723 | if (rc_delay[trio_index][mac]) { |
664 | TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC) && | 724 | pr_info("Delaying PCIe RC TRIO init %d sec" |
665 | (port_config.strap_state != | 725 | " on MAC %d on TRIO %d\n", |
666 | TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC_G1)) { | 726 | rc_delay[trio_index][mac], mac, |
667 | /* | 727 | trio_index); |
668 | * If this is really intended to be an EP port, | 728 | msleep(rc_delay[trio_index][mac] * 1000); |
669 | * record it so that the endpoint driver will know about it. | 729 | } |
670 | */ | 730 | ret = gxio_trio_force_rc_link_up(trio_context, mac); |
671 | if (port_config.strap_state == | 731 | if (ret < 0) |
672 | TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT || | 732 | pr_err("PCI: PCIE_FORCE_LINK_UP failure, " |
673 | port_config.strap_state == | 733 | "MAC %d on TRIO %d\n", mac, trio_index); |
674 | TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT_G1) | ||
675 | pcie_ports[trio_index][mac].allow_ep = 1; | ||
676 | |||
677 | continue; | ||
678 | } | 734 | } |
679 | 735 | ||
680 | /* | ||
681 | * Delay the RC link training if needed. | ||
682 | */ | ||
683 | if (rc_delay[trio_index][mac]) | ||
684 | msleep(rc_delay[trio_index][mac] * 1000); | ||
685 | |||
686 | ret = gxio_trio_force_rc_link_up(trio_context, mac); | ||
687 | if (ret < 0) | ||
688 | pr_err("PCI: PCIE_FORCE_LINK_UP failure, " | ||
689 | "MAC %d on TRIO %d\n", mac, trio_index); | ||
690 | |||
691 | pr_info("PCI: Found PCI controller #%d on TRIO %d MAC %d\n", i, | 736 | pr_info("PCI: Found PCI controller #%d on TRIO %d MAC %d\n", i, |
692 | trio_index, controller->mac); | 737 | trio_index, controller->mac); |
693 | 738 | ||
694 | /* | 739 | /* Delay the bus probe if needed. */ |
695 | * Wait a bit here because some EP devices take longer | 740 | if (rc_delay[trio_index][mac]) { |
696 | * to come up. | 741 | pr_info("Delaying PCIe RC bus enumerating %d sec" |
697 | */ | 742 | " on MAC %d on TRIO %d\n", |
698 | msleep(1000); | 743 | rc_delay[trio_index][mac], mac, |
699 | 744 | trio_index); | |
700 | /* | 745 | msleep(rc_delay[trio_index][mac] * 1000); |
701 | * Check for PCIe link-up status. | 746 | } else { |
702 | */ | 747 | /* |
703 | 748 | * Wait a bit here because some EP devices | |
704 | reg_offset = | 749 | * take longer to come up. |
705 | (TRIO_PCIE_INTFC_PORT_STATUS << | 750 | */ |
706 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | | 751 | msleep(1000); |
707 | (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE << | 752 | } |
708 | TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | | ||
709 | (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); | ||
710 | 753 | ||
754 | /* Check for PCIe link-up status again. */ | ||
711 | port_status.word = | 755 | port_status.word = |
712 | __gxio_mmio_read(trio_context->mmio_base_mac + | 756 | __gxio_mmio_read(trio_context->mmio_base_mac + |
713 | reg_offset); | 757 | reg_offset); |
714 | if (!port_status.dl_up) { | 758 | if (!port_status.dl_up) { |
715 | pr_err("PCI: link is down, MAC %d on TRIO %d\n", | 759 | if (pcie_ports[trio_index].ports[mac].removable) { |
716 | mac, trio_index); | 760 | pr_info("PCI: link is down, MAC %d on TRIO %d\n", |
761 | mac, trio_index); | ||
762 | pr_info("This is expected if no PCIe card" | ||
763 | " is connected to this link\n"); | ||
764 | } else | ||
765 | pr_err("PCI: link is down, MAC %d on TRIO %d\n", | ||
766 | mac, trio_index); | ||
717 | continue; | 767 | continue; |
718 | } | 768 | } |
719 | 769 | ||
@@ -739,7 +789,6 @@ int __init pcibios_init(void) | |||
739 | * Change the device ID so that Linux bus crawl doesn't confuse | 789 | * Change the device ID so that Linux bus crawl doesn't confuse |
740 | * the internal bridge with any Tilera endpoints. | 790 | * the internal bridge with any Tilera endpoints. |
741 | */ | 791 | */ |
742 | |||
743 | reg_offset = | 792 | reg_offset = |
744 | (TRIO_PCIE_RC_DEVICE_ID_VEN_ID << | 793 | (TRIO_PCIE_RC_DEVICE_ID_VEN_ID << |
745 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | | 794 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | |
@@ -752,10 +801,7 @@ int __init pcibios_init(void) | |||
752 | TRIO_PCIE_RC_DEVICE_ID_VEN_ID__DEV_ID_SHIFT) | | 801 | TRIO_PCIE_RC_DEVICE_ID_VEN_ID__DEV_ID_SHIFT) | |
753 | TILERA_VENDOR_ID); | 802 | TILERA_VENDOR_ID); |
754 | 803 | ||
755 | /* | 804 | /* Set the internal P2P bridge class code. */ |
756 | * Set the internal P2P bridge class code. | ||
757 | */ | ||
758 | |||
759 | reg_offset = | 805 | reg_offset = |
760 | (TRIO_PCIE_RC_REVISION_ID << | 806 | (TRIO_PCIE_RC_REVISION_ID << |
761 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | | 807 | TRIO_CFG_REGION_ADDR__REG_SHIFT) | |
@@ -766,26 +812,22 @@ int __init pcibios_init(void) | |||
766 | class_code_revision = | 812 | class_code_revision = |
767 | __gxio_mmio_read32(trio_context->mmio_base_mac + | 813 | __gxio_mmio_read32(trio_context->mmio_base_mac + |
768 | reg_offset); | 814 | reg_offset); |
769 | class_code_revision = (class_code_revision & 0xff ) | | 815 | class_code_revision = (class_code_revision & 0xff) | |
770 | (PCI_CLASS_BRIDGE_PCI << 16); | 816 | (PCI_CLASS_BRIDGE_PCI << 16); |
771 | 817 | ||
772 | __gxio_mmio_write32(trio_context->mmio_base_mac + | 818 | __gxio_mmio_write32(trio_context->mmio_base_mac + |
773 | reg_offset, class_code_revision); | 819 | reg_offset, class_code_revision); |
774 | 820 | ||
775 | #ifdef USE_SHARED_PCIE_CONFIG_REGION | 821 | #ifdef USE_SHARED_PCIE_CONFIG_REGION |
776 | 822 | ||
777 | /* | 823 | /* Map in the MMIO space for the PIO region. */ |
778 | * Map in the MMIO space for the PIO region. | ||
779 | */ | ||
780 | offset = HV_TRIO_PIO_OFFSET(trio_context->pio_cfg_index) | | 824 | offset = HV_TRIO_PIO_OFFSET(trio_context->pio_cfg_index) | |
781 | (((unsigned long long)mac) << | 825 | (((unsigned long long)mac) << |
782 | TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT); | 826 | TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT); |
783 | 827 | ||
784 | #else | 828 | #else |
785 | 829 | ||
786 | /* | 830 | /* Alloc a PIO region for PCI config access per MAC. */ |
787 | * Alloc a PIO region for PCI config access per MAC. | ||
788 | */ | ||
789 | ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0); | 831 | ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0); |
790 | if (ret < 0) { | 832 | if (ret < 0) { |
791 | pr_err("PCI: PCI CFG PIO alloc failure for mac %d " | 833 | pr_err("PCI: PCI CFG PIO alloc failure for mac %d " |
@@ -796,9 +838,7 @@ int __init pcibios_init(void) | |||
796 | 838 | ||
797 | trio_context->pio_cfg_index[mac] = ret; | 839 | trio_context->pio_cfg_index[mac] = ret; |
798 | 840 | ||
799 | /* | 841 | /* For PIO CFG, the bus_address_hi parameter is 0. */ |
800 | * For PIO CFG, the bus_address_hi parameter is 0. | ||
801 | */ | ||
802 | ret = gxio_trio_init_pio_region_aux(trio_context, | 842 | ret = gxio_trio_init_pio_region_aux(trio_context, |
803 | trio_context->pio_cfg_index[mac], | 843 | trio_context->pio_cfg_index[mac], |
804 | mac, 0, HV_TRIO_PIO_FLAG_CONFIG_SPACE); | 844 | mac, 0, HV_TRIO_PIO_FLAG_CONFIG_SPACE); |
@@ -815,9 +855,15 @@ int __init pcibios_init(void) | |||
815 | 855 | ||
816 | #endif | 856 | #endif |
817 | 857 | ||
858 | /* | ||
859 | * To save VMALLOC space, we take advantage of the fact that | ||
860 | * bit 29 in the PIO CFG address format is reserved 0. With | ||
861 | * TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT being 30, | ||
862 | * this cuts VMALLOC space usage from 1GB to 512MB per mac. | ||
863 | */ | ||
818 | trio_context->mmio_base_pio_cfg[mac] = | 864 | trio_context->mmio_base_pio_cfg[mac] = |
819 | iorpc_ioremap(trio_context->fd, offset, | 865 | iorpc_ioremap(trio_context->fd, offset, (1UL << |
820 | (1 << TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT)); | 866 | (TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT - 1))); |
821 | if (trio_context->mmio_base_pio_cfg[mac] == NULL) { | 867 | if (trio_context->mmio_base_pio_cfg[mac] == NULL) { |
822 | pr_err("PCI: PIO map failure for mac %d on TRIO %d\n", | 868 | pr_err("PCI: PIO map failure for mac %d on TRIO %d\n", |
823 | mac, trio_index); | 869 | mac, trio_index); |
@@ -825,9 +871,7 @@ int __init pcibios_init(void) | |||
825 | continue; | 871 | continue; |
826 | } | 872 | } |
827 | 873 | ||
828 | /* | 874 | /* Initialize the PCIe interrupts. */ |
829 | * Initialize the PCIe interrupts. | ||
830 | */ | ||
831 | if (tile_init_irqs(controller)) { | 875 | if (tile_init_irqs(controller)) { |
832 | pr_err("PCI: IRQs init failure for mac %d on TRIO %d\n", | 876 | pr_err("PCI: IRQs init failure for mac %d on TRIO %d\n", |
833 | mac, trio_index); | 877 | mac, trio_index); |
@@ -838,17 +882,16 @@ int __init pcibios_init(void) | |||
838 | /* | 882 | /* |
839 | * The PCI memory resource is located above the PA space. | 883 | * The PCI memory resource is located above the PA space. |
840 | * The memory range for the PCI root bus should not overlap | 884 | * The memory range for the PCI root bus should not overlap |
841 | * with the physical RAM | 885 | * with the physical RAM. |
842 | */ | 886 | */ |
843 | pci_add_resource_offset(&resources, &controller->mem_space, | 887 | pci_add_resource_offset(&resources, &controller->mem_space, |
844 | controller->mem_offset); | 888 | controller->mem_offset); |
845 | 889 | pci_add_resource(&resources, &controller->io_space); | |
846 | controller->first_busno = next_busno; | 890 | controller->first_busno = next_busno; |
847 | bus = pci_scan_root_bus(NULL, next_busno, controller->ops, | 891 | bus = pci_scan_root_bus(NULL, next_busno, controller->ops, |
848 | controller, &resources); | 892 | controller, &resources); |
849 | controller->root_bus = bus; | 893 | controller->root_bus = bus; |
850 | next_busno = bus->busn_res.end + 1; | 894 | next_busno = bus->busn_res.end + 1; |
851 | |||
852 | } | 895 | } |
853 | 896 | ||
854 | /* Do machine dependent PCI interrupt routing */ | 897 | /* Do machine dependent PCI interrupt routing */ |
@@ -860,7 +903,6 @@ int __init pcibios_init(void) | |||
860 | * It allocates all of the resources (I/O memory, etc) | 903 | * It allocates all of the resources (I/O memory, etc) |
861 | * associated with the devices read in above. | 904 | * associated with the devices read in above. |
862 | */ | 905 | */ |
863 | |||
864 | pci_assign_unassigned_resources(); | 906 | pci_assign_unassigned_resources(); |
865 | 907 | ||
866 | /* Record the I/O resources in the PCI controller structure. */ | 908 | /* Record the I/O resources in the PCI controller structure. */ |
@@ -868,9 +910,6 @@ int __init pcibios_init(void) | |||
868 | struct pci_controller *controller = &pci_controllers[i]; | 910 | struct pci_controller *controller = &pci_controllers[i]; |
869 | gxio_trio_context_t *trio_context = controller->trio; | 911 | gxio_trio_context_t *trio_context = controller->trio; |
870 | struct pci_bus *root_bus = pci_controllers[i].root_bus; | 912 | struct pci_bus *root_bus = pci_controllers[i].root_bus; |
871 | struct pci_bus *next_bus; | ||
872 | uint32_t bus_address_hi; | ||
873 | struct pci_dev *dev; | ||
874 | int ret; | 913 | int ret; |
875 | int j; | 914 | int j; |
876 | 915 | ||
@@ -884,43 +923,12 @@ int __init pcibios_init(void) | |||
884 | /* Configure the max_payload_size values for this domain. */ | 923 | /* Configure the max_payload_size values for this domain. */ |
885 | fixup_read_and_payload_sizes(controller); | 924 | fixup_read_and_payload_sizes(controller); |
886 | 925 | ||
887 | list_for_each_entry(dev, &root_bus->devices, bus_list) { | 926 | /* Alloc a PIO region for PCI memory access for each RC port. */ |
888 | /* Find the PCI host controller, ie. the 1st bridge. */ | ||
889 | if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && | ||
890 | (PCI_SLOT(dev->devfn) == 0)) { | ||
891 | next_bus = dev->subordinate; | ||
892 | pci_controllers[i].mem_resources[0] = | ||
893 | *next_bus->resource[0]; | ||
894 | pci_controllers[i].mem_resources[1] = | ||
895 | *next_bus->resource[1]; | ||
896 | pci_controllers[i].mem_resources[2] = | ||
897 | *next_bus->resource[2]; | ||
898 | |||
899 | break; | ||
900 | } | ||
901 | } | ||
902 | |||
903 | if (pci_controllers[i].mem_resources[1].flags & IORESOURCE_MEM) | ||
904 | bus_address_hi = | ||
905 | pci_controllers[i].mem_resources[1].start >> 32; | ||
906 | else if (pci_controllers[i].mem_resources[2].flags & IORESOURCE_PREFETCH) | ||
907 | bus_address_hi = | ||
908 | pci_controllers[i].mem_resources[2].start >> 32; | ||
909 | else { | ||
910 | /* This is unlikely. */ | ||
911 | pr_err("PCI: no memory resources on TRIO %d mac %d\n", | ||
912 | controller->trio_index, controller->mac); | ||
913 | continue; | ||
914 | } | ||
915 | |||
916 | /* | ||
917 | * Alloc a PIO region for PCI memory access for each RC port. | ||
918 | */ | ||
919 | ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0); | 927 | ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0); |
920 | if (ret < 0) { | 928 | if (ret < 0) { |
921 | pr_err("PCI: MEM PIO alloc failure on TRIO %d mac %d, " | 929 | pr_err("PCI: MEM PIO alloc failure on TRIO %d mac %d, " |
922 | "give up\n", controller->trio_index, | 930 | "give up\n", controller->trio_index, |
923 | controller->mac); | 931 | controller->mac); |
924 | 932 | ||
925 | continue; | 933 | continue; |
926 | } | 934 | } |
@@ -938,12 +946,45 @@ int __init pcibios_init(void) | |||
938 | 0); | 946 | 0); |
939 | if (ret < 0) { | 947 | if (ret < 0) { |
940 | pr_err("PCI: MEM PIO init failure on TRIO %d mac %d, " | 948 | pr_err("PCI: MEM PIO init failure on TRIO %d mac %d, " |
941 | "give up\n", controller->trio_index, | 949 | "give up\n", controller->trio_index, |
942 | controller->mac); | 950 | controller->mac); |
943 | 951 | ||
944 | continue; | 952 | continue; |
945 | } | 953 | } |
946 | 954 | ||
955 | #ifdef CONFIG_TILE_PCI_IO | ||
956 | /* | ||
957 | * Alloc a PIO region for PCI I/O space access for each RC port. | ||
958 | */ | ||
959 | ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0); | ||
960 | if (ret < 0) { | ||
961 | pr_err("PCI: I/O PIO alloc failure on TRIO %d mac %d, " | ||
962 | "give up\n", controller->trio_index, | ||
963 | controller->mac); | ||
964 | |||
965 | continue; | ||
966 | } | ||
967 | |||
968 | controller->pio_io_index = ret; | ||
969 | |||
970 | /* | ||
971 | * For PIO IO, the bus_address_hi parameter is hard-coded 0 | ||
972 | * because PCI I/O address space is 32-bit. | ||
973 | */ | ||
974 | ret = gxio_trio_init_pio_region_aux(trio_context, | ||
975 | controller->pio_io_index, | ||
976 | controller->mac, | ||
977 | 0, | ||
978 | HV_TRIO_PIO_FLAG_IO_SPACE); | ||
979 | if (ret < 0) { | ||
980 | pr_err("PCI: I/O PIO init failure on TRIO %d mac %d, " | ||
981 | "give up\n", controller->trio_index, | ||
982 | controller->mac); | ||
983 | |||
984 | continue; | ||
985 | } | ||
986 | #endif | ||
987 | |||
947 | /* | 988 | /* |
948 | * Configure a Mem-Map region for each memory controller so | 989 | * Configure a Mem-Map region for each memory controller so |
949 | * that Linux can map all of its PA space to the PCI bus. | 990 | * that Linux can map all of its PA space to the PCI bus. |
@@ -958,9 +999,9 @@ int __init pcibios_init(void) | |||
958 | 0); | 999 | 0); |
959 | if (ret < 0) { | 1000 | if (ret < 0) { |
960 | pr_err("PCI: Mem-Map alloc failure on TRIO %d " | 1001 | pr_err("PCI: Mem-Map alloc failure on TRIO %d " |
961 | "mac %d for MC %d, give up\n", | 1002 | "mac %d for MC %d, give up\n", |
962 | controller->trio_index, | 1003 | controller->trio_index, |
963 | controller->mac, j); | 1004 | controller->mac, j); |
964 | 1005 | ||
965 | goto alloc_mem_map_failed; | 1006 | goto alloc_mem_map_failed; |
966 | } | 1007 | } |
@@ -991,9 +1032,9 @@ int __init pcibios_init(void) | |||
991 | GXIO_TRIO_ORDER_MODE_UNORDERED); | 1032 | GXIO_TRIO_ORDER_MODE_UNORDERED); |
992 | if (ret < 0) { | 1033 | if (ret < 0) { |
993 | pr_err("PCI: Mem-Map init failure on TRIO %d " | 1034 | pr_err("PCI: Mem-Map init failure on TRIO %d " |
994 | "mac %d for MC %d, give up\n", | 1035 | "mac %d for MC %d, give up\n", |
995 | controller->trio_index, | 1036 | controller->trio_index, |
996 | controller->mac, j); | 1037 | controller->mac, j); |
997 | 1038 | ||
998 | goto alloc_mem_map_failed; | 1039 | goto alloc_mem_map_failed; |
999 | } | 1040 | } |
@@ -1002,23 +1043,19 @@ int __init pcibios_init(void) | |||
1002 | alloc_mem_map_failed: | 1043 | alloc_mem_map_failed: |
1003 | break; | 1044 | break; |
1004 | } | 1045 | } |
1005 | |||
1006 | } | 1046 | } |
1007 | 1047 | ||
1008 | return 0; | 1048 | return 0; |
1009 | } | 1049 | } |
1010 | subsys_initcall(pcibios_init); | 1050 | subsys_initcall(pcibios_init); |
1011 | 1051 | ||
1012 | /* Note: to be deleted after Linux 3.6 merge. */ | 1052 | /* No bus fixups needed. */ |
1013 | void pcibios_fixup_bus(struct pci_bus *bus) | 1053 | void pcibios_fixup_bus(struct pci_bus *bus) |
1014 | { | 1054 | { |
1015 | } | 1055 | } |
1016 | 1056 | ||
1017 | /* | 1057 | /* Process any "pci=" kernel boot arguments. */ |
1018 | * This can be called from the generic PCI layer, but doesn't need to | 1058 | char *__init pcibios_setup(char *str) |
1019 | * do anything. | ||
1020 | */ | ||
1021 | char *pcibios_setup(char *str) | ||
1022 | { | 1059 | { |
1023 | if (!strcmp(str, "off")) { | 1060 | if (!strcmp(str, "off")) { |
1024 | pci_probe = 0; | 1061 | pci_probe = 0; |
@@ -1029,8 +1066,7 @@ char *pcibios_setup(char *str) | |||
1029 | 1066 | ||
1030 | /* | 1067 | /* |
1031 | * Enable memory address decoding, as appropriate, for the | 1068 | * Enable memory address decoding, as appropriate, for the |
1032 | * device described by the 'dev' struct. The I/O decoding | 1069 | * device described by the 'dev' struct. |
1033 | * is disabled, though the TILE-Gx supports I/O addressing. | ||
1034 | * | 1070 | * |
1035 | * This is called from the generic PCI layer, and can be called | 1071 | * This is called from the generic PCI layer, and can be called |
1036 | * for bridges or endpoints. | 1072 | * for bridges or endpoints. |
@@ -1040,13 +1076,24 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) | |||
1040 | return pci_enable_resources(dev, mask); | 1076 | return pci_enable_resources(dev, mask); |
1041 | } | 1077 | } |
1042 | 1078 | ||
1043 | /* Called for each device after PCI setup is done. */ | 1079 | /* |
1080 | * Called for each device after PCI setup is done. | ||
1081 | * We initialize the PCI device capabilities conservatively, assuming that | ||
1082 | * all devices can only address the 32-bit DMA space. The exception here is | ||
1083 | * that the device dma_offset is set to the value that matches the 64-bit | ||
1084 | * capable devices. This is OK because dma_offset is not used by legacy | ||
1085 | * dma_ops, nor by the hybrid dma_ops's streaming DMAs, which are 64-bit ops. | ||
1086 | * This implementation matches the kernel design of setting PCI devices' | ||
1087 | * coherent_dma_mask to 0xffffffffull by default, allowing the device drivers | ||
1088 | * to skip calling pci_set_consistent_dma_mask(DMA_BIT_MASK(32)). | ||
1089 | */ | ||
1044 | static void pcibios_fixup_final(struct pci_dev *pdev) | 1090 | static void pcibios_fixup_final(struct pci_dev *pdev) |
1045 | { | 1091 | { |
1046 | set_dma_ops(&pdev->dev, gx_pci_dma_map_ops); | 1092 | set_dma_ops(&pdev->dev, gx_legacy_pci_dma_map_ops); |
1047 | set_dma_offset(&pdev->dev, TILE_PCI_MEM_MAP_BASE_OFFSET); | 1093 | set_dma_offset(&pdev->dev, TILE_PCI_MEM_MAP_BASE_OFFSET); |
1048 | pdev->dev.archdata.max_direct_dma_addr = | 1094 | pdev->dev.archdata.max_direct_dma_addr = |
1049 | TILE_PCI_MAX_DIRECT_DMA_ADDRESS; | 1095 | TILE_PCI_MAX_DIRECT_DMA_ADDRESS; |
1096 | pdev->dev.coherent_dma_mask = TILE_PCI_MAX_DIRECT_DMA_ADDRESS; | ||
1050 | } | 1097 | } |
1051 | DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final); | 1098 | DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final); |
1052 | 1099 | ||
@@ -1060,19 +1107,15 @@ void __iomem *ioremap(resource_size_t phys_addr, unsigned long size) | |||
1060 | resource_size_t start; | 1107 | resource_size_t start; |
1061 | resource_size_t end; | 1108 | resource_size_t end; |
1062 | int trio_fd; | 1109 | int trio_fd; |
1063 | int i, j; | 1110 | int i; |
1064 | 1111 | ||
1065 | start = phys_addr; | 1112 | start = phys_addr; |
1066 | end = phys_addr + size - 1; | 1113 | end = phys_addr + size - 1; |
1067 | 1114 | ||
1068 | /* | 1115 | /* |
1069 | * In the following, each PCI controller's mem_resources[1] | 1116 | * By searching phys_addr in each controller's mem_space, we can |
1070 | * represents its (non-prefetchable) PCI memory resource and | ||
1071 | * mem_resources[2] refers to its prefetchable PCI memory resource. | ||
1072 | * By searching phys_addr in each controller's mem_resources[], we can | ||
1073 | * determine the controller that should accept the PCI memory access. | 1117 | * determine the controller that should accept the PCI memory access. |
1074 | */ | 1118 | */ |
1075 | |||
1076 | for (i = 0; i < num_rc_controllers; i++) { | 1119 | for (i = 0; i < num_rc_controllers; i++) { |
1077 | /* | 1120 | /* |
1078 | * Skip controllers that are not properly initialized or | 1121 | * Skip controllers that are not properly initialized or |
@@ -1081,25 +1124,18 @@ void __iomem *ioremap(resource_size_t phys_addr, unsigned long size) | |||
1081 | if (pci_controllers[i].root_bus == NULL) | 1124 | if (pci_controllers[i].root_bus == NULL) |
1082 | continue; | 1125 | continue; |
1083 | 1126 | ||
1084 | for (j = 1; j < 3; j++) { | 1127 | bar_start = pci_controllers[i].mem_space.start; |
1085 | bar_start = | 1128 | bar_end = pci_controllers[i].mem_space.end; |
1086 | pci_controllers[i].mem_resources[j].start; | ||
1087 | bar_end = | ||
1088 | pci_controllers[i].mem_resources[j].end; | ||
1089 | |||
1090 | if ((start >= bar_start) && (end <= bar_end)) { | ||
1091 | 1129 | ||
1092 | controller = &pci_controllers[i]; | 1130 | if ((start >= bar_start) && (end <= bar_end)) { |
1093 | 1131 | controller = &pci_controllers[i]; | |
1094 | goto got_it; | 1132 | break; |
1095 | } | ||
1096 | } | 1133 | } |
1097 | } | 1134 | } |
1098 | 1135 | ||
1099 | if (controller == NULL) | 1136 | if (controller == NULL) |
1100 | return NULL; | 1137 | return NULL; |
1101 | 1138 | ||
1102 | got_it: | ||
1103 | trio_fd = controller->trio->fd; | 1139 | trio_fd = controller->trio->fd; |
1104 | 1140 | ||
1105 | /* Convert the resource start to the bus address offset. */ | 1141 | /* Convert the resource start to the bus address offset. */ |
@@ -1107,14 +1143,71 @@ got_it: | |||
1107 | 1143 | ||
1108 | offset = HV_TRIO_PIO_OFFSET(controller->pio_mem_index) + start; | 1144 | offset = HV_TRIO_PIO_OFFSET(controller->pio_mem_index) + start; |
1109 | 1145 | ||
1110 | /* | 1146 | /* We need to keep the PCI bus address's in-page offset in the VA. */ |
1111 | * We need to keep the PCI bus address's in-page offset in the VA. | ||
1112 | */ | ||
1113 | return iorpc_ioremap(trio_fd, offset, size) + | 1147 | return iorpc_ioremap(trio_fd, offset, size) + |
1114 | (phys_addr & (PAGE_SIZE - 1)); | 1148 | (start & (PAGE_SIZE - 1)); |
1115 | } | 1149 | } |
1116 | EXPORT_SYMBOL(ioremap); | 1150 | EXPORT_SYMBOL(ioremap); |
1117 | 1151 | ||
1152 | #ifdef CONFIG_TILE_PCI_IO | ||
1153 | /* Map a PCI I/O address into VA space. */ | ||
1154 | void __iomem *ioport_map(unsigned long port, unsigned int size) | ||
1155 | { | ||
1156 | struct pci_controller *controller = NULL; | ||
1157 | resource_size_t bar_start; | ||
1158 | resource_size_t bar_end; | ||
1159 | resource_size_t offset; | ||
1160 | resource_size_t start; | ||
1161 | resource_size_t end; | ||
1162 | int trio_fd; | ||
1163 | int i; | ||
1164 | |||
1165 | start = port; | ||
1166 | end = port + size - 1; | ||
1167 | |||
1168 | /* | ||
1169 | * By searching the port in each controller's io_space, we can | ||
1170 | * determine the controller that should accept the PCI I/O access. | ||
1171 | */ | ||
1172 | for (i = 0; i < num_rc_controllers; i++) { | ||
1173 | /* | ||
1174 | * Skip controllers that are not properly initialized or | ||
1175 | * have down links. | ||
1176 | */ | ||
1177 | if (pci_controllers[i].root_bus == NULL) | ||
1178 | continue; | ||
1179 | |||
1180 | bar_start = pci_controllers[i].io_space.start; | ||
1181 | bar_end = pci_controllers[i].io_space.end; | ||
1182 | |||
1183 | if ((start >= bar_start) && (end <= bar_end)) { | ||
1184 | controller = &pci_controllers[i]; | ||
1185 | break; | ||
1186 | } | ||
1187 | } | ||
1188 | |||
1189 | if (controller == NULL) | ||
1190 | return NULL; | ||
1191 | |||
1192 | trio_fd = controller->trio->fd; | ||
1193 | |||
1194 | /* Convert the resource start to the bus address offset. */ | ||
1195 | port -= controller->io_space.start; | ||
1196 | |||
1197 | offset = HV_TRIO_PIO_OFFSET(controller->pio_io_index) + port; | ||
1198 | |||
1199 | /* We need to keep the PCI bus address's in-page offset in the VA. */ | ||
1200 | return iorpc_ioremap(trio_fd, offset, size) + (port & (PAGE_SIZE - 1)); | ||
1201 | } | ||
1202 | EXPORT_SYMBOL(ioport_map); | ||
1203 | |||
1204 | void ioport_unmap(void __iomem *addr) | ||
1205 | { | ||
1206 | iounmap(addr); | ||
1207 | } | ||
1208 | EXPORT_SYMBOL(ioport_unmap); | ||
1209 | #endif | ||
1210 | |||
1118 | void pci_iounmap(struct pci_dev *dev, void __iomem *addr) | 1211 | void pci_iounmap(struct pci_dev *dev, void __iomem *addr) |
1119 | { | 1212 | { |
1120 | iounmap(addr); | 1213 | iounmap(addr); |
@@ -1136,7 +1229,6 @@ EXPORT_SYMBOL(pci_iounmap); | |||
1136 | * offset is in bytes, from the start of config space for the | 1229 | * offset is in bytes, from the start of config space for the |
1137 | * specified bus & device. | 1230 | * specified bus & device. |
1138 | */ | 1231 | */ |
1139 | |||
1140 | static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset, | 1232 | static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset, |
1141 | int size, u32 *val) | 1233 | int size, u32 *val) |
1142 | { | 1234 | { |
@@ -1186,7 +1278,6 @@ static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset, | |||
1186 | * Accesses to the directly attached device have to be | 1278 | * Accesses to the directly attached device have to be |
1187 | * sent as type-0 configs. | 1279 | * sent as type-0 configs. |
1188 | */ | 1280 | */ |
1189 | |||
1190 | if (busnum == (controller->first_busno + 1)) { | 1281 | if (busnum == (controller->first_busno + 1)) { |
1191 | /* | 1282 | /* |
1192 | * There is only one device off of our built-in P2P bridge. | 1283 | * There is only one device off of our built-in P2P bridge. |
@@ -1208,9 +1299,8 @@ static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset, | |||
1208 | * Note that we don't set the mac field in cfg_addr because the | 1299 | * Note that we don't set the mac field in cfg_addr because the |
1209 | * mapping is per port. | 1300 | * mapping is per port. |
1210 | */ | 1301 | */ |
1211 | |||
1212 | mmio_addr = trio_context->mmio_base_pio_cfg[controller->mac] + | 1302 | mmio_addr = trio_context->mmio_base_pio_cfg[controller->mac] + |
1213 | cfg_addr.word; | 1303 | cfg_addr.word; |
1214 | 1304 | ||
1215 | valid_device: | 1305 | valid_device: |
1216 | 1306 | ||
@@ -1314,7 +1404,6 @@ static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset, | |||
1314 | * Accesses to the directly attached device have to be | 1404 | * Accesses to the directly attached device have to be |
1315 | * sent as type-0 configs. | 1405 | * sent as type-0 configs. |
1316 | */ | 1406 | */ |
1317 | |||
1318 | if (busnum == (controller->first_busno + 1)) { | 1407 | if (busnum == (controller->first_busno + 1)) { |
1319 | /* | 1408 | /* |
1320 | * There is only one device off of our built-in P2P bridge. | 1409 | * There is only one device off of our built-in P2P bridge. |
@@ -1336,7 +1425,6 @@ static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset, | |||
1336 | * Note that we don't set the mac field in cfg_addr because the | 1425 | * Note that we don't set the mac field in cfg_addr because the |
1337 | * mapping is per port. | 1426 | * mapping is per port. |
1338 | */ | 1427 | */ |
1339 | |||
1340 | mmio_addr = trio_context->mmio_base_pio_cfg[controller->mac] + | 1428 | mmio_addr = trio_context->mmio_base_pio_cfg[controller->mac] + |
1341 | cfg_addr.word; | 1429 | cfg_addr.word; |
1342 | 1430 | ||
@@ -1374,11 +1462,8 @@ static struct pci_ops tile_cfg_ops = { | |||
1374 | }; | 1462 | }; |
1375 | 1463 | ||
1376 | 1464 | ||
1377 | /* | 1465 | /* MSI support starts here. */ |
1378 | * MSI support starts here. | 1466 | static unsigned int tilegx_msi_startup(struct irq_data *d) |
1379 | */ | ||
1380 | static unsigned int | ||
1381 | tilegx_msi_startup(struct irq_data *d) | ||
1382 | { | 1467 | { |
1383 | if (d->msi_desc) | 1468 | if (d->msi_desc) |
1384 | unmask_msi_irq(d); | 1469 | unmask_msi_irq(d); |
@@ -1386,21 +1471,18 @@ tilegx_msi_startup(struct irq_data *d) | |||
1386 | return 0; | 1471 | return 0; |
1387 | } | 1472 | } |
1388 | 1473 | ||
1389 | static void | 1474 | static void tilegx_msi_ack(struct irq_data *d) |
1390 | tilegx_msi_ack(struct irq_data *d) | ||
1391 | { | 1475 | { |
1392 | __insn_mtspr(SPR_IPI_EVENT_RESET_K, 1UL << d->irq); | 1476 | __insn_mtspr(SPR_IPI_EVENT_RESET_K, 1UL << d->irq); |
1393 | } | 1477 | } |
1394 | 1478 | ||
1395 | static void | 1479 | static void tilegx_msi_mask(struct irq_data *d) |
1396 | tilegx_msi_mask(struct irq_data *d) | ||
1397 | { | 1480 | { |
1398 | mask_msi_irq(d); | 1481 | mask_msi_irq(d); |
1399 | __insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq); | 1482 | __insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq); |
1400 | } | 1483 | } |
1401 | 1484 | ||
1402 | static void | 1485 | static void tilegx_msi_unmask(struct irq_data *d) |
1403 | tilegx_msi_unmask(struct irq_data *d) | ||
1404 | { | 1486 | { |
1405 | __insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq); | 1487 | __insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq); |
1406 | unmask_msi_irq(d); | 1488 | unmask_msi_irq(d); |
@@ -1457,32 +1539,55 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) | |||
1457 | trio_context = controller->trio; | 1539 | trio_context = controller->trio; |
1458 | 1540 | ||
1459 | /* | 1541 | /* |
1460 | * Allocate the Mem-Map that will accept the MSI write and | 1542 | * Allocate a scatter-queue that will accept the MSI write and |
1461 | * trigger the TILE-side interrupts. | 1543 | * trigger the TILE-side interrupts. We use the scatter-queue regions |
1544 | * before the mem map regions, because the latter are needed by more | ||
1545 | * applications. | ||
1462 | */ | 1546 | */ |
1463 | mem_map = gxio_trio_alloc_memory_maps(trio_context, 1, 0, 0); | 1547 | mem_map = gxio_trio_alloc_scatter_queues(trio_context, 1, 0, 0); |
1464 | if (mem_map < 0) { | 1548 | if (mem_map >= 0) { |
1465 | dev_printk(KERN_INFO, &pdev->dev, | 1549 | TRIO_MAP_SQ_DOORBELL_FMT_t doorbell_template = {{ |
1466 | "%s Mem-Map alloc failure. " | 1550 | .pop = 0, |
1467 | "Failed to initialize MSI interrupts. " | 1551 | .doorbell = 1, |
1468 | "Falling back to legacy interrupts.\n", | 1552 | }}; |
1469 | desc->msi_attrib.is_msix ? "MSI-X" : "MSI"); | 1553 | |
1554 | mem_map += TRIO_NUM_MAP_MEM_REGIONS; | ||
1555 | mem_map_base = MEM_MAP_INTR_REGIONS_BASE + | ||
1556 | mem_map * MEM_MAP_INTR_REGION_SIZE; | ||
1557 | mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1; | ||
1558 | |||
1559 | msi_addr = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 8; | ||
1560 | msg.data = (unsigned int)doorbell_template.word; | ||
1561 | } else { | ||
1562 | /* SQ regions are out, allocate from map mem regions. */ | ||
1563 | mem_map = gxio_trio_alloc_memory_maps(trio_context, 1, 0, 0); | ||
1564 | if (mem_map < 0) { | ||
1565 | dev_printk(KERN_INFO, &pdev->dev, | ||
1566 | "%s Mem-Map alloc failure. " | ||
1567 | "Failed to initialize MSI interrupts. " | ||
1568 | "Falling back to legacy interrupts.\n", | ||
1569 | desc->msi_attrib.is_msix ? "MSI-X" : "MSI"); | ||
1570 | ret = -ENOMEM; | ||
1571 | goto msi_mem_map_alloc_failure; | ||
1572 | } | ||
1470 | 1573 | ||
1471 | ret = -ENOMEM; | 1574 | mem_map_base = MEM_MAP_INTR_REGIONS_BASE + |
1472 | goto msi_mem_map_alloc_failure; | 1575 | mem_map * MEM_MAP_INTR_REGION_SIZE; |
1576 | mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1; | ||
1577 | |||
1578 | msi_addr = mem_map_base + TRIO_MAP_MEM_REG_INT3 - | ||
1579 | TRIO_MAP_MEM_REG_INT0; | ||
1580 | |||
1581 | msg.data = mem_map; | ||
1473 | } | 1582 | } |
1474 | 1583 | ||
1475 | /* We try to distribute different IRQs to different tiles. */ | 1584 | /* We try to distribute different IRQs to different tiles. */ |
1476 | cpu = tile_irq_cpu(irq); | 1585 | cpu = tile_irq_cpu(irq); |
1477 | 1586 | ||
1478 | /* | 1587 | /* |
1479 | * Now call up to the HV to configure the Mem-Map interrupt and | 1588 | * Now call up to the HV to configure the MSI interrupt and |
1480 | * set up the IPI binding. | 1589 | * set up the IPI binding. |
1481 | */ | 1590 | */ |
1482 | mem_map_base = MEM_MAP_INTR_REGIONS_BASE + | ||
1483 | mem_map * MEM_MAP_INTR_REGION_SIZE; | ||
1484 | mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1; | ||
1485 | |||
1486 | ret = gxio_trio_config_msi_intr(trio_context, cpu_x(cpu), cpu_y(cpu), | 1591 | ret = gxio_trio_config_msi_intr(trio_context, cpu_x(cpu), cpu_y(cpu), |
1487 | KERNEL_PL, irq, controller->mac, | 1592 | KERNEL_PL, irq, controller->mac, |
1488 | mem_map, mem_map_base, mem_map_limit, | 1593 | mem_map, mem_map_base, mem_map_limit, |
@@ -1495,13 +1600,9 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) | |||
1495 | 1600 | ||
1496 | irq_set_msi_desc(irq, desc); | 1601 | irq_set_msi_desc(irq, desc); |
1497 | 1602 | ||
1498 | msi_addr = mem_map_base + TRIO_MAP_MEM_REG_INT3 - TRIO_MAP_MEM_REG_INT0; | ||
1499 | |||
1500 | msg.address_hi = msi_addr >> 32; | 1603 | msg.address_hi = msi_addr >> 32; |
1501 | msg.address_lo = msi_addr & 0xffffffff; | 1604 | msg.address_lo = msi_addr & 0xffffffff; |
1502 | 1605 | ||
1503 | msg.data = mem_map; | ||
1504 | |||
1505 | write_msi_msg(irq, &msg); | 1606 | write_msi_msg(irq, &msg); |
1506 | irq_set_chip_and_handler(irq, &tilegx_msi_chip, handle_level_irq); | 1607 | irq_set_chip_and_handler(irq, &tilegx_msi_chip, handle_level_irq); |
1507 | irq_set_handler_data(irq, controller); | 1608 | irq_set_handler_data(irq, controller); |
diff --git a/arch/tile/kernel/proc.c b/arch/tile/kernel/proc.c index dafc447b5125..681100c59fda 100644 --- a/arch/tile/kernel/proc.c +++ b/arch/tile/kernel/proc.c | |||
@@ -113,7 +113,6 @@ arch_initcall(proc_tile_init); | |||
113 | * Support /proc/sys/tile directory | 113 | * Support /proc/sys/tile directory |
114 | */ | 114 | */ |
115 | 115 | ||
116 | #ifndef __tilegx__ /* FIXME: GX: no support for unaligned access yet */ | ||
117 | static ctl_table unaligned_subtable[] = { | 116 | static ctl_table unaligned_subtable[] = { |
118 | { | 117 | { |
119 | .procname = "enabled", | 118 | .procname = "enabled", |
@@ -160,4 +159,3 @@ static int __init proc_sys_tile_init(void) | |||
160 | } | 159 | } |
161 | 160 | ||
162 | arch_initcall(proc_sys_tile_init); | 161 | arch_initcall(proc_sys_tile_init); |
163 | #endif | ||
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 8ac304484f98..16ed58948757 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/syscalls.h> | 33 | #include <asm/syscalls.h> |
34 | #include <asm/traps.h> | 34 | #include <asm/traps.h> |
35 | #include <asm/setup.h> | 35 | #include <asm/setup.h> |
36 | #include <asm/uaccess.h> | ||
36 | #ifdef CONFIG_HARDWALL | 37 | #ifdef CONFIG_HARDWALL |
37 | #include <asm/hardwall.h> | 38 | #include <asm/hardwall.h> |
38 | #endif | 39 | #endif |
@@ -74,19 +75,6 @@ void arch_release_thread_info(struct thread_info *info) | |||
74 | { | 75 | { |
75 | struct single_step_state *step_state = info->step_state; | 76 | struct single_step_state *step_state = info->step_state; |
76 | 77 | ||
77 | #ifdef CONFIG_HARDWALL | ||
78 | /* | ||
79 | * We free a thread_info from the context of the task that has | ||
80 | * been scheduled next, so the original task is already dead. | ||
81 | * Calling deactivate here just frees up the data structures. | ||
82 | * If the task we're freeing held the last reference to a | ||
83 | * hardwall fd, it would have been released prior to this point | ||
84 | * anyway via exit_files(), and the hardwall_task.info pointers | ||
85 | * would be NULL by now. | ||
86 | */ | ||
87 | hardwall_deactivate_all(info->task); | ||
88 | #endif | ||
89 | |||
90 | if (step_state) { | 78 | if (step_state) { |
91 | 79 | ||
92 | /* | 80 | /* |
@@ -160,6 +148,14 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
160 | */ | 148 | */ |
161 | task_thread_info(p)->step_state = NULL; | 149 | task_thread_info(p)->step_state = NULL; |
162 | 150 | ||
151 | #ifdef __tilegx__ | ||
152 | /* | ||
153 | * Do not clone unalign jit fixup from the parent; each thread | ||
154 | * must allocate its own on demand. | ||
155 | */ | ||
156 | task_thread_info(p)->unalign_jit_base = NULL; | ||
157 | #endif | ||
158 | |||
163 | /* | 159 | /* |
164 | * Copy the registers onto the kernel stack so the | 160 | * Copy the registers onto the kernel stack so the |
165 | * return-from-interrupt code will reload it into registers. | 161 | * return-from-interrupt code will reload it into registers. |
@@ -191,16 +187,8 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
191 | memset(&p->thread.dma_async_tlb, 0, sizeof(struct async_tlb)); | 187 | memset(&p->thread.dma_async_tlb, 0, sizeof(struct async_tlb)); |
192 | #endif | 188 | #endif |
193 | 189 | ||
194 | #if CHIP_HAS_SN_PROC() | ||
195 | /* Likewise, the new thread is not running static processor code. */ | ||
196 | p->thread.sn_proc_running = 0; | ||
197 | memset(&p->thread.sn_async_tlb, 0, sizeof(struct async_tlb)); | ||
198 | #endif | ||
199 | |||
200 | #if CHIP_HAS_PROC_STATUS_SPR() | ||
201 | /* New thread has its miscellaneous processor state bits clear. */ | 190 | /* New thread has its miscellaneous processor state bits clear. */ |
202 | p->thread.proc_status = 0; | 191 | p->thread.proc_status = 0; |
203 | #endif | ||
204 | 192 | ||
205 | #ifdef CONFIG_HARDWALL | 193 | #ifdef CONFIG_HARDWALL |
206 | /* New thread does not own any networks. */ | 194 | /* New thread does not own any networks. */ |
@@ -218,19 +206,32 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
218 | return 0; | 206 | return 0; |
219 | } | 207 | } |
220 | 208 | ||
209 | int set_unalign_ctl(struct task_struct *tsk, unsigned int val) | ||
210 | { | ||
211 | task_thread_info(tsk)->align_ctl = val; | ||
212 | return 0; | ||
213 | } | ||
214 | |||
215 | int get_unalign_ctl(struct task_struct *tsk, unsigned long adr) | ||
216 | { | ||
217 | return put_user(task_thread_info(tsk)->align_ctl, | ||
218 | (unsigned int __user *)adr); | ||
219 | } | ||
220 | |||
221 | static struct task_struct corrupt_current = { .comm = "<corrupt>" }; | ||
222 | |||
221 | /* | 223 | /* |
222 | * Return "current" if it looks plausible, or else a pointer to a dummy. | 224 | * Return "current" if it looks plausible, or else a pointer to a dummy. |
223 | * This can be helpful if we are just trying to emit a clean panic. | 225 | * This can be helpful if we are just trying to emit a clean panic. |
224 | */ | 226 | */ |
225 | struct task_struct *validate_current(void) | 227 | struct task_struct *validate_current(void) |
226 | { | 228 | { |
227 | static struct task_struct corrupt = { .comm = "<corrupt>" }; | ||
228 | struct task_struct *tsk = current; | 229 | struct task_struct *tsk = current; |
229 | if (unlikely((unsigned long)tsk < PAGE_OFFSET || | 230 | if (unlikely((unsigned long)tsk < PAGE_OFFSET || |
230 | (high_memory && (void *)tsk > high_memory) || | 231 | (high_memory && (void *)tsk > high_memory) || |
231 | ((unsigned long)tsk & (__alignof__(*tsk) - 1)) != 0)) { | 232 | ((unsigned long)tsk & (__alignof__(*tsk) - 1)) != 0)) { |
232 | pr_err("Corrupt 'current' %p (sp %#lx)\n", tsk, stack_pointer); | 233 | pr_err("Corrupt 'current' %p (sp %#lx)\n", tsk, stack_pointer); |
233 | tsk = &corrupt; | 234 | tsk = &corrupt_current; |
234 | } | 235 | } |
235 | return tsk; | 236 | return tsk; |
236 | } | 237 | } |
@@ -369,15 +370,11 @@ static void save_arch_state(struct thread_struct *t) | |||
369 | t->system_save[2] = __insn_mfspr(SPR_SYSTEM_SAVE_0_2); | 370 | t->system_save[2] = __insn_mfspr(SPR_SYSTEM_SAVE_0_2); |
370 | t->system_save[3] = __insn_mfspr(SPR_SYSTEM_SAVE_0_3); | 371 | t->system_save[3] = __insn_mfspr(SPR_SYSTEM_SAVE_0_3); |
371 | t->intctrl_0 = __insn_mfspr(SPR_INTCTRL_0_STATUS); | 372 | t->intctrl_0 = __insn_mfspr(SPR_INTCTRL_0_STATUS); |
372 | #if CHIP_HAS_PROC_STATUS_SPR() | ||
373 | t->proc_status = __insn_mfspr(SPR_PROC_STATUS); | 373 | t->proc_status = __insn_mfspr(SPR_PROC_STATUS); |
374 | #endif | ||
375 | #if !CHIP_HAS_FIXED_INTVEC_BASE() | 374 | #if !CHIP_HAS_FIXED_INTVEC_BASE() |
376 | t->interrupt_vector_base = __insn_mfspr(SPR_INTERRUPT_VECTOR_BASE_0); | 375 | t->interrupt_vector_base = __insn_mfspr(SPR_INTERRUPT_VECTOR_BASE_0); |
377 | #endif | 376 | #endif |
378 | #if CHIP_HAS_TILE_RTF_HWM() | ||
379 | t->tile_rtf_hwm = __insn_mfspr(SPR_TILE_RTF_HWM); | 377 | t->tile_rtf_hwm = __insn_mfspr(SPR_TILE_RTF_HWM); |
380 | #endif | ||
381 | #if CHIP_HAS_DSTREAM_PF() | 378 | #if CHIP_HAS_DSTREAM_PF() |
382 | t->dstream_pf = __insn_mfspr(SPR_DSTREAM_PF); | 379 | t->dstream_pf = __insn_mfspr(SPR_DSTREAM_PF); |
383 | #endif | 380 | #endif |
@@ -398,15 +395,11 @@ static void restore_arch_state(const struct thread_struct *t) | |||
398 | __insn_mtspr(SPR_SYSTEM_SAVE_0_2, t->system_save[2]); | 395 | __insn_mtspr(SPR_SYSTEM_SAVE_0_2, t->system_save[2]); |
399 | __insn_mtspr(SPR_SYSTEM_SAVE_0_3, t->system_save[3]); | 396 | __insn_mtspr(SPR_SYSTEM_SAVE_0_3, t->system_save[3]); |
400 | __insn_mtspr(SPR_INTCTRL_0_STATUS, t->intctrl_0); | 397 | __insn_mtspr(SPR_INTCTRL_0_STATUS, t->intctrl_0); |
401 | #if CHIP_HAS_PROC_STATUS_SPR() | ||
402 | __insn_mtspr(SPR_PROC_STATUS, t->proc_status); | 398 | __insn_mtspr(SPR_PROC_STATUS, t->proc_status); |
403 | #endif | ||
404 | #if !CHIP_HAS_FIXED_INTVEC_BASE() | 399 | #if !CHIP_HAS_FIXED_INTVEC_BASE() |
405 | __insn_mtspr(SPR_INTERRUPT_VECTOR_BASE_0, t->interrupt_vector_base); | 400 | __insn_mtspr(SPR_INTERRUPT_VECTOR_BASE_0, t->interrupt_vector_base); |
406 | #endif | 401 | #endif |
407 | #if CHIP_HAS_TILE_RTF_HWM() | ||
408 | __insn_mtspr(SPR_TILE_RTF_HWM, t->tile_rtf_hwm); | 402 | __insn_mtspr(SPR_TILE_RTF_HWM, t->tile_rtf_hwm); |
409 | #endif | ||
410 | #if CHIP_HAS_DSTREAM_PF() | 403 | #if CHIP_HAS_DSTREAM_PF() |
411 | __insn_mtspr(SPR_DSTREAM_PF, t->dstream_pf); | 404 | __insn_mtspr(SPR_DSTREAM_PF, t->dstream_pf); |
412 | #endif | 405 | #endif |
@@ -415,26 +408,11 @@ static void restore_arch_state(const struct thread_struct *t) | |||
415 | 408 | ||
416 | void _prepare_arch_switch(struct task_struct *next) | 409 | void _prepare_arch_switch(struct task_struct *next) |
417 | { | 410 | { |
418 | #if CHIP_HAS_SN_PROC() | ||
419 | int snctl; | ||
420 | #endif | ||
421 | #if CHIP_HAS_TILE_DMA() | 411 | #if CHIP_HAS_TILE_DMA() |
422 | struct tile_dma_state *dma = ¤t->thread.tile_dma_state; | 412 | struct tile_dma_state *dma = ¤t->thread.tile_dma_state; |
423 | if (dma->enabled) | 413 | if (dma->enabled) |
424 | save_tile_dma_state(dma); | 414 | save_tile_dma_state(dma); |
425 | #endif | 415 | #endif |
426 | #if CHIP_HAS_SN_PROC() | ||
427 | /* | ||
428 | * Suspend the static network processor if it was running. | ||
429 | * We do not suspend the fabric itself, just like we don't | ||
430 | * try to suspend the UDN. | ||
431 | */ | ||
432 | snctl = __insn_mfspr(SPR_SNCTL); | ||
433 | current->thread.sn_proc_running = | ||
434 | (snctl & SPR_SNCTL__FRZPROC_MASK) == 0; | ||
435 | if (current->thread.sn_proc_running) | ||
436 | __insn_mtspr(SPR_SNCTL, snctl | SPR_SNCTL__FRZPROC_MASK); | ||
437 | #endif | ||
438 | } | 416 | } |
439 | 417 | ||
440 | 418 | ||
@@ -462,17 +440,6 @@ struct task_struct *__sched _switch_to(struct task_struct *prev, | |||
462 | /* Restore other arch state. */ | 440 | /* Restore other arch state. */ |
463 | restore_arch_state(&next->thread); | 441 | restore_arch_state(&next->thread); |
464 | 442 | ||
465 | #if CHIP_HAS_SN_PROC() | ||
466 | /* | ||
467 | * Restart static network processor in the new process | ||
468 | * if it was running before. | ||
469 | */ | ||
470 | if (next->thread.sn_proc_running) { | ||
471 | int snctl = __insn_mfspr(SPR_SNCTL); | ||
472 | __insn_mtspr(SPR_SNCTL, snctl & ~SPR_SNCTL__FRZPROC_MASK); | ||
473 | } | ||
474 | #endif | ||
475 | |||
476 | #ifdef CONFIG_HARDWALL | 443 | #ifdef CONFIG_HARDWALL |
477 | /* Enable or disable access to the network registers appropriately. */ | 444 | /* Enable or disable access to the network registers appropriately. */ |
478 | hardwall_switch_tasks(prev, next); | 445 | hardwall_switch_tasks(prev, next); |
@@ -514,7 +481,7 @@ int do_work_pending(struct pt_regs *regs, u32 thread_info_flags) | |||
514 | schedule(); | 481 | schedule(); |
515 | return 1; | 482 | return 1; |
516 | } | 483 | } |
517 | #if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() | 484 | #if CHIP_HAS_TILE_DMA() |
518 | if (thread_info_flags & _TIF_ASYNC_TLB) { | 485 | if (thread_info_flags & _TIF_ASYNC_TLB) { |
519 | do_async_page_fault(regs); | 486 | do_async_page_fault(regs); |
520 | return 1; | 487 | return 1; |
@@ -564,7 +531,15 @@ void flush_thread(void) | |||
564 | */ | 531 | */ |
565 | void exit_thread(void) | 532 | void exit_thread(void) |
566 | { | 533 | { |
567 | /* Nothing */ | 534 | #ifdef CONFIG_HARDWALL |
535 | /* | ||
536 | * Remove the task from the list of tasks that are associated | ||
537 | * with any live hardwalls. (If the task that is exiting held | ||
538 | * the last reference to a hardwall fd, it would already have | ||
539 | * been released and deactivated at this point.) | ||
540 | */ | ||
541 | hardwall_deactivate_all(current); | ||
542 | #endif | ||
568 | } | 543 | } |
569 | 544 | ||
570 | void show_regs(struct pt_regs *regs) | 545 | void show_regs(struct pt_regs *regs) |
@@ -573,23 +548,24 @@ void show_regs(struct pt_regs *regs) | |||
573 | int i; | 548 | int i; |
574 | 549 | ||
575 | pr_err("\n"); | 550 | pr_err("\n"); |
576 | show_regs_print_info(KERN_ERR); | 551 | if (tsk != &corrupt_current) |
552 | show_regs_print_info(KERN_ERR); | ||
577 | #ifdef __tilegx__ | 553 | #ifdef __tilegx__ |
578 | for (i = 0; i < 51; i += 3) | 554 | for (i = 0; i < 17; i++) |
579 | pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT" r%-2d: "REGFMT"\n", | 555 | pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT" r%-2d: "REGFMT"\n", |
580 | i, regs->regs[i], i+1, regs->regs[i+1], | 556 | i, regs->regs[i], i+18, regs->regs[i+18], |
581 | i+2, regs->regs[i+2]); | 557 | i+36, regs->regs[i+36]); |
582 | pr_err(" r51: "REGFMT" r52: "REGFMT" tp : "REGFMT"\n", | 558 | pr_err(" r17: "REGFMT" r35: "REGFMT" tp : "REGFMT"\n", |
583 | regs->regs[51], regs->regs[52], regs->tp); | 559 | regs->regs[17], regs->regs[35], regs->tp); |
584 | pr_err(" sp : "REGFMT" lr : "REGFMT"\n", regs->sp, regs->lr); | 560 | pr_err(" sp : "REGFMT" lr : "REGFMT"\n", regs->sp, regs->lr); |
585 | #else | 561 | #else |
586 | for (i = 0; i < 52; i += 4) | 562 | for (i = 0; i < 13; i++) |
587 | pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT | 563 | pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT |
588 | " r%-2d: "REGFMT" r%-2d: "REGFMT"\n", | 564 | " r%-2d: "REGFMT" r%-2d: "REGFMT"\n", |
589 | i, regs->regs[i], i+1, regs->regs[i+1], | 565 | i, regs->regs[i], i+14, regs->regs[i+14], |
590 | i+2, regs->regs[i+2], i+3, regs->regs[i+3]); | 566 | i+27, regs->regs[i+27], i+40, regs->regs[i+40]); |
591 | pr_err(" r52: "REGFMT" tp : "REGFMT" sp : "REGFMT" lr : "REGFMT"\n", | 567 | pr_err(" r13: "REGFMT" tp : "REGFMT" sp : "REGFMT" lr : "REGFMT"\n", |
592 | regs->regs[52], regs->tp, regs->sp, regs->lr); | 568 | regs->regs[13], regs->tp, regs->sp, regs->lr); |
593 | #endif | 569 | #endif |
594 | pr_err(" pc : "REGFMT" ex1: %ld faultnum: %ld\n", | 570 | pr_err(" pc : "REGFMT" ex1: %ld faultnum: %ld\n", |
595 | regs->pc, regs->ex1, regs->faultnum); | 571 | regs->pc, regs->ex1, regs->faultnum); |
diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c index 0f83ed4602b2..de98c6ddf136 100644 --- a/arch/tile/kernel/ptrace.c +++ b/arch/tile/kernel/ptrace.c | |||
@@ -265,6 +265,21 @@ int do_syscall_trace_enter(struct pt_regs *regs) | |||
265 | 265 | ||
266 | void do_syscall_trace_exit(struct pt_regs *regs) | 266 | void do_syscall_trace_exit(struct pt_regs *regs) |
267 | { | 267 | { |
268 | long errno; | ||
269 | |||
270 | /* | ||
271 | * The standard tile calling convention returns the value (or negative | ||
272 | * errno) in r0, and zero (or positive errno) in r1. | ||
273 | * It saves a couple of cycles on the hot path to do this work in | ||
274 | * registers only as we return, rather than updating the in-memory | ||
275 | * struct ptregs. | ||
276 | */ | ||
277 | errno = (long) regs->regs[0]; | ||
278 | if (errno < 0 && errno > -4096) | ||
279 | regs->regs[1] = -errno; | ||
280 | else | ||
281 | regs->regs[1] = 0; | ||
282 | |||
268 | if (test_thread_flag(TIF_SYSCALL_TRACE)) | 283 | if (test_thread_flag(TIF_SYSCALL_TRACE)) |
269 | tracehook_report_syscall_exit(regs, 0); | 284 | tracehook_report_syscall_exit(regs, 0); |
270 | 285 | ||
@@ -272,7 +287,7 @@ void do_syscall_trace_exit(struct pt_regs *regs) | |||
272 | trace_sys_exit(regs, regs->regs[0]); | 287 | trace_sys_exit(regs, regs->regs[0]); |
273 | } | 288 | } |
274 | 289 | ||
275 | void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) | 290 | void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs) |
276 | { | 291 | { |
277 | struct siginfo info; | 292 | struct siginfo info; |
278 | 293 | ||
@@ -288,5 +303,5 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code) | |||
288 | /* Handle synthetic interrupt delivered only by the simulator. */ | 303 | /* Handle synthetic interrupt delivered only by the simulator. */ |
289 | void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num) | 304 | void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num) |
290 | { | 305 | { |
291 | send_sigtrap(current, regs, fault_num); | 306 | send_sigtrap(current, regs); |
292 | } | 307 | } |
diff --git a/arch/tile/kernel/reboot.c b/arch/tile/kernel/reboot.c index d1b5c913ae72..6c5d2c070a12 100644 --- a/arch/tile/kernel/reboot.c +++ b/arch/tile/kernel/reboot.c | |||
@@ -27,7 +27,6 @@ | |||
27 | 27 | ||
28 | void machine_halt(void) | 28 | void machine_halt(void) |
29 | { | 29 | { |
30 | warn_early_printk(); | ||
31 | arch_local_irq_disable_all(); | 30 | arch_local_irq_disable_all(); |
32 | smp_send_stop(); | 31 | smp_send_stop(); |
33 | hv_halt(); | 32 | hv_halt(); |
@@ -35,7 +34,6 @@ void machine_halt(void) | |||
35 | 34 | ||
36 | void machine_power_off(void) | 35 | void machine_power_off(void) |
37 | { | 36 | { |
38 | warn_early_printk(); | ||
39 | arch_local_irq_disable_all(); | 37 | arch_local_irq_disable_all(); |
40 | smp_send_stop(); | 38 | smp_send_stop(); |
41 | hv_power_off(); | 39 | hv_power_off(); |
diff --git a/arch/tile/kernel/regs_32.S b/arch/tile/kernel/regs_32.S index c12280c2d904..542cae17a93a 100644 --- a/arch/tile/kernel/regs_32.S +++ b/arch/tile/kernel/regs_32.S | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <asm/switch_to.h> | 20 | #include <asm/switch_to.h> |
21 | 21 | ||
22 | /* | 22 | /* |
23 | * See <asm/system.h>; called with prev and next task_struct pointers. | 23 | * See <asm/switch_to.h>; called with prev and next task_struct pointers. |
24 | * "prev" is returned in r0 for _switch_to and also for ret_from_fork. | 24 | * "prev" is returned in r0 for _switch_to and also for ret_from_fork. |
25 | * | 25 | * |
26 | * We want to save pc/sp in "prev", and get the new pc/sp from "next". | 26 | * We want to save pc/sp in "prev", and get the new pc/sp from "next". |
@@ -39,7 +39,7 @@ | |||
39 | */ | 39 | */ |
40 | 40 | ||
41 | #if CALLEE_SAVED_REGS_COUNT != 24 | 41 | #if CALLEE_SAVED_REGS_COUNT != 24 |
42 | # error Mismatch between <asm/system.h> and kernel/entry.S | 42 | # error Mismatch between <asm/switch_to.h> and kernel/entry.S |
43 | #endif | 43 | #endif |
44 | #define FRAME_SIZE ((2 + CALLEE_SAVED_REGS_COUNT) * 4) | 44 | #define FRAME_SIZE ((2 + CALLEE_SAVED_REGS_COUNT) * 4) |
45 | 45 | ||
diff --git a/arch/tile/kernel/regs_64.S b/arch/tile/kernel/regs_64.S index 0829fd01fa30..bbffcc6f340f 100644 --- a/arch/tile/kernel/regs_64.S +++ b/arch/tile/kernel/regs_64.S | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <asm/switch_to.h> | 20 | #include <asm/switch_to.h> |
21 | 21 | ||
22 | /* | 22 | /* |
23 | * See <asm/system.h>; called with prev and next task_struct pointers. | 23 | * See <asm/switch_to.h>; called with prev and next task_struct pointers. |
24 | * "prev" is returned in r0 for _switch_to and also for ret_from_fork. | 24 | * "prev" is returned in r0 for _switch_to and also for ret_from_fork. |
25 | * | 25 | * |
26 | * We want to save pc/sp in "prev", and get the new pc/sp from "next". | 26 | * We want to save pc/sp in "prev", and get the new pc/sp from "next". |
@@ -39,7 +39,7 @@ | |||
39 | */ | 39 | */ |
40 | 40 | ||
41 | #if CALLEE_SAVED_REGS_COUNT != 24 | 41 | #if CALLEE_SAVED_REGS_COUNT != 24 |
42 | # error Mismatch between <asm/system.h> and kernel/entry.S | 42 | # error Mismatch between <asm/switch_to.h> and kernel/entry.S |
43 | #endif | 43 | #endif |
44 | #define FRAME_SIZE ((2 + CALLEE_SAVED_REGS_COUNT) * 8) | 44 | #define FRAME_SIZE ((2 + CALLEE_SAVED_REGS_COUNT) * 8) |
45 | 45 | ||
diff --git a/arch/tile/kernel/relocate_kernel_32.S b/arch/tile/kernel/relocate_kernel_32.S index 010b418515f8..e44fbcf8cbd5 100644 --- a/arch/tile/kernel/relocate_kernel_32.S +++ b/arch/tile/kernel/relocate_kernel_32.S | |||
@@ -20,15 +20,6 @@ | |||
20 | #include <asm/page.h> | 20 | #include <asm/page.h> |
21 | #include <hv/hypervisor.h> | 21 | #include <hv/hypervisor.h> |
22 | 22 | ||
23 | #define ___hvb MEM_SV_INTRPT + HV_GLUE_START_CPA | ||
24 | |||
25 | #define ___hv_dispatch(f) (___hvb + (HV_DISPATCH_ENTRY_SIZE * f)) | ||
26 | |||
27 | #define ___hv_console_putc ___hv_dispatch(HV_DISPATCH_CONSOLE_PUTC) | ||
28 | #define ___hv_halt ___hv_dispatch(HV_DISPATCH_HALT) | ||
29 | #define ___hv_reexec ___hv_dispatch(HV_DISPATCH_REEXEC) | ||
30 | #define ___hv_flush_remote ___hv_dispatch(HV_DISPATCH_FLUSH_REMOTE) | ||
31 | |||
32 | #undef RELOCATE_NEW_KERNEL_VERBOSE | 23 | #undef RELOCATE_NEW_KERNEL_VERBOSE |
33 | 24 | ||
34 | STD_ENTRY(relocate_new_kernel) | 25 | STD_ENTRY(relocate_new_kernel) |
@@ -43,8 +34,8 @@ STD_ENTRY(relocate_new_kernel) | |||
43 | addi sp, sp, -8 | 34 | addi sp, sp, -8 |
44 | /* we now have a stack (whether we need one or not) */ | 35 | /* we now have a stack (whether we need one or not) */ |
45 | 36 | ||
46 | moveli r40, lo16(___hv_console_putc) | 37 | moveli r40, lo16(hv_console_putc) |
47 | auli r40, r40, ha16(___hv_console_putc) | 38 | auli r40, r40, ha16(hv_console_putc) |
48 | 39 | ||
49 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE | 40 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE |
50 | moveli r0, 'r' | 41 | moveli r0, 'r' |
@@ -86,7 +77,6 @@ STD_ENTRY(relocate_new_kernel) | |||
86 | move r30, sp | 77 | move r30, sp |
87 | addi sp, sp, -8 | 78 | addi sp, sp, -8 |
88 | 79 | ||
89 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
90 | /* | 80 | /* |
91 | * On TILEPro, we need to flush all tiles' caches, since we may | 81 | * On TILEPro, we need to flush all tiles' caches, since we may |
92 | * have been doing hash-for-home caching there. Note that we | 82 | * have been doing hash-for-home caching there. Note that we |
@@ -114,15 +104,14 @@ STD_ENTRY(relocate_new_kernel) | |||
114 | } | 104 | } |
115 | { | 105 | { |
116 | move r8, zero /* asids */ | 106 | move r8, zero /* asids */ |
117 | moveli r20, lo16(___hv_flush_remote) | 107 | moveli r20, lo16(hv_flush_remote) |
118 | } | 108 | } |
119 | { | 109 | { |
120 | move r9, zero /* asidcount */ | 110 | move r9, zero /* asidcount */ |
121 | auli r20, r20, ha16(___hv_flush_remote) | 111 | auli r20, r20, ha16(hv_flush_remote) |
122 | } | 112 | } |
123 | 113 | ||
124 | jalr r20 | 114 | jalr r20 |
125 | #endif | ||
126 | 115 | ||
127 | /* r33 is destination pointer, default to zero */ | 116 | /* r33 is destination pointer, default to zero */ |
128 | 117 | ||
@@ -175,8 +164,8 @@ STD_ENTRY(relocate_new_kernel) | |||
175 | move r0, r32 | 164 | move r0, r32 |
176 | moveli r1, 0 /* arg to hv_reexec is 64 bits */ | 165 | moveli r1, 0 /* arg to hv_reexec is 64 bits */ |
177 | 166 | ||
178 | moveli r41, lo16(___hv_reexec) | 167 | moveli r41, lo16(hv_reexec) |
179 | auli r41, r41, ha16(___hv_reexec) | 168 | auli r41, r41, ha16(hv_reexec) |
180 | 169 | ||
181 | jalr r41 | 170 | jalr r41 |
182 | 171 | ||
@@ -267,8 +256,8 @@ STD_ENTRY(relocate_new_kernel) | |||
267 | moveli r0, '\n' | 256 | moveli r0, '\n' |
268 | jalr r40 | 257 | jalr r40 |
269 | .Lhalt: | 258 | .Lhalt: |
270 | moveli r41, lo16(___hv_halt) | 259 | moveli r41, lo16(hv_halt) |
271 | auli r41, r41, ha16(___hv_halt) | 260 | auli r41, r41, ha16(hv_halt) |
272 | 261 | ||
273 | jalr r41 | 262 | jalr r41 |
274 | STD_ENDPROC(relocate_new_kernel) | 263 | STD_ENDPROC(relocate_new_kernel) |
diff --git a/arch/tile/kernel/relocate_kernel_64.S b/arch/tile/kernel/relocate_kernel_64.S index 1c09a4f5a4ea..d9d8cf6176e8 100644 --- a/arch/tile/kernel/relocate_kernel_64.S +++ b/arch/tile/kernel/relocate_kernel_64.S | |||
@@ -34,11 +34,11 @@ STD_ENTRY(relocate_new_kernel) | |||
34 | addi sp, sp, -8 | 34 | addi sp, sp, -8 |
35 | /* we now have a stack (whether we need one or not) */ | 35 | /* we now have a stack (whether we need one or not) */ |
36 | 36 | ||
37 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE | ||
37 | moveli r40, hw2_last(hv_console_putc) | 38 | moveli r40, hw2_last(hv_console_putc) |
38 | shl16insli r40, r40, hw1(hv_console_putc) | 39 | shl16insli r40, r40, hw1(hv_console_putc) |
39 | shl16insli r40, r40, hw0(hv_console_putc) | 40 | shl16insli r40, r40, hw0(hv_console_putc) |
40 | 41 | ||
41 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE | ||
42 | moveli r0, 'r' | 42 | moveli r0, 'r' |
43 | jalr r40 | 43 | jalr r40 |
44 | 44 | ||
@@ -78,7 +78,6 @@ STD_ENTRY(relocate_new_kernel) | |||
78 | move r30, sp | 78 | move r30, sp |
79 | addi sp, sp, -16 | 79 | addi sp, sp, -16 |
80 | 80 | ||
81 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
82 | /* | 81 | /* |
83 | * On TILE-GX, we need to flush all tiles' caches, since we may | 82 | * On TILE-GX, we need to flush all tiles' caches, since we may |
84 | * have been doing hash-for-home caching there. Note that we | 83 | * have been doing hash-for-home caching there. Note that we |
@@ -116,7 +115,6 @@ STD_ENTRY(relocate_new_kernel) | |||
116 | shl16insli r20, r20, hw0(hv_flush_remote) | 115 | shl16insli r20, r20, hw0(hv_flush_remote) |
117 | 116 | ||
118 | jalr r20 | 117 | jalr r20 |
119 | #endif | ||
120 | 118 | ||
121 | /* r33 is destination pointer, default to zero */ | 119 | /* r33 is destination pointer, default to zero */ |
122 | 120 | ||
@@ -176,10 +174,12 @@ STD_ENTRY(relocate_new_kernel) | |||
176 | 174 | ||
177 | /* we should not get here */ | 175 | /* we should not get here */ |
178 | 176 | ||
177 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE | ||
179 | moveli r0, '?' | 178 | moveli r0, '?' |
180 | jalr r40 | 179 | jalr r40 |
181 | moveli r0, '\n' | 180 | moveli r0, '\n' |
182 | jalr r40 | 181 | jalr r40 |
182 | #endif | ||
183 | 183 | ||
184 | j .Lhalt | 184 | j .Lhalt |
185 | 185 | ||
@@ -237,7 +237,9 @@ STD_ENTRY(relocate_new_kernel) | |||
237 | j .Lloop | 237 | j .Lloop |
238 | 238 | ||
239 | 239 | ||
240 | .Lerr: moveli r0, 'e' | 240 | .Lerr: |
241 | #ifdef RELOCATE_NEW_KERNEL_VERBOSE | ||
242 | moveli r0, 'e' | ||
241 | jalr r40 | 243 | jalr r40 |
242 | moveli r0, 'r' | 244 | moveli r0, 'r' |
243 | jalr r40 | 245 | jalr r40 |
@@ -245,6 +247,7 @@ STD_ENTRY(relocate_new_kernel) | |||
245 | jalr r40 | 247 | jalr r40 |
246 | moveli r0, '\n' | 248 | moveli r0, '\n' |
247 | jalr r40 | 249 | jalr r40 |
250 | #endif | ||
248 | .Lhalt: | 251 | .Lhalt: |
249 | moveli r41, hw2_last(hv_halt) | 252 | moveli r41, hw2_last(hv_halt) |
250 | shl16insli r41, r41, hw1(hv_halt) | 253 | shl16insli r41, r41, hw1(hv_halt) |
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c index eceb8344280f..4c34caea9dd3 100644 --- a/arch/tile/kernel/setup.c +++ b/arch/tile/kernel/setup.c | |||
@@ -154,6 +154,65 @@ static int __init setup_maxnodemem(char *str) | |||
154 | } | 154 | } |
155 | early_param("maxnodemem", setup_maxnodemem); | 155 | early_param("maxnodemem", setup_maxnodemem); |
156 | 156 | ||
157 | struct memmap_entry { | ||
158 | u64 addr; /* start of memory segment */ | ||
159 | u64 size; /* size of memory segment */ | ||
160 | }; | ||
161 | static struct memmap_entry memmap_map[64]; | ||
162 | static int memmap_nr; | ||
163 | |||
164 | static void add_memmap_region(u64 addr, u64 size) | ||
165 | { | ||
166 | if (memmap_nr >= ARRAY_SIZE(memmap_map)) { | ||
167 | pr_err("Ooops! Too many entries in the memory map!\n"); | ||
168 | return; | ||
169 | } | ||
170 | memmap_map[memmap_nr].addr = addr; | ||
171 | memmap_map[memmap_nr].size = size; | ||
172 | memmap_nr++; | ||
173 | } | ||
174 | |||
175 | static int __init setup_memmap(char *p) | ||
176 | { | ||
177 | char *oldp; | ||
178 | u64 start_at, mem_size; | ||
179 | |||
180 | if (!p) | ||
181 | return -EINVAL; | ||
182 | |||
183 | if (!strncmp(p, "exactmap", 8)) { | ||
184 | pr_err("\"memmap=exactmap\" not valid on tile\n"); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | oldp = p; | ||
189 | mem_size = memparse(p, &p); | ||
190 | if (p == oldp) | ||
191 | return -EINVAL; | ||
192 | |||
193 | if (*p == '@') { | ||
194 | pr_err("\"memmap=nn@ss\" (force RAM) invalid on tile\n"); | ||
195 | } else if (*p == '#') { | ||
196 | pr_err("\"memmap=nn#ss\" (force ACPI data) invalid on tile\n"); | ||
197 | } else if (*p == '$') { | ||
198 | start_at = memparse(p+1, &p); | ||
199 | add_memmap_region(start_at, mem_size); | ||
200 | } else { | ||
201 | if (mem_size == 0) | ||
202 | return -EINVAL; | ||
203 | maxmem_pfn = (mem_size >> HPAGE_SHIFT) << | ||
204 | (HPAGE_SHIFT - PAGE_SHIFT); | ||
205 | } | ||
206 | return *p == '\0' ? 0 : -EINVAL; | ||
207 | } | ||
208 | early_param("memmap", setup_memmap); | ||
209 | |||
210 | static int __init setup_mem(char *str) | ||
211 | { | ||
212 | return setup_maxmem(str); | ||
213 | } | ||
214 | early_param("mem", setup_mem); /* compatibility with x86 */ | ||
215 | |||
157 | static int __init setup_isolnodes(char *str) | 216 | static int __init setup_isolnodes(char *str) |
158 | { | 217 | { |
159 | char buf[MAX_NUMNODES * 5]; | 218 | char buf[MAX_NUMNODES * 5]; |
@@ -209,7 +268,7 @@ early_param("vmalloc", parse_vmalloc); | |||
209 | /* | 268 | /* |
210 | * Determine for each controller where its lowmem is mapped and how much of | 269 | * Determine for each controller where its lowmem is mapped and how much of |
211 | * it is mapped there. On controller zero, the first few megabytes are | 270 | * it is mapped there. On controller zero, the first few megabytes are |
212 | * already mapped in as code at MEM_SV_INTRPT, so in principle we could | 271 | * already mapped in as code at MEM_SV_START, so in principle we could |
213 | * start our data mappings higher up, but for now we don't bother, to avoid | 272 | * start our data mappings higher up, but for now we don't bother, to avoid |
214 | * additional confusion. | 273 | * additional confusion. |
215 | * | 274 | * |
@@ -614,11 +673,12 @@ static void __init setup_bootmem_allocator_node(int i) | |||
614 | /* | 673 | /* |
615 | * Throw away any memory aliased by the PCI region. | 674 | * Throw away any memory aliased by the PCI region. |
616 | */ | 675 | */ |
617 | if (pci_reserve_start_pfn < end && pci_reserve_end_pfn > start) | 676 | if (pci_reserve_start_pfn < end && pci_reserve_end_pfn > start) { |
618 | reserve_bootmem(PFN_PHYS(pci_reserve_start_pfn), | 677 | start = max(pci_reserve_start_pfn, start); |
619 | PFN_PHYS(pci_reserve_end_pfn - | 678 | end = min(pci_reserve_end_pfn, end); |
620 | pci_reserve_start_pfn), | 679 | reserve_bootmem(PFN_PHYS(start), PFN_PHYS(end - start), |
621 | BOOTMEM_EXCLUSIVE); | 680 | BOOTMEM_EXCLUSIVE); |
681 | } | ||
622 | #endif | 682 | #endif |
623 | } | 683 | } |
624 | 684 | ||
@@ -628,6 +688,31 @@ static void __init setup_bootmem_allocator(void) | |||
628 | for (i = 0; i < MAX_NUMNODES; ++i) | 688 | for (i = 0; i < MAX_NUMNODES; ++i) |
629 | setup_bootmem_allocator_node(i); | 689 | setup_bootmem_allocator_node(i); |
630 | 690 | ||
691 | /* Reserve any memory excluded by "memmap" arguments. */ | ||
692 | for (i = 0; i < memmap_nr; ++i) { | ||
693 | struct memmap_entry *m = &memmap_map[i]; | ||
694 | reserve_bootmem(m->addr, m->size, 0); | ||
695 | } | ||
696 | |||
697 | #ifdef CONFIG_BLK_DEV_INITRD | ||
698 | if (initrd_start) { | ||
699 | /* Make sure the initrd memory region is not modified. */ | ||
700 | if (reserve_bootmem(initrd_start, initrd_end - initrd_start, | ||
701 | BOOTMEM_EXCLUSIVE)) { | ||
702 | pr_crit("The initrd memory region has been polluted. Disabling it.\n"); | ||
703 | initrd_start = 0; | ||
704 | initrd_end = 0; | ||
705 | } else { | ||
706 | /* | ||
707 | * Translate initrd_start & initrd_end from PA to VA for | ||
708 | * future access. | ||
709 | */ | ||
710 | initrd_start += PAGE_OFFSET; | ||
711 | initrd_end += PAGE_OFFSET; | ||
712 | } | ||
713 | } | ||
714 | #endif | ||
715 | |||
631 | #ifdef CONFIG_KEXEC | 716 | #ifdef CONFIG_KEXEC |
632 | if (crashk_res.start != crashk_res.end) | 717 | if (crashk_res.start != crashk_res.end) |
633 | reserve_bootmem(crashk_res.start, resource_size(&crashk_res), 0); | 718 | reserve_bootmem(crashk_res.start, resource_size(&crashk_res), 0); |
@@ -961,9 +1046,6 @@ void setup_cpu(int boot) | |||
961 | arch_local_irq_unmask(INT_DMATLB_MISS); | 1046 | arch_local_irq_unmask(INT_DMATLB_MISS); |
962 | arch_local_irq_unmask(INT_DMATLB_ACCESS); | 1047 | arch_local_irq_unmask(INT_DMATLB_ACCESS); |
963 | #endif | 1048 | #endif |
964 | #if CHIP_HAS_SN_PROC() | ||
965 | arch_local_irq_unmask(INT_SNITLB_MISS); | ||
966 | #endif | ||
967 | #ifdef __tilegx__ | 1049 | #ifdef __tilegx__ |
968 | arch_local_irq_unmask(INT_SINGLE_STEP_K); | 1050 | arch_local_irq_unmask(INT_SINGLE_STEP_K); |
969 | #endif | 1051 | #endif |
@@ -978,10 +1060,6 @@ void setup_cpu(int boot) | |||
978 | /* Static network is not restricted. */ | 1060 | /* Static network is not restricted. */ |
979 | __insn_mtspr(SPR_MPL_SN_ACCESS_SET_0, 1); | 1061 | __insn_mtspr(SPR_MPL_SN_ACCESS_SET_0, 1); |
980 | #endif | 1062 | #endif |
981 | #if CHIP_HAS_SN_PROC() | ||
982 | __insn_mtspr(SPR_MPL_SN_NOTIFY_SET_0, 1); | ||
983 | __insn_mtspr(SPR_MPL_SN_CPL_SET_0, 1); | ||
984 | #endif | ||
985 | 1063 | ||
986 | /* | 1064 | /* |
987 | * Set the MPL for interrupt control 0 & 1 to the corresponding | 1065 | * Set the MPL for interrupt control 0 & 1 to the corresponding |
@@ -1029,6 +1107,10 @@ static void __init load_hv_initrd(void) | |||
1029 | int fd, rc; | 1107 | int fd, rc; |
1030 | void *initrd; | 1108 | void *initrd; |
1031 | 1109 | ||
1110 | /* If initrd has already been set, skip initramfs file in hvfs. */ | ||
1111 | if (initrd_start) | ||
1112 | return; | ||
1113 | |||
1032 | fd = hv_fs_findfile((HV_VirtAddr) initramfs_file); | 1114 | fd = hv_fs_findfile((HV_VirtAddr) initramfs_file); |
1033 | if (fd == HV_ENOENT) { | 1115 | if (fd == HV_ENOENT) { |
1034 | if (set_initramfs_file) { | 1116 | if (set_initramfs_file) { |
@@ -1067,6 +1149,25 @@ void __init free_initrd_mem(unsigned long begin, unsigned long end) | |||
1067 | free_bootmem(__pa(begin), end - begin); | 1149 | free_bootmem(__pa(begin), end - begin); |
1068 | } | 1150 | } |
1069 | 1151 | ||
1152 | static int __init setup_initrd(char *str) | ||
1153 | { | ||
1154 | char *endp; | ||
1155 | unsigned long initrd_size; | ||
1156 | |||
1157 | initrd_size = str ? simple_strtoul(str, &endp, 0) : 0; | ||
1158 | if (initrd_size == 0 || *endp != '@') | ||
1159 | return -EINVAL; | ||
1160 | |||
1161 | initrd_start = simple_strtoul(endp+1, &endp, 0); | ||
1162 | if (initrd_start == 0) | ||
1163 | return -EINVAL; | ||
1164 | |||
1165 | initrd_end = initrd_start + initrd_size; | ||
1166 | |||
1167 | return 0; | ||
1168 | } | ||
1169 | early_param("initrd", setup_initrd); | ||
1170 | |||
1070 | #else | 1171 | #else |
1071 | static inline void load_hv_initrd(void) {} | 1172 | static inline void load_hv_initrd(void) {} |
1072 | #endif /* CONFIG_BLK_DEV_INITRD */ | 1173 | #endif /* CONFIG_BLK_DEV_INITRD */ |
@@ -1134,7 +1235,7 @@ static void __init validate_va(void) | |||
1134 | #ifndef __tilegx__ /* FIXME: GX: probably some validation relevant here */ | 1235 | #ifndef __tilegx__ /* FIXME: GX: probably some validation relevant here */ |
1135 | /* | 1236 | /* |
1136 | * Similarly, make sure we're only using allowed VAs. | 1237 | * Similarly, make sure we're only using allowed VAs. |
1137 | * We assume we can contiguously use MEM_USER_INTRPT .. MEM_HV_INTRPT, | 1238 | * We assume we can contiguously use MEM_USER_INTRPT .. MEM_HV_START, |
1138 | * and 0 .. KERNEL_HIGH_VADDR. | 1239 | * and 0 .. KERNEL_HIGH_VADDR. |
1139 | * In addition, make sure we CAN'T use the end of memory, since | 1240 | * In addition, make sure we CAN'T use the end of memory, since |
1140 | * we use the last chunk of each pgd for the pgd_list. | 1241 | * we use the last chunk of each pgd for the pgd_list. |
@@ -1149,7 +1250,7 @@ static void __init validate_va(void) | |||
1149 | if (range.size == 0) | 1250 | if (range.size == 0) |
1150 | break; | 1251 | break; |
1151 | if (range.start <= MEM_USER_INTRPT && | 1252 | if (range.start <= MEM_USER_INTRPT && |
1152 | range.start + range.size >= MEM_HV_INTRPT) | 1253 | range.start + range.size >= MEM_HV_START) |
1153 | user_kernel_ok = 1; | 1254 | user_kernel_ok = 1; |
1154 | if (range.start == 0) | 1255 | if (range.start == 0) |
1155 | max_va = range.size; | 1256 | max_va = range.size; |
@@ -1183,7 +1284,6 @@ static void __init validate_va(void) | |||
1183 | struct cpumask __write_once cpu_lotar_map; | 1284 | struct cpumask __write_once cpu_lotar_map; |
1184 | EXPORT_SYMBOL(cpu_lotar_map); | 1285 | EXPORT_SYMBOL(cpu_lotar_map); |
1185 | 1286 | ||
1186 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
1187 | /* | 1287 | /* |
1188 | * hash_for_home_map lists all the tiles that hash-for-home data | 1288 | * hash_for_home_map lists all the tiles that hash-for-home data |
1189 | * will be cached on. Note that this may includes tiles that are not | 1289 | * will be cached on. Note that this may includes tiles that are not |
@@ -1193,7 +1293,6 @@ EXPORT_SYMBOL(cpu_lotar_map); | |||
1193 | */ | 1293 | */ |
1194 | struct cpumask hash_for_home_map; | 1294 | struct cpumask hash_for_home_map; |
1195 | EXPORT_SYMBOL(hash_for_home_map); | 1295 | EXPORT_SYMBOL(hash_for_home_map); |
1196 | #endif | ||
1197 | 1296 | ||
1198 | /* | 1297 | /* |
1199 | * cpu_cacheable_map lists all the cpus whose caches the hypervisor can | 1298 | * cpu_cacheable_map lists all the cpus whose caches the hypervisor can |
@@ -1286,7 +1385,6 @@ static void __init setup_cpu_maps(void) | |||
1286 | cpu_lotar_map = *cpu_possible_mask; | 1385 | cpu_lotar_map = *cpu_possible_mask; |
1287 | } | 1386 | } |
1288 | 1387 | ||
1289 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
1290 | /* Retrieve set of CPUs used for hash-for-home caching */ | 1388 | /* Retrieve set of CPUs used for hash-for-home caching */ |
1291 | rc = hv_inquire_tiles(HV_INQ_TILES_HFH_CACHE, | 1389 | rc = hv_inquire_tiles(HV_INQ_TILES_HFH_CACHE, |
1292 | (HV_VirtAddr) hash_for_home_map.bits, | 1390 | (HV_VirtAddr) hash_for_home_map.bits, |
@@ -1294,9 +1392,6 @@ static void __init setup_cpu_maps(void) | |||
1294 | if (rc < 0) | 1392 | if (rc < 0) |
1295 | early_panic("hv_inquire_tiles(HFH_CACHE) failed: rc %d\n", rc); | 1393 | early_panic("hv_inquire_tiles(HFH_CACHE) failed: rc %d\n", rc); |
1296 | cpumask_or(&cpu_cacheable_map, cpu_possible_mask, &hash_for_home_map); | 1394 | cpumask_or(&cpu_cacheable_map, cpu_possible_mask, &hash_for_home_map); |
1297 | #else | ||
1298 | cpu_cacheable_map = *cpu_possible_mask; | ||
1299 | #endif | ||
1300 | } | 1395 | } |
1301 | 1396 | ||
1302 | 1397 | ||
@@ -1492,7 +1587,7 @@ void __init setup_per_cpu_areas(void) | |||
1492 | 1587 | ||
1493 | /* Update the vmalloc mapping and page home. */ | 1588 | /* Update the vmalloc mapping and page home. */ |
1494 | unsigned long addr = (unsigned long)ptr + i; | 1589 | unsigned long addr = (unsigned long)ptr + i; |
1495 | pte_t *ptep = virt_to_pte(NULL, addr); | 1590 | pte_t *ptep = virt_to_kpte(addr); |
1496 | pte_t pte = *ptep; | 1591 | pte_t pte = *ptep; |
1497 | BUG_ON(pfn != pte_pfn(pte)); | 1592 | BUG_ON(pfn != pte_pfn(pte)); |
1498 | pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3); | 1593 | pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3); |
@@ -1501,12 +1596,12 @@ void __init setup_per_cpu_areas(void) | |||
1501 | 1596 | ||
1502 | /* Update the lowmem mapping for consistency. */ | 1597 | /* Update the lowmem mapping for consistency. */ |
1503 | lowmem_va = (unsigned long)pfn_to_kaddr(pfn); | 1598 | lowmem_va = (unsigned long)pfn_to_kaddr(pfn); |
1504 | ptep = virt_to_pte(NULL, lowmem_va); | 1599 | ptep = virt_to_kpte(lowmem_va); |
1505 | if (pte_huge(*ptep)) { | 1600 | if (pte_huge(*ptep)) { |
1506 | printk(KERN_DEBUG "early shatter of huge page" | 1601 | printk(KERN_DEBUG "early shatter of huge page" |
1507 | " at %#lx\n", lowmem_va); | 1602 | " at %#lx\n", lowmem_va); |
1508 | shatter_pmd((pmd_t *)ptep); | 1603 | shatter_pmd((pmd_t *)ptep); |
1509 | ptep = virt_to_pte(NULL, lowmem_va); | 1604 | ptep = virt_to_kpte(lowmem_va); |
1510 | BUG_ON(pte_huge(*ptep)); | 1605 | BUG_ON(pte_huge(*ptep)); |
1511 | } | 1606 | } |
1512 | BUG_ON(pfn != pte_pfn(*ptep)); | 1607 | BUG_ON(pfn != pte_pfn(*ptep)); |
@@ -1548,6 +1643,8 @@ insert_non_bus_resource(void) | |||
1548 | { | 1643 | { |
1549 | struct resource *res = | 1644 | struct resource *res = |
1550 | kzalloc(sizeof(struct resource), GFP_ATOMIC); | 1645 | kzalloc(sizeof(struct resource), GFP_ATOMIC); |
1646 | if (!res) | ||
1647 | return NULL; | ||
1551 | res->name = "Non-Bus Physical Address Space"; | 1648 | res->name = "Non-Bus Physical Address Space"; |
1552 | res->start = (1ULL << 32); | 1649 | res->start = (1ULL << 32); |
1553 | res->end = -1LL; | 1650 | res->end = -1LL; |
@@ -1561,11 +1658,13 @@ insert_non_bus_resource(void) | |||
1561 | #endif | 1658 | #endif |
1562 | 1659 | ||
1563 | static struct resource* __init | 1660 | static struct resource* __init |
1564 | insert_ram_resource(u64 start_pfn, u64 end_pfn) | 1661 | insert_ram_resource(u64 start_pfn, u64 end_pfn, bool reserved) |
1565 | { | 1662 | { |
1566 | struct resource *res = | 1663 | struct resource *res = |
1567 | kzalloc(sizeof(struct resource), GFP_ATOMIC); | 1664 | kzalloc(sizeof(struct resource), GFP_ATOMIC); |
1568 | res->name = "System RAM"; | 1665 | if (!res) |
1666 | return NULL; | ||
1667 | res->name = reserved ? "Reserved" : "System RAM"; | ||
1569 | res->start = start_pfn << PAGE_SHIFT; | 1668 | res->start = start_pfn << PAGE_SHIFT; |
1570 | res->end = (end_pfn << PAGE_SHIFT) - 1; | 1669 | res->end = (end_pfn << PAGE_SHIFT) - 1; |
1571 | res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; | 1670 | res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; |
@@ -1585,7 +1684,7 @@ insert_ram_resource(u64 start_pfn, u64 end_pfn) | |||
1585 | static int __init request_standard_resources(void) | 1684 | static int __init request_standard_resources(void) |
1586 | { | 1685 | { |
1587 | int i; | 1686 | int i; |
1588 | enum { CODE_DELTA = MEM_SV_INTRPT - PAGE_OFFSET }; | 1687 | enum { CODE_DELTA = MEM_SV_START - PAGE_OFFSET }; |
1589 | 1688 | ||
1590 | #if defined(CONFIG_PCI) && !defined(__tilegx__) | 1689 | #if defined(CONFIG_PCI) && !defined(__tilegx__) |
1591 | insert_non_bus_resource(); | 1690 | insert_non_bus_resource(); |
@@ -1600,11 +1699,11 @@ static int __init request_standard_resources(void) | |||
1600 | end_pfn > pci_reserve_start_pfn) { | 1699 | end_pfn > pci_reserve_start_pfn) { |
1601 | if (end_pfn > pci_reserve_end_pfn) | 1700 | if (end_pfn > pci_reserve_end_pfn) |
1602 | insert_ram_resource(pci_reserve_end_pfn, | 1701 | insert_ram_resource(pci_reserve_end_pfn, |
1603 | end_pfn); | 1702 | end_pfn, 0); |
1604 | end_pfn = pci_reserve_start_pfn; | 1703 | end_pfn = pci_reserve_start_pfn; |
1605 | } | 1704 | } |
1606 | #endif | 1705 | #endif |
1607 | insert_ram_resource(start_pfn, end_pfn); | 1706 | insert_ram_resource(start_pfn, end_pfn, 0); |
1608 | } | 1707 | } |
1609 | 1708 | ||
1610 | code_resource.start = __pa(_text - CODE_DELTA); | 1709 | code_resource.start = __pa(_text - CODE_DELTA); |
@@ -1615,6 +1714,13 @@ static int __init request_standard_resources(void) | |||
1615 | insert_resource(&iomem_resource, &code_resource); | 1714 | insert_resource(&iomem_resource, &code_resource); |
1616 | insert_resource(&iomem_resource, &data_resource); | 1715 | insert_resource(&iomem_resource, &data_resource); |
1617 | 1716 | ||
1717 | /* Mark any "memmap" regions busy for the resource manager. */ | ||
1718 | for (i = 0; i < memmap_nr; ++i) { | ||
1719 | struct memmap_entry *m = &memmap_map[i]; | ||
1720 | insert_ram_resource(PFN_DOWN(m->addr), | ||
1721 | PFN_UP(m->addr + m->size - 1), 1); | ||
1722 | } | ||
1723 | |||
1618 | #ifdef CONFIG_KEXEC | 1724 | #ifdef CONFIG_KEXEC |
1619 | insert_resource(&iomem_resource, &crashk_res); | 1725 | insert_resource(&iomem_resource, &crashk_res); |
1620 | #endif | 1726 | #endif |
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c index 9531845bf661..2d1dbf38a9ab 100644 --- a/arch/tile/kernel/signal.c +++ b/arch/tile/kernel/signal.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <asm/ucontext.h> | 33 | #include <asm/ucontext.h> |
34 | #include <asm/sigframe.h> | 34 | #include <asm/sigframe.h> |
35 | #include <asm/syscalls.h> | 35 | #include <asm/syscalls.h> |
36 | #include <asm/vdso.h> | ||
36 | #include <arch/interrupts.h> | 37 | #include <arch/interrupts.h> |
37 | 38 | ||
38 | #define DEBUG_SIG 0 | 39 | #define DEBUG_SIG 0 |
@@ -190,7 +191,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
190 | if (err) | 191 | if (err) |
191 | goto give_sigsegv; | 192 | goto give_sigsegv; |
192 | 193 | ||
193 | restorer = VDSO_BASE; | 194 | restorer = VDSO_SYM(&__vdso_rt_sigreturn); |
194 | if (ka->sa.sa_flags & SA_RESTORER) | 195 | if (ka->sa.sa_flags & SA_RESTORER) |
195 | restorer = (unsigned long) ka->sa.sa_restorer; | 196 | restorer = (unsigned long) ka->sa.sa_restorer; |
196 | 197 | ||
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index 27742e87e255..de07fa7d1315 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c | |||
@@ -12,41 +12,30 @@ | |||
12 | * more details. | 12 | * more details. |
13 | * | 13 | * |
14 | * A code-rewriter that enables instruction single-stepping. | 14 | * A code-rewriter that enables instruction single-stepping. |
15 | * Derived from iLib's single-stepping code. | ||
16 | */ | 15 | */ |
17 | 16 | ||
18 | #ifndef __tilegx__ /* Hardware support for single step unavailable. */ | 17 | #include <linux/smp.h> |
19 | 18 | #include <linux/ptrace.h> | |
20 | /* These functions are only used on the TILE platform */ | ||
21 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
22 | #include <linux/thread_info.h> | 20 | #include <linux/thread_info.h> |
23 | #include <linux/uaccess.h> | 21 | #include <linux/uaccess.h> |
24 | #include <linux/mman.h> | 22 | #include <linux/mman.h> |
25 | #include <linux/types.h> | 23 | #include <linux/types.h> |
26 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/prctl.h> | ||
27 | #include <asm/cacheflush.h> | 26 | #include <asm/cacheflush.h> |
27 | #include <asm/traps.h> | ||
28 | #include <asm/uaccess.h> | ||
28 | #include <asm/unaligned.h> | 29 | #include <asm/unaligned.h> |
29 | #include <arch/abi.h> | 30 | #include <arch/abi.h> |
31 | #include <arch/spr_def.h> | ||
30 | #include <arch/opcode.h> | 32 | #include <arch/opcode.h> |
31 | 33 | ||
32 | #define signExtend17(val) sign_extend((val), 17) | ||
33 | #define TILE_X1_MASK (0xffffffffULL << 31) | ||
34 | |||
35 | int unaligned_printk; | ||
36 | 34 | ||
37 | static int __init setup_unaligned_printk(char *str) | 35 | #ifndef __tilegx__ /* Hardware support for single step unavailable. */ |
38 | { | ||
39 | long val; | ||
40 | if (strict_strtol(str, 0, &val) != 0) | ||
41 | return 0; | ||
42 | unaligned_printk = val; | ||
43 | pr_info("Printk for each unaligned data accesses is %s\n", | ||
44 | unaligned_printk ? "enabled" : "disabled"); | ||
45 | return 1; | ||
46 | } | ||
47 | __setup("unaligned_printk=", setup_unaligned_printk); | ||
48 | 36 | ||
49 | unsigned int unaligned_fixup_count; | 37 | #define signExtend17(val) sign_extend((val), 17) |
38 | #define TILE_X1_MASK (0xffffffffULL << 31) | ||
50 | 39 | ||
51 | enum mem_op { | 40 | enum mem_op { |
52 | MEMOP_NONE, | 41 | MEMOP_NONE, |
@@ -56,12 +45,13 @@ enum mem_op { | |||
56 | MEMOP_STORE_POSTINCR | 45 | MEMOP_STORE_POSTINCR |
57 | }; | 46 | }; |
58 | 47 | ||
59 | static inline tile_bundle_bits set_BrOff_X1(tile_bundle_bits n, s32 offset) | 48 | static inline tilepro_bundle_bits set_BrOff_X1(tilepro_bundle_bits n, |
49 | s32 offset) | ||
60 | { | 50 | { |
61 | tile_bundle_bits result; | 51 | tilepro_bundle_bits result; |
62 | 52 | ||
63 | /* mask out the old offset */ | 53 | /* mask out the old offset */ |
64 | tile_bundle_bits mask = create_BrOff_X1(-1); | 54 | tilepro_bundle_bits mask = create_BrOff_X1(-1); |
65 | result = n & (~mask); | 55 | result = n & (~mask); |
66 | 56 | ||
67 | /* or in the new offset */ | 57 | /* or in the new offset */ |
@@ -70,10 +60,11 @@ static inline tile_bundle_bits set_BrOff_X1(tile_bundle_bits n, s32 offset) | |||
70 | return result; | 60 | return result; |
71 | } | 61 | } |
72 | 62 | ||
73 | static inline tile_bundle_bits move_X1(tile_bundle_bits n, int dest, int src) | 63 | static inline tilepro_bundle_bits move_X1(tilepro_bundle_bits n, int dest, |
64 | int src) | ||
74 | { | 65 | { |
75 | tile_bundle_bits result; | 66 | tilepro_bundle_bits result; |
76 | tile_bundle_bits op; | 67 | tilepro_bundle_bits op; |
77 | 68 | ||
78 | result = n & (~TILE_X1_MASK); | 69 | result = n & (~TILE_X1_MASK); |
79 | 70 | ||
@@ -87,13 +78,13 @@ static inline tile_bundle_bits move_X1(tile_bundle_bits n, int dest, int src) | |||
87 | return result; | 78 | return result; |
88 | } | 79 | } |
89 | 80 | ||
90 | static inline tile_bundle_bits nop_X1(tile_bundle_bits n) | 81 | static inline tilepro_bundle_bits nop_X1(tilepro_bundle_bits n) |
91 | { | 82 | { |
92 | return move_X1(n, TREG_ZERO, TREG_ZERO); | 83 | return move_X1(n, TREG_ZERO, TREG_ZERO); |
93 | } | 84 | } |
94 | 85 | ||
95 | static inline tile_bundle_bits addi_X1( | 86 | static inline tilepro_bundle_bits addi_X1( |
96 | tile_bundle_bits n, int dest, int src, int imm) | 87 | tilepro_bundle_bits n, int dest, int src, int imm) |
97 | { | 88 | { |
98 | n &= ~TILE_X1_MASK; | 89 | n &= ~TILE_X1_MASK; |
99 | 90 | ||
@@ -107,15 +98,26 @@ static inline tile_bundle_bits addi_X1( | |||
107 | return n; | 98 | return n; |
108 | } | 99 | } |
109 | 100 | ||
110 | static tile_bundle_bits rewrite_load_store_unaligned( | 101 | static tilepro_bundle_bits rewrite_load_store_unaligned( |
111 | struct single_step_state *state, | 102 | struct single_step_state *state, |
112 | tile_bundle_bits bundle, | 103 | tilepro_bundle_bits bundle, |
113 | struct pt_regs *regs, | 104 | struct pt_regs *regs, |
114 | enum mem_op mem_op, | 105 | enum mem_op mem_op, |
115 | int size, int sign_ext) | 106 | int size, int sign_ext) |
116 | { | 107 | { |
117 | unsigned char __user *addr; | 108 | unsigned char __user *addr; |
118 | int val_reg, addr_reg, err, val; | 109 | int val_reg, addr_reg, err, val; |
110 | int align_ctl; | ||
111 | |||
112 | align_ctl = unaligned_fixup; | ||
113 | switch (task_thread_info(current)->align_ctl) { | ||
114 | case PR_UNALIGN_NOPRINT: | ||
115 | align_ctl = 1; | ||
116 | break; | ||
117 | case PR_UNALIGN_SIGBUS: | ||
118 | align_ctl = 0; | ||
119 | break; | ||
120 | } | ||
119 | 121 | ||
120 | /* Get address and value registers */ | 122 | /* Get address and value registers */ |
121 | if (bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK) { | 123 | if (bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK) { |
@@ -160,7 +162,7 @@ static tile_bundle_bits rewrite_load_store_unaligned( | |||
160 | * tilepro hardware would be doing, if it could provide us with the | 162 | * tilepro hardware would be doing, if it could provide us with the |
161 | * actual bad address in an SPR, which it doesn't. | 163 | * actual bad address in an SPR, which it doesn't. |
162 | */ | 164 | */ |
163 | if (unaligned_fixup == 0) { | 165 | if (align_ctl == 0) { |
164 | siginfo_t info = { | 166 | siginfo_t info = { |
165 | .si_signo = SIGBUS, | 167 | .si_signo = SIGBUS, |
166 | .si_code = BUS_ADRALN, | 168 | .si_code = BUS_ADRALN, |
@@ -209,14 +211,14 @@ static tile_bundle_bits rewrite_load_store_unaligned( | |||
209 | 211 | ||
210 | if (err) { | 212 | if (err) { |
211 | siginfo_t info = { | 213 | siginfo_t info = { |
212 | .si_signo = SIGSEGV, | 214 | .si_signo = SIGBUS, |
213 | .si_code = SEGV_MAPERR, | 215 | .si_code = BUS_ADRALN, |
214 | .si_addr = addr | 216 | .si_addr = addr |
215 | }; | 217 | }; |
216 | trace_unhandled_signal("segfault", regs, | 218 | trace_unhandled_signal("bad address for unaligned fixup", regs, |
217 | (unsigned long)addr, SIGSEGV); | 219 | (unsigned long)addr, SIGBUS); |
218 | force_sig_info(info.si_signo, &info, current); | 220 | force_sig_info(info.si_signo, &info, current); |
219 | return (tile_bundle_bits) 0; | 221 | return (tilepro_bundle_bits) 0; |
220 | } | 222 | } |
221 | 223 | ||
222 | if (unaligned_printk || unaligned_fixup_count == 0) { | 224 | if (unaligned_printk || unaligned_fixup_count == 0) { |
@@ -285,7 +287,7 @@ void single_step_execve(void) | |||
285 | ti->step_state = NULL; | 287 | ti->step_state = NULL; |
286 | } | 288 | } |
287 | 289 | ||
288 | /** | 290 | /* |
289 | * single_step_once() - entry point when single stepping has been triggered. | 291 | * single_step_once() - entry point when single stepping has been triggered. |
290 | * @regs: The machine register state | 292 | * @regs: The machine register state |
291 | * | 293 | * |
@@ -304,20 +306,31 @@ void single_step_execve(void) | |||
304 | */ | 306 | */ |
305 | void single_step_once(struct pt_regs *regs) | 307 | void single_step_once(struct pt_regs *regs) |
306 | { | 308 | { |
307 | extern tile_bundle_bits __single_step_ill_insn; | 309 | extern tilepro_bundle_bits __single_step_ill_insn; |
308 | extern tile_bundle_bits __single_step_j_insn; | 310 | extern tilepro_bundle_bits __single_step_j_insn; |
309 | extern tile_bundle_bits __single_step_addli_insn; | 311 | extern tilepro_bundle_bits __single_step_addli_insn; |
310 | extern tile_bundle_bits __single_step_auli_insn; | 312 | extern tilepro_bundle_bits __single_step_auli_insn; |
311 | struct thread_info *info = (void *)current_thread_info(); | 313 | struct thread_info *info = (void *)current_thread_info(); |
312 | struct single_step_state *state = info->step_state; | 314 | struct single_step_state *state = info->step_state; |
313 | int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); | 315 | int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); |
314 | tile_bundle_bits __user *buffer, *pc; | 316 | tilepro_bundle_bits __user *buffer, *pc; |
315 | tile_bundle_bits bundle; | 317 | tilepro_bundle_bits bundle; |
316 | int temp_reg; | 318 | int temp_reg; |
317 | int target_reg = TREG_LR; | 319 | int target_reg = TREG_LR; |
318 | int err; | 320 | int err; |
319 | enum mem_op mem_op = MEMOP_NONE; | 321 | enum mem_op mem_op = MEMOP_NONE; |
320 | int size = 0, sign_ext = 0; /* happy compiler */ | 322 | int size = 0, sign_ext = 0; /* happy compiler */ |
323 | int align_ctl; | ||
324 | |||
325 | align_ctl = unaligned_fixup; | ||
326 | switch (task_thread_info(current)->align_ctl) { | ||
327 | case PR_UNALIGN_NOPRINT: | ||
328 | align_ctl = 1; | ||
329 | break; | ||
330 | case PR_UNALIGN_SIGBUS: | ||
331 | align_ctl = 0; | ||
332 | break; | ||
333 | } | ||
321 | 334 | ||
322 | asm( | 335 | asm( |
323 | " .pushsection .rodata.single_step\n" | 336 | " .pushsection .rodata.single_step\n" |
@@ -390,7 +403,7 @@ void single_step_once(struct pt_regs *regs) | |||
390 | if (regs->faultnum == INT_SWINT_1) | 403 | if (regs->faultnum == INT_SWINT_1) |
391 | regs->pc -= 8; | 404 | regs->pc -= 8; |
392 | 405 | ||
393 | pc = (tile_bundle_bits __user *)(regs->pc); | 406 | pc = (tilepro_bundle_bits __user *)(regs->pc); |
394 | if (get_user(bundle, pc) != 0) { | 407 | if (get_user(bundle, pc) != 0) { |
395 | pr_err("Couldn't read instruction at %p trying to step\n", pc); | 408 | pr_err("Couldn't read instruction at %p trying to step\n", pc); |
396 | return; | 409 | return; |
@@ -533,7 +546,6 @@ void single_step_once(struct pt_regs *regs) | |||
533 | } | 546 | } |
534 | break; | 547 | break; |
535 | 548 | ||
536 | #if CHIP_HAS_WH64() | ||
537 | /* postincrement operations */ | 549 | /* postincrement operations */ |
538 | case IMM_0_OPCODE_X1: | 550 | case IMM_0_OPCODE_X1: |
539 | switch (get_ImmOpcodeExtension_X1(bundle)) { | 551 | switch (get_ImmOpcodeExtension_X1(bundle)) { |
@@ -568,7 +580,6 @@ void single_step_once(struct pt_regs *regs) | |||
568 | break; | 580 | break; |
569 | } | 581 | } |
570 | break; | 582 | break; |
571 | #endif /* CHIP_HAS_WH64() */ | ||
572 | } | 583 | } |
573 | 584 | ||
574 | if (state->update) { | 585 | if (state->update) { |
@@ -627,9 +638,9 @@ void single_step_once(struct pt_regs *regs) | |||
627 | 638 | ||
628 | /* | 639 | /* |
629 | * Check if we need to rewrite an unaligned load/store. | 640 | * Check if we need to rewrite an unaligned load/store. |
630 | * Returning zero is a special value meaning we need to SIGSEGV. | 641 | * Returning zero is a special value meaning we generated a signal. |
631 | */ | 642 | */ |
632 | if (mem_op != MEMOP_NONE && unaligned_fixup >= 0) { | 643 | if (mem_op != MEMOP_NONE && align_ctl >= 0) { |
633 | bundle = rewrite_load_store_unaligned(state, bundle, regs, | 644 | bundle = rewrite_load_store_unaligned(state, bundle, regs, |
634 | mem_op, size, sign_ext); | 645 | mem_op, size, sign_ext); |
635 | if (bundle == 0) | 646 | if (bundle == 0) |
@@ -668,9 +679,9 @@ void single_step_once(struct pt_regs *regs) | |||
668 | } | 679 | } |
669 | 680 | ||
670 | /* End with a jump back to the next instruction */ | 681 | /* End with a jump back to the next instruction */ |
671 | delta = ((regs->pc + TILE_BUNDLE_SIZE_IN_BYTES) - | 682 | delta = ((regs->pc + TILEPRO_BUNDLE_SIZE_IN_BYTES) - |
672 | (unsigned long)buffer) >> | 683 | (unsigned long)buffer) >> |
673 | TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES; | 684 | TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES; |
674 | bundle = __single_step_j_insn; | 685 | bundle = __single_step_j_insn; |
675 | bundle |= create_JOffLong_X1(delta); | 686 | bundle |= create_JOffLong_X1(delta); |
676 | err |= __put_user(bundle, buffer++); | 687 | err |= __put_user(bundle, buffer++); |
@@ -698,9 +709,6 @@ void single_step_once(struct pt_regs *regs) | |||
698 | } | 709 | } |
699 | 710 | ||
700 | #else | 711 | #else |
701 | #include <linux/smp.h> | ||
702 | #include <linux/ptrace.h> | ||
703 | #include <arch/spr_def.h> | ||
704 | 712 | ||
705 | static DEFINE_PER_CPU(unsigned long, ss_saved_pc); | 713 | static DEFINE_PER_CPU(unsigned long, ss_saved_pc); |
706 | 714 | ||
@@ -743,10 +751,10 @@ void gx_singlestep_handle(struct pt_regs *regs, int fault_num) | |||
743 | } else if ((*ss_pc != regs->pc) || | 751 | } else if ((*ss_pc != regs->pc) || |
744 | (!(control & SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK))) { | 752 | (!(control & SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK))) { |
745 | 753 | ||
746 | ptrace_notify(SIGTRAP); | ||
747 | control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK; | 754 | control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK; |
748 | control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK; | 755 | control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK; |
749 | __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); | 756 | __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); |
757 | send_sigtrap(current, regs); | ||
750 | } | 758 | } |
751 | } | 759 | } |
752 | 760 | ||
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c index cbc73a8b8fe1..01e8ab29f43a 100644 --- a/arch/tile/kernel/smp.c +++ b/arch/tile/kernel/smp.c | |||
@@ -20,8 +20,13 @@ | |||
20 | #include <linux/irq.h> | 20 | #include <linux/irq.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <asm/cacheflush.h> | 22 | #include <asm/cacheflush.h> |
23 | #include <asm/homecache.h> | ||
23 | 24 | ||
24 | HV_Topology smp_topology __write_once; | 25 | /* |
26 | * We write to width and height with a single store in head_NN.S, | ||
27 | * so make the variable aligned to "long". | ||
28 | */ | ||
29 | HV_Topology smp_topology __write_once __aligned(sizeof(long)); | ||
25 | EXPORT_SYMBOL(smp_topology); | 30 | EXPORT_SYMBOL(smp_topology); |
26 | 31 | ||
27 | #if CHIP_HAS_IPI() | 32 | #if CHIP_HAS_IPI() |
@@ -100,8 +105,8 @@ static void smp_start_cpu_interrupt(void) | |||
100 | /* Handler to stop the current cpu. */ | 105 | /* Handler to stop the current cpu. */ |
101 | static void smp_stop_cpu_interrupt(void) | 106 | static void smp_stop_cpu_interrupt(void) |
102 | { | 107 | { |
103 | set_cpu_online(smp_processor_id(), 0); | ||
104 | arch_local_irq_disable_all(); | 108 | arch_local_irq_disable_all(); |
109 | set_cpu_online(smp_processor_id(), 0); | ||
105 | for (;;) | 110 | for (;;) |
106 | asm("nap; nop"); | 111 | asm("nap; nop"); |
107 | } | 112 | } |
@@ -167,9 +172,16 @@ static void ipi_flush_icache_range(void *info) | |||
167 | void flush_icache_range(unsigned long start, unsigned long end) | 172 | void flush_icache_range(unsigned long start, unsigned long end) |
168 | { | 173 | { |
169 | struct ipi_flush flush = { start, end }; | 174 | struct ipi_flush flush = { start, end }; |
170 | preempt_disable(); | 175 | |
171 | on_each_cpu(ipi_flush_icache_range, &flush, 1); | 176 | /* If invoked with irqs disabled, we can not issue IPIs. */ |
172 | preempt_enable(); | 177 | if (irqs_disabled()) |
178 | flush_remote(0, HV_FLUSH_EVICT_L1I, NULL, 0, 0, 0, | ||
179 | NULL, NULL, 0); | ||
180 | else { | ||
181 | preempt_disable(); | ||
182 | on_each_cpu(ipi_flush_icache_range, &flush, 1); | ||
183 | preempt_enable(); | ||
184 | } | ||
173 | } | 185 | } |
174 | 186 | ||
175 | 187 | ||
diff --git a/arch/tile/kernel/smpboot.c b/arch/tile/kernel/smpboot.c index a535655b7089..732e9d138661 100644 --- a/arch/tile/kernel/smpboot.c +++ b/arch/tile/kernel/smpboot.c | |||
@@ -142,13 +142,15 @@ static struct cpumask cpu_started; | |||
142 | */ | 142 | */ |
143 | static void start_secondary(void) | 143 | static void start_secondary(void) |
144 | { | 144 | { |
145 | int cpuid = smp_processor_id(); | 145 | int cpuid; |
146 | |||
147 | preempt_disable(); | ||
148 | |||
149 | cpuid = smp_processor_id(); | ||
146 | 150 | ||
147 | /* Set our thread pointer appropriately. */ | 151 | /* Set our thread pointer appropriately. */ |
148 | set_my_cpu_offset(__per_cpu_offset[cpuid]); | 152 | set_my_cpu_offset(__per_cpu_offset[cpuid]); |
149 | 153 | ||
150 | preempt_disable(); | ||
151 | |||
152 | /* | 154 | /* |
153 | * In large machines even this will slow us down, since we | 155 | * In large machines even this will slow us down, since we |
154 | * will be contending for for the printk spinlock. | 156 | * will be contending for for the printk spinlock. |
diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c index af8dfc9665f6..362284af3afd 100644 --- a/arch/tile/kernel/stack.c +++ b/arch/tile/kernel/stack.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <asm/switch_to.h> | 29 | #include <asm/switch_to.h> |
30 | #include <asm/sigframe.h> | 30 | #include <asm/sigframe.h> |
31 | #include <asm/stack.h> | 31 | #include <asm/stack.h> |
32 | #include <asm/vdso.h> | ||
32 | #include <arch/abi.h> | 33 | #include <arch/abi.h> |
33 | #include <arch/interrupts.h> | 34 | #include <arch/interrupts.h> |
34 | 35 | ||
@@ -102,9 +103,8 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt) | |||
102 | p->sp >= sp) { | 103 | p->sp >= sp) { |
103 | if (kbt->verbose) | 104 | if (kbt->verbose) |
104 | pr_err(" <%s while in kernel mode>\n", fault); | 105 | pr_err(" <%s while in kernel mode>\n", fault); |
105 | } else if (EX1_PL(p->ex1) == USER_PL && | 106 | } else if (user_mode(p) && |
106 | p->pc < PAGE_OFFSET && | 107 | p->sp < PAGE_OFFSET && p->sp != 0) { |
107 | p->sp < PAGE_OFFSET) { | ||
108 | if (kbt->verbose) | 108 | if (kbt->verbose) |
109 | pr_err(" <%s while in user mode>\n", fault); | 109 | pr_err(" <%s while in user mode>\n", fault); |
110 | } else if (kbt->verbose) { | 110 | } else if (kbt->verbose) { |
@@ -120,7 +120,7 @@ static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt) | |||
120 | /* Is the pc pointing to a sigreturn trampoline? */ | 120 | /* Is the pc pointing to a sigreturn trampoline? */ |
121 | static int is_sigreturn(unsigned long pc) | 121 | static int is_sigreturn(unsigned long pc) |
122 | { | 122 | { |
123 | return (pc == VDSO_BASE); | 123 | return current->mm && (pc == VDSO_SYM(&__vdso_rt_sigreturn)); |
124 | } | 124 | } |
125 | 125 | ||
126 | /* Return a pt_regs pointer for a valid signal handler frame */ | 126 | /* Return a pt_regs pointer for a valid signal handler frame */ |
@@ -129,7 +129,7 @@ static struct pt_regs *valid_sigframe(struct KBacktraceIterator* kbt, | |||
129 | { | 129 | { |
130 | BacktraceIterator *b = &kbt->it; | 130 | BacktraceIterator *b = &kbt->it; |
131 | 131 | ||
132 | if (b->pc == VDSO_BASE && b->sp < PAGE_OFFSET && | 132 | if (is_sigreturn(b->pc) && b->sp < PAGE_OFFSET && |
133 | b->sp % sizeof(long) == 0) { | 133 | b->sp % sizeof(long) == 0) { |
134 | int retval; | 134 | int retval; |
135 | pagefault_disable(); | 135 | pagefault_disable(); |
@@ -195,21 +195,21 @@ static int KBacktraceIterator_next_item_inclusive( | |||
195 | */ | 195 | */ |
196 | static void validate_stack(struct pt_regs *regs) | 196 | static void validate_stack(struct pt_regs *regs) |
197 | { | 197 | { |
198 | int cpu = smp_processor_id(); | 198 | int cpu = raw_smp_processor_id(); |
199 | unsigned long ksp0 = get_current_ksp0(); | 199 | unsigned long ksp0 = get_current_ksp0(); |
200 | unsigned long ksp0_base = ksp0 - THREAD_SIZE; | 200 | unsigned long ksp0_base = ksp0 & -THREAD_SIZE; |
201 | unsigned long sp = stack_pointer; | 201 | unsigned long sp = stack_pointer; |
202 | 202 | ||
203 | if (EX1_PL(regs->ex1) == KERNEL_PL && regs->sp >= ksp0) { | 203 | if (EX1_PL(regs->ex1) == KERNEL_PL && regs->sp >= ksp0) { |
204 | pr_err("WARNING: cpu %d: kernel stack page %#lx underrun!\n" | 204 | pr_err("WARNING: cpu %d: kernel stack %#lx..%#lx underrun!\n" |
205 | " sp %#lx (%#lx in caller), caller pc %#lx, lr %#lx\n", | 205 | " sp %#lx (%#lx in caller), caller pc %#lx, lr %#lx\n", |
206 | cpu, ksp0_base, sp, regs->sp, regs->pc, regs->lr); | 206 | cpu, ksp0_base, ksp0, sp, regs->sp, regs->pc, regs->lr); |
207 | } | 207 | } |
208 | 208 | ||
209 | else if (sp < ksp0_base + sizeof(struct thread_info)) { | 209 | else if (sp < ksp0_base + sizeof(struct thread_info)) { |
210 | pr_err("WARNING: cpu %d: kernel stack page %#lx overrun!\n" | 210 | pr_err("WARNING: cpu %d: kernel stack %#lx..%#lx overrun!\n" |
211 | " sp %#lx (%#lx in caller), caller pc %#lx, lr %#lx\n", | 211 | " sp %#lx (%#lx in caller), caller pc %#lx, lr %#lx\n", |
212 | cpu, ksp0_base, sp, regs->sp, regs->pc, regs->lr); | 212 | cpu, ksp0_base, ksp0, sp, regs->sp, regs->pc, regs->lr); |
213 | } | 213 | } |
214 | } | 214 | } |
215 | 215 | ||
@@ -352,6 +352,26 @@ static void describe_addr(struct KBacktraceIterator *kbt, | |||
352 | } | 352 | } |
353 | 353 | ||
354 | /* | 354 | /* |
355 | * Avoid possible crash recursion during backtrace. If it happens, it | ||
356 | * makes it easy to lose the actual root cause of the failure, so we | ||
357 | * put a simple guard on all the backtrace loops. | ||
358 | */ | ||
359 | static bool start_backtrace(void) | ||
360 | { | ||
361 | if (current->thread.in_backtrace) { | ||
362 | pr_err("Backtrace requested while in backtrace!\n"); | ||
363 | return false; | ||
364 | } | ||
365 | current->thread.in_backtrace = true; | ||
366 | return true; | ||
367 | } | ||
368 | |||
369 | static void end_backtrace(void) | ||
370 | { | ||
371 | current->thread.in_backtrace = false; | ||
372 | } | ||
373 | |||
374 | /* | ||
355 | * This method wraps the backtracer's more generic support. | 375 | * This method wraps the backtracer's more generic support. |
356 | * It is only invoked from the architecture-specific code; show_stack() | 376 | * It is only invoked from the architecture-specific code; show_stack() |
357 | * and dump_stack() (in entry.S) are architecture-independent entry points. | 377 | * and dump_stack() (in entry.S) are architecture-independent entry points. |
@@ -361,6 +381,8 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers) | |||
361 | int i; | 381 | int i; |
362 | int have_mmap_sem = 0; | 382 | int have_mmap_sem = 0; |
363 | 383 | ||
384 | if (!start_backtrace()) | ||
385 | return; | ||
364 | if (headers) { | 386 | if (headers) { |
365 | /* | 387 | /* |
366 | * Add a blank line since if we are called from panic(), | 388 | * Add a blank line since if we are called from panic(), |
@@ -371,7 +393,7 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers) | |||
371 | pr_err("Starting stack dump of tid %d, pid %d (%s)" | 393 | pr_err("Starting stack dump of tid %d, pid %d (%s)" |
372 | " on cpu %d at cycle %lld\n", | 394 | " on cpu %d at cycle %lld\n", |
373 | kbt->task->pid, kbt->task->tgid, kbt->task->comm, | 395 | kbt->task->pid, kbt->task->tgid, kbt->task->comm, |
374 | smp_processor_id(), get_cycles()); | 396 | raw_smp_processor_id(), get_cycles()); |
375 | } | 397 | } |
376 | kbt->verbose = 1; | 398 | kbt->verbose = 1; |
377 | i = 0; | 399 | i = 0; |
@@ -402,6 +424,7 @@ void tile_show_stack(struct KBacktraceIterator *kbt, int headers) | |||
402 | pr_err("Stack dump complete\n"); | 424 | pr_err("Stack dump complete\n"); |
403 | if (have_mmap_sem) | 425 | if (have_mmap_sem) |
404 | up_read(&kbt->task->mm->mmap_sem); | 426 | up_read(&kbt->task->mm->mmap_sem); |
427 | end_backtrace(); | ||
405 | } | 428 | } |
406 | EXPORT_SYMBOL(tile_show_stack); | 429 | EXPORT_SYMBOL(tile_show_stack); |
407 | 430 | ||
@@ -463,6 +486,8 @@ void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace) | |||
463 | int skip = trace->skip; | 486 | int skip = trace->skip; |
464 | int i = 0; | 487 | int i = 0; |
465 | 488 | ||
489 | if (!start_backtrace()) | ||
490 | goto done; | ||
466 | if (task == NULL || task == current) | 491 | if (task == NULL || task == current) |
467 | KBacktraceIterator_init_current(&kbt); | 492 | KBacktraceIterator_init_current(&kbt); |
468 | else | 493 | else |
@@ -476,6 +501,8 @@ void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace) | |||
476 | break; | 501 | break; |
477 | trace->entries[i++] = kbt.it.pc; | 502 | trace->entries[i++] = kbt.it.pc; |
478 | } | 503 | } |
504 | end_backtrace(); | ||
505 | done: | ||
479 | trace->nr_entries = i; | 506 | trace->nr_entries = i; |
480 | } | 507 | } |
481 | EXPORT_SYMBOL(save_stack_trace_tsk); | 508 | EXPORT_SYMBOL(save_stack_trace_tsk); |
diff --git a/arch/tile/kernel/sys.c b/arch/tile/kernel/sys.c index b881a7be24bd..38debe706061 100644 --- a/arch/tile/kernel/sys.c +++ b/arch/tile/kernel/sys.c | |||
@@ -38,8 +38,10 @@ | |||
38 | SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, len, | 38 | SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, len, |
39 | unsigned long, flags) | 39 | unsigned long, flags) |
40 | { | 40 | { |
41 | /* DCACHE is not particularly effective if not bound to one cpu. */ | ||
41 | if (flags & DCACHE) | 42 | if (flags & DCACHE) |
42 | homecache_evict(cpumask_of(smp_processor_id())); | 43 | homecache_evict(cpumask_of(raw_smp_processor_id())); |
44 | |||
43 | if (flags & ICACHE) | 45 | if (flags & ICACHE) |
44 | flush_remote(0, HV_FLUSH_EVICT_L1I, mm_cpumask(current->mm), | 46 | flush_remote(0, HV_FLUSH_EVICT_L1I, mm_cpumask(current->mm), |
45 | 0, 0, 0, NULL, NULL, 0); | 47 | 0, 0, 0, NULL, NULL, 0); |
diff --git a/arch/tile/kernel/sysfs.c b/arch/tile/kernel/sysfs.c index e25b0a89c18f..a3ed12f8f83b 100644 --- a/arch/tile/kernel/sysfs.c +++ b/arch/tile/kernel/sysfs.c | |||
@@ -157,6 +157,67 @@ hvconfig_bin_read(struct file *filp, struct kobject *kobj, | |||
157 | return count; | 157 | return count; |
158 | } | 158 | } |
159 | 159 | ||
160 | static ssize_t hv_stats_show(struct device *dev, | ||
161 | struct device_attribute *attr, | ||
162 | char *page) | ||
163 | { | ||
164 | int cpu = dev->id; | ||
165 | long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu)); | ||
166 | |||
167 | ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, | ||
168 | (unsigned long)page, PAGE_SIZE - 1, | ||
169 | lotar, 0); | ||
170 | n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1); | ||
171 | page[n] = '\0'; | ||
172 | return n; | ||
173 | } | ||
174 | |||
175 | static ssize_t hv_stats_store(struct device *dev, | ||
176 | struct device_attribute *attr, | ||
177 | const char *page, | ||
178 | size_t count) | ||
179 | { | ||
180 | int cpu = dev->id; | ||
181 | long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu)); | ||
182 | |||
183 | ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, 0, 0, lotar, 1); | ||
184 | return n < 0 ? n : count; | ||
185 | } | ||
186 | |||
187 | static DEVICE_ATTR(hv_stats, 0644, hv_stats_show, hv_stats_store); | ||
188 | |||
189 | static int hv_stats_device_add(struct device *dev, struct subsys_interface *sif) | ||
190 | { | ||
191 | int err, cpu = dev->id; | ||
192 | |||
193 | if (!cpu_online(cpu)) | ||
194 | return 0; | ||
195 | |||
196 | err = sysfs_create_file(&dev->kobj, &dev_attr_hv_stats.attr); | ||
197 | |||
198 | return err; | ||
199 | } | ||
200 | |||
201 | static int hv_stats_device_remove(struct device *dev, | ||
202 | struct subsys_interface *sif) | ||
203 | { | ||
204 | int cpu = dev->id; | ||
205 | |||
206 | if (!cpu_online(cpu)) | ||
207 | return 0; | ||
208 | |||
209 | sysfs_remove_file(&dev->kobj, &dev_attr_hv_stats.attr); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | |||
214 | static struct subsys_interface hv_stats_interface = { | ||
215 | .name = "hv_stats", | ||
216 | .subsys = &cpu_subsys, | ||
217 | .add_dev = hv_stats_device_add, | ||
218 | .remove_dev = hv_stats_device_remove, | ||
219 | }; | ||
220 | |||
160 | static int __init create_sysfs_entries(void) | 221 | static int __init create_sysfs_entries(void) |
161 | { | 222 | { |
162 | int err = 0; | 223 | int err = 0; |
@@ -188,6 +249,21 @@ static int __init create_sysfs_entries(void) | |||
188 | err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin); | 249 | err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin); |
189 | } | 250 | } |
190 | 251 | ||
252 | if (!err) { | ||
253 | /* | ||
254 | * Don't bother adding the hv_stats files on each CPU if | ||
255 | * our hypervisor doesn't supply statistics. | ||
256 | */ | ||
257 | int cpu = raw_smp_processor_id(); | ||
258 | long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu)); | ||
259 | char dummy; | ||
260 | ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, | ||
261 | (unsigned long) &dummy, 1, | ||
262 | lotar, 0); | ||
263 | if (n >= 0) | ||
264 | err = subsys_interface_register(&hv_stats_interface); | ||
265 | } | ||
266 | |||
191 | return err; | 267 | return err; |
192 | } | 268 | } |
193 | subsys_initcall(create_sysfs_entries); | 269 | subsys_initcall(create_sysfs_entries); |
diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c index 7c353d8c2da9..5d10642db63e 100644 --- a/arch/tile/kernel/time.c +++ b/arch/tile/kernel/time.c | |||
@@ -23,8 +23,10 @@ | |||
23 | #include <linux/smp.h> | 23 | #include <linux/smp.h> |
24 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
25 | #include <linux/module.h> | 25 | #include <linux/module.h> |
26 | #include <linux/timekeeper_internal.h> | ||
26 | #include <asm/irq_regs.h> | 27 | #include <asm/irq_regs.h> |
27 | #include <asm/traps.h> | 28 | #include <asm/traps.h> |
29 | #include <asm/vdso.h> | ||
28 | #include <hv/hypervisor.h> | 30 | #include <hv/hypervisor.h> |
29 | #include <arch/interrupts.h> | 31 | #include <arch/interrupts.h> |
30 | #include <arch/spr_def.h> | 32 | #include <arch/spr_def.h> |
@@ -110,7 +112,6 @@ void __init time_init(void) | |||
110 | setup_tile_timer(); | 112 | setup_tile_timer(); |
111 | } | 113 | } |
112 | 114 | ||
113 | |||
114 | /* | 115 | /* |
115 | * Define the tile timer clock event device. The timer is driven by | 116 | * Define the tile timer clock event device. The timer is driven by |
116 | * the TILE_TIMER_CONTROL register, which consists of a 31-bit down | 117 | * the TILE_TIMER_CONTROL register, which consists of a 31-bit down |
@@ -237,3 +238,37 @@ cycles_t ns2cycles(unsigned long nsecs) | |||
237 | struct clock_event_device *dev = &__raw_get_cpu_var(tile_timer); | 238 | struct clock_event_device *dev = &__raw_get_cpu_var(tile_timer); |
238 | return ((u64)nsecs * dev->mult) >> dev->shift; | 239 | return ((u64)nsecs * dev->mult) >> dev->shift; |
239 | } | 240 | } |
241 | |||
242 | void update_vsyscall_tz(void) | ||
243 | { | ||
244 | /* Userspace gettimeofday will spin while this value is odd. */ | ||
245 | ++vdso_data->tz_update_count; | ||
246 | smp_wmb(); | ||
247 | vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; | ||
248 | vdso_data->tz_dsttime = sys_tz.tz_dsttime; | ||
249 | smp_wmb(); | ||
250 | ++vdso_data->tz_update_count; | ||
251 | } | ||
252 | |||
253 | void update_vsyscall(struct timekeeper *tk) | ||
254 | { | ||
255 | struct timespec wall_time = tk_xtime(tk); | ||
256 | struct timespec *wtm = &tk->wall_to_monotonic; | ||
257 | struct clocksource *clock = tk->clock; | ||
258 | |||
259 | if (clock != &cycle_counter_cs) | ||
260 | return; | ||
261 | |||
262 | /* Userspace gettimeofday will spin while this value is odd. */ | ||
263 | ++vdso_data->tb_update_count; | ||
264 | smp_wmb(); | ||
265 | vdso_data->xtime_tod_stamp = clock->cycle_last; | ||
266 | vdso_data->xtime_clock_sec = wall_time.tv_sec; | ||
267 | vdso_data->xtime_clock_nsec = wall_time.tv_nsec; | ||
268 | vdso_data->wtom_clock_sec = wtm->tv_sec; | ||
269 | vdso_data->wtom_clock_nsec = wtm->tv_nsec; | ||
270 | vdso_data->mult = clock->mult; | ||
271 | vdso_data->shift = clock->shift; | ||
272 | smp_wmb(); | ||
273 | ++vdso_data->tb_update_count; | ||
274 | } | ||
diff --git a/arch/tile/kernel/tlb.c b/arch/tile/kernel/tlb.c index 3fd54d5bbd4c..f23b53515671 100644 --- a/arch/tile/kernel/tlb.c +++ b/arch/tile/kernel/tlb.c | |||
@@ -91,8 +91,14 @@ void flush_tlb_all(void) | |||
91 | } | 91 | } |
92 | } | 92 | } |
93 | 93 | ||
94 | /* | ||
95 | * Callers need to flush the L1I themselves if necessary, e.g. for | ||
96 | * kernel module unload. Otherwise we assume callers are not using | ||
97 | * executable pgprot_t's. Using EVICT_L1I means that dataplane cpus | ||
98 | * will get an unnecessary interrupt otherwise. | ||
99 | */ | ||
94 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) | 100 | void flush_tlb_kernel_range(unsigned long start, unsigned long end) |
95 | { | 101 | { |
96 | flush_remote(0, HV_FLUSH_EVICT_L1I, cpu_online_mask, | 102 | flush_remote(0, 0, NULL, |
97 | start, end - start, PAGE_SIZE, cpu_online_mask, NULL, 0); | 103 | start, end - start, PAGE_SIZE, cpu_online_mask, NULL, 0); |
98 | } | 104 | } |
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index 5b19a23c8908..6b603d556ca6 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
16 | #include <linux/kernel.h> | 16 | #include <linux/kernel.h> |
17 | #include <linux/kprobes.h> | 17 | #include <linux/kprobes.h> |
18 | #include <linux/kdebug.h> | ||
18 | #include <linux/module.h> | 19 | #include <linux/module.h> |
19 | #include <linux/reboot.h> | 20 | #include <linux/reboot.h> |
20 | #include <linux/uaccess.h> | 21 | #include <linux/uaccess.h> |
@@ -29,7 +30,7 @@ | |||
29 | 30 | ||
30 | void __init trap_init(void) | 31 | void __init trap_init(void) |
31 | { | 32 | { |
32 | /* Nothing needed here since we link code at .intrpt1 */ | 33 | /* Nothing needed here since we link code at .intrpt */ |
33 | } | 34 | } |
34 | 35 | ||
35 | int unaligned_fixup = 1; | 36 | int unaligned_fixup = 1; |
@@ -100,13 +101,7 @@ static int retry_gpv(unsigned int gpv_reason) | |||
100 | 101 | ||
101 | #endif /* CHIP_HAS_TILE_DMA() */ | 102 | #endif /* CHIP_HAS_TILE_DMA() */ |
102 | 103 | ||
103 | #ifdef __tilegx__ | 104 | extern tile_bundle_bits bpt_code; |
104 | #define bundle_bits tilegx_bundle_bits | ||
105 | #else | ||
106 | #define bundle_bits tile_bundle_bits | ||
107 | #endif | ||
108 | |||
109 | extern bundle_bits bpt_code; | ||
110 | 105 | ||
111 | asm(".pushsection .rodata.bpt_code,\"a\";" | 106 | asm(".pushsection .rodata.bpt_code,\"a\";" |
112 | ".align 8;" | 107 | ".align 8;" |
@@ -114,7 +109,7 @@ asm(".pushsection .rodata.bpt_code,\"a\";" | |||
114 | ".size bpt_code,.-bpt_code;" | 109 | ".size bpt_code,.-bpt_code;" |
115 | ".popsection"); | 110 | ".popsection"); |
116 | 111 | ||
117 | static int special_ill(bundle_bits bundle, int *sigp, int *codep) | 112 | static int special_ill(tile_bundle_bits bundle, int *sigp, int *codep) |
118 | { | 113 | { |
119 | int sig, code, maxcode; | 114 | int sig, code, maxcode; |
120 | 115 | ||
@@ -214,24 +209,73 @@ static const char *const int_name[] = { | |||
214 | #endif | 209 | #endif |
215 | }; | 210 | }; |
216 | 211 | ||
212 | static int do_bpt(struct pt_regs *regs) | ||
213 | { | ||
214 | unsigned long bundle, bcode, bpt; | ||
215 | |||
216 | bundle = *(unsigned long *)instruction_pointer(regs); | ||
217 | |||
218 | /* | ||
219 | * bpt shoule be { bpt; nop }, which is 0x286a44ae51485000ULL. | ||
220 | * we encode the unused least significant bits for other purpose. | ||
221 | */ | ||
222 | bpt = bundle & ~((1ULL << 12) - 1); | ||
223 | if (bpt != TILE_BPT_BUNDLE) | ||
224 | return 0; | ||
225 | |||
226 | bcode = bundle & ((1ULL << 12) - 1); | ||
227 | /* | ||
228 | * notify the kprobe handlers, if instruction is likely to | ||
229 | * pertain to them. | ||
230 | */ | ||
231 | switch (bcode) { | ||
232 | /* breakpoint_insn */ | ||
233 | case 0: | ||
234 | notify_die(DIE_BREAK, "debug", regs, bundle, | ||
235 | INT_ILL, SIGTRAP); | ||
236 | break; | ||
237 | /* compiled_bpt */ | ||
238 | case DIE_COMPILED_BPT: | ||
239 | notify_die(DIE_COMPILED_BPT, "debug", regs, bundle, | ||
240 | INT_ILL, SIGTRAP); | ||
241 | break; | ||
242 | /* breakpoint2_insn */ | ||
243 | case DIE_SSTEPBP: | ||
244 | notify_die(DIE_SSTEPBP, "single_step", regs, bundle, | ||
245 | INT_ILL, SIGTRAP); | ||
246 | break; | ||
247 | default: | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | return 1; | ||
252 | } | ||
253 | |||
217 | void __kprobes do_trap(struct pt_regs *regs, int fault_num, | 254 | void __kprobes do_trap(struct pt_regs *regs, int fault_num, |
218 | unsigned long reason) | 255 | unsigned long reason) |
219 | { | 256 | { |
220 | siginfo_t info = { 0 }; | 257 | siginfo_t info = { 0 }; |
221 | int signo, code; | 258 | int signo, code; |
222 | unsigned long address = 0; | 259 | unsigned long address = 0; |
223 | bundle_bits instr; | 260 | tile_bundle_bits instr; |
261 | int is_kernel = !user_mode(regs); | ||
262 | |||
263 | /* Handle breakpoints, etc. */ | ||
264 | if (is_kernel && fault_num == INT_ILL && do_bpt(regs)) | ||
265 | return; | ||
224 | 266 | ||
225 | /* Re-enable interrupts. */ | 267 | /* Re-enable interrupts, if they were previously enabled. */ |
226 | local_irq_enable(); | 268 | if (!(regs->flags & PT_FLAGS_DISABLE_IRQ)) |
269 | local_irq_enable(); | ||
227 | 270 | ||
228 | /* | 271 | /* |
229 | * If it hits in kernel mode and we can't fix it up, just exit the | 272 | * If it hits in kernel mode and we can't fix it up, just exit the |
230 | * current process and hope for the best. | 273 | * current process and hope for the best. |
231 | */ | 274 | */ |
232 | if (!user_mode(regs)) { | 275 | if (is_kernel) { |
233 | const char *name; | 276 | const char *name; |
234 | if (fixup_exception(regs)) /* only UNALIGN_DATA in practice */ | 277 | char buf[100]; |
278 | if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */ | ||
235 | return; | 279 | return; |
236 | if (fault_num >= 0 && | 280 | if (fault_num >= 0 && |
237 | fault_num < sizeof(int_name)/sizeof(int_name[0]) && | 281 | fault_num < sizeof(int_name)/sizeof(int_name[0]) && |
@@ -239,10 +283,16 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
239 | name = int_name[fault_num]; | 283 | name = int_name[fault_num]; |
240 | else | 284 | else |
241 | name = "Unknown interrupt"; | 285 | name = "Unknown interrupt"; |
242 | pr_alert("Kernel took bad trap %d (%s) at PC %#lx\n", | ||
243 | fault_num, name, regs->pc); | ||
244 | if (fault_num == INT_GPV) | 286 | if (fault_num == INT_GPV) |
245 | pr_alert("GPV_REASON is %#lx\n", reason); | 287 | snprintf(buf, sizeof(buf), "; GPV_REASON %#lx", reason); |
288 | #ifdef __tilegx__ | ||
289 | else if (fault_num == INT_ILL_TRANS) | ||
290 | snprintf(buf, sizeof(buf), "; address %#lx", reason); | ||
291 | #endif | ||
292 | else | ||
293 | buf[0] = '\0'; | ||
294 | pr_alert("Kernel took bad trap %d (%s) at PC %#lx%s\n", | ||
295 | fault_num, name, regs->pc, buf); | ||
246 | show_regs(regs); | 296 | show_regs(regs); |
247 | do_exit(SIGKILL); /* FIXME: implement i386 die() */ | 297 | do_exit(SIGKILL); /* FIXME: implement i386 die() */ |
248 | return; | 298 | return; |
@@ -324,11 +374,8 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
324 | fill_ra_stack(); | 374 | fill_ra_stack(); |
325 | 375 | ||
326 | signo = SIGSEGV; | 376 | signo = SIGSEGV; |
377 | address = reason; | ||
327 | code = SEGV_MAPERR; | 378 | code = SEGV_MAPERR; |
328 | if (reason & SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK) | ||
329 | address = regs->pc; | ||
330 | else | ||
331 | address = 0; /* FIXME: GX: single-step for address */ | ||
332 | break; | 379 | break; |
333 | } | 380 | } |
334 | #endif | 381 | #endif |
diff --git a/arch/tile/kernel/unaligned.c b/arch/tile/kernel/unaligned.c new file mode 100644 index 000000000000..b425fb6a480d --- /dev/null +++ b/arch/tile/kernel/unaligned.c | |||
@@ -0,0 +1,1609 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * A code-rewriter that handles unaligned exception. | ||
15 | */ | ||
16 | |||
17 | #include <linux/smp.h> | ||
18 | #include <linux/ptrace.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/thread_info.h> | ||
21 | #include <linux/uaccess.h> | ||
22 | #include <linux/mman.h> | ||
23 | #include <linux/types.h> | ||
24 | #include <linux/err.h> | ||
25 | #include <linux/module.h> | ||
26 | #include <linux/compat.h> | ||
27 | #include <linux/prctl.h> | ||
28 | #include <asm/cacheflush.h> | ||
29 | #include <asm/traps.h> | ||
30 | #include <asm/uaccess.h> | ||
31 | #include <asm/unaligned.h> | ||
32 | #include <arch/abi.h> | ||
33 | #include <arch/spr_def.h> | ||
34 | #include <arch/opcode.h> | ||
35 | |||
36 | |||
37 | /* | ||
38 | * This file handles unaligned exception for tile-Gx. The tilepro's unaligned | ||
39 | * exception is supported out of single_step.c | ||
40 | */ | ||
41 | |||
42 | int unaligned_printk; | ||
43 | |||
44 | static int __init setup_unaligned_printk(char *str) | ||
45 | { | ||
46 | long val; | ||
47 | if (kstrtol(str, 0, &val) != 0) | ||
48 | return 0; | ||
49 | unaligned_printk = val; | ||
50 | pr_info("Printk for each unaligned data accesses is %s\n", | ||
51 | unaligned_printk ? "enabled" : "disabled"); | ||
52 | return 1; | ||
53 | } | ||
54 | __setup("unaligned_printk=", setup_unaligned_printk); | ||
55 | |||
56 | unsigned int unaligned_fixup_count; | ||
57 | |||
58 | #ifdef __tilegx__ | ||
59 | |||
60 | /* | ||
61 | * Unalign data jit fixup code fragement. Reserved space is 128 bytes. | ||
62 | * The 1st 64-bit word saves fault PC address, 2nd word is the fault | ||
63 | * instruction bundle followed by 14 JIT bundles. | ||
64 | */ | ||
65 | |||
66 | struct unaligned_jit_fragment { | ||
67 | unsigned long pc; | ||
68 | tilegx_bundle_bits bundle; | ||
69 | tilegx_bundle_bits insn[14]; | ||
70 | }; | ||
71 | |||
72 | /* | ||
73 | * Check if a nop or fnop at bundle's pipeline X0. | ||
74 | */ | ||
75 | |||
76 | static bool is_bundle_x0_nop(tilegx_bundle_bits bundle) | ||
77 | { | ||
78 | return (((get_UnaryOpcodeExtension_X0(bundle) == | ||
79 | NOP_UNARY_OPCODE_X0) && | ||
80 | (get_RRROpcodeExtension_X0(bundle) == | ||
81 | UNARY_RRR_0_OPCODE_X0) && | ||
82 | (get_Opcode_X0(bundle) == | ||
83 | RRR_0_OPCODE_X0)) || | ||
84 | ((get_UnaryOpcodeExtension_X0(bundle) == | ||
85 | FNOP_UNARY_OPCODE_X0) && | ||
86 | (get_RRROpcodeExtension_X0(bundle) == | ||
87 | UNARY_RRR_0_OPCODE_X0) && | ||
88 | (get_Opcode_X0(bundle) == | ||
89 | RRR_0_OPCODE_X0))); | ||
90 | } | ||
91 | |||
92 | /* | ||
93 | * Check if nop or fnop at bundle's pipeline X1. | ||
94 | */ | ||
95 | |||
96 | static bool is_bundle_x1_nop(tilegx_bundle_bits bundle) | ||
97 | { | ||
98 | return (((get_UnaryOpcodeExtension_X1(bundle) == | ||
99 | NOP_UNARY_OPCODE_X1) && | ||
100 | (get_RRROpcodeExtension_X1(bundle) == | ||
101 | UNARY_RRR_0_OPCODE_X1) && | ||
102 | (get_Opcode_X1(bundle) == | ||
103 | RRR_0_OPCODE_X1)) || | ||
104 | ((get_UnaryOpcodeExtension_X1(bundle) == | ||
105 | FNOP_UNARY_OPCODE_X1) && | ||
106 | (get_RRROpcodeExtension_X1(bundle) == | ||
107 | UNARY_RRR_0_OPCODE_X1) && | ||
108 | (get_Opcode_X1(bundle) == | ||
109 | RRR_0_OPCODE_X1))); | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Check if nop or fnop at bundle's Y0 pipeline. | ||
114 | */ | ||
115 | |||
116 | static bool is_bundle_y0_nop(tilegx_bundle_bits bundle) | ||
117 | { | ||
118 | return (((get_UnaryOpcodeExtension_Y0(bundle) == | ||
119 | NOP_UNARY_OPCODE_Y0) && | ||
120 | (get_RRROpcodeExtension_Y0(bundle) == | ||
121 | UNARY_RRR_1_OPCODE_Y0) && | ||
122 | (get_Opcode_Y0(bundle) == | ||
123 | RRR_1_OPCODE_Y0)) || | ||
124 | ((get_UnaryOpcodeExtension_Y0(bundle) == | ||
125 | FNOP_UNARY_OPCODE_Y0) && | ||
126 | (get_RRROpcodeExtension_Y0(bundle) == | ||
127 | UNARY_RRR_1_OPCODE_Y0) && | ||
128 | (get_Opcode_Y0(bundle) == | ||
129 | RRR_1_OPCODE_Y0))); | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * Check if nop or fnop at bundle's pipeline Y1. | ||
134 | */ | ||
135 | |||
136 | static bool is_bundle_y1_nop(tilegx_bundle_bits bundle) | ||
137 | { | ||
138 | return (((get_UnaryOpcodeExtension_Y1(bundle) == | ||
139 | NOP_UNARY_OPCODE_Y1) && | ||
140 | (get_RRROpcodeExtension_Y1(bundle) == | ||
141 | UNARY_RRR_1_OPCODE_Y1) && | ||
142 | (get_Opcode_Y1(bundle) == | ||
143 | RRR_1_OPCODE_Y1)) || | ||
144 | ((get_UnaryOpcodeExtension_Y1(bundle) == | ||
145 | FNOP_UNARY_OPCODE_Y1) && | ||
146 | (get_RRROpcodeExtension_Y1(bundle) == | ||
147 | UNARY_RRR_1_OPCODE_Y1) && | ||
148 | (get_Opcode_Y1(bundle) == | ||
149 | RRR_1_OPCODE_Y1))); | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * Test if a bundle's y0 and y1 pipelines are both nop or fnop. | ||
154 | */ | ||
155 | |||
156 | static bool is_y0_y1_nop(tilegx_bundle_bits bundle) | ||
157 | { | ||
158 | return is_bundle_y0_nop(bundle) && is_bundle_y1_nop(bundle); | ||
159 | } | ||
160 | |||
161 | /* | ||
162 | * Test if a bundle's x0 and x1 pipelines are both nop or fnop. | ||
163 | */ | ||
164 | |||
165 | static bool is_x0_x1_nop(tilegx_bundle_bits bundle) | ||
166 | { | ||
167 | return is_bundle_x0_nop(bundle) && is_bundle_x1_nop(bundle); | ||
168 | } | ||
169 | |||
170 | /* | ||
171 | * Find the destination, source registers of fault unalign access instruction | ||
172 | * at X1 or Y2. Also, allocate up to 3 scratch registers clob1, clob2 and | ||
173 | * clob3, which are guaranteed different from any register used in the fault | ||
174 | * bundle. r_alias is used to return if the other instructions other than the | ||
175 | * unalign load/store shares same register with ra, rb and rd. | ||
176 | */ | ||
177 | |||
178 | static void find_regs(tilegx_bundle_bits bundle, uint64_t *rd, uint64_t *ra, | ||
179 | uint64_t *rb, uint64_t *clob1, uint64_t *clob2, | ||
180 | uint64_t *clob3, bool *r_alias) | ||
181 | { | ||
182 | int i; | ||
183 | uint64_t reg; | ||
184 | uint64_t reg_map = 0, alias_reg_map = 0, map; | ||
185 | bool alias; | ||
186 | |||
187 | *ra = -1; | ||
188 | *rb = -1; | ||
189 | |||
190 | if (rd) | ||
191 | *rd = -1; | ||
192 | |||
193 | *clob1 = -1; | ||
194 | *clob2 = -1; | ||
195 | *clob3 = -1; | ||
196 | alias = false; | ||
197 | |||
198 | /* | ||
199 | * Parse fault bundle, find potential used registers and mark | ||
200 | * corresponding bits in reg_map and alias_map. These 2 bit maps | ||
201 | * are used to find the scratch registers and determine if there | ||
202 | * is register alais. | ||
203 | */ | ||
204 | if (bundle & TILEGX_BUNDLE_MODE_MASK) { /* Y Mode Bundle. */ | ||
205 | |||
206 | reg = get_SrcA_Y2(bundle); | ||
207 | reg_map |= 1ULL << reg; | ||
208 | *ra = reg; | ||
209 | reg = get_SrcBDest_Y2(bundle); | ||
210 | reg_map |= 1ULL << reg; | ||
211 | |||
212 | if (rd) { | ||
213 | /* Load. */ | ||
214 | *rd = reg; | ||
215 | alias_reg_map = (1ULL << *rd) | (1ULL << *ra); | ||
216 | } else { | ||
217 | /* Store. */ | ||
218 | *rb = reg; | ||
219 | alias_reg_map = (1ULL << *ra) | (1ULL << *rb); | ||
220 | } | ||
221 | |||
222 | if (!is_bundle_y1_nop(bundle)) { | ||
223 | reg = get_SrcA_Y1(bundle); | ||
224 | reg_map |= (1ULL << reg); | ||
225 | map = (1ULL << reg); | ||
226 | |||
227 | reg = get_SrcB_Y1(bundle); | ||
228 | reg_map |= (1ULL << reg); | ||
229 | map |= (1ULL << reg); | ||
230 | |||
231 | reg = get_Dest_Y1(bundle); | ||
232 | reg_map |= (1ULL << reg); | ||
233 | map |= (1ULL << reg); | ||
234 | |||
235 | if (map & alias_reg_map) | ||
236 | alias = true; | ||
237 | } | ||
238 | |||
239 | if (!is_bundle_y0_nop(bundle)) { | ||
240 | reg = get_SrcA_Y0(bundle); | ||
241 | reg_map |= (1ULL << reg); | ||
242 | map = (1ULL << reg); | ||
243 | |||
244 | reg = get_SrcB_Y0(bundle); | ||
245 | reg_map |= (1ULL << reg); | ||
246 | map |= (1ULL << reg); | ||
247 | |||
248 | reg = get_Dest_Y0(bundle); | ||
249 | reg_map |= (1ULL << reg); | ||
250 | map |= (1ULL << reg); | ||
251 | |||
252 | if (map & alias_reg_map) | ||
253 | alias = true; | ||
254 | } | ||
255 | } else { /* X Mode Bundle. */ | ||
256 | |||
257 | reg = get_SrcA_X1(bundle); | ||
258 | reg_map |= (1ULL << reg); | ||
259 | *ra = reg; | ||
260 | if (rd) { | ||
261 | /* Load. */ | ||
262 | reg = get_Dest_X1(bundle); | ||
263 | reg_map |= (1ULL << reg); | ||
264 | *rd = reg; | ||
265 | alias_reg_map = (1ULL << *rd) | (1ULL << *ra); | ||
266 | } else { | ||
267 | /* Store. */ | ||
268 | reg = get_SrcB_X1(bundle); | ||
269 | reg_map |= (1ULL << reg); | ||
270 | *rb = reg; | ||
271 | alias_reg_map = (1ULL << *ra) | (1ULL << *rb); | ||
272 | } | ||
273 | |||
274 | if (!is_bundle_x0_nop(bundle)) { | ||
275 | reg = get_SrcA_X0(bundle); | ||
276 | reg_map |= (1ULL << reg); | ||
277 | map = (1ULL << reg); | ||
278 | |||
279 | reg = get_SrcB_X0(bundle); | ||
280 | reg_map |= (1ULL << reg); | ||
281 | map |= (1ULL << reg); | ||
282 | |||
283 | reg = get_Dest_X0(bundle); | ||
284 | reg_map |= (1ULL << reg); | ||
285 | map |= (1ULL << reg); | ||
286 | |||
287 | if (map & alias_reg_map) | ||
288 | alias = true; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | /* | ||
293 | * "alias" indicates if the unalign access registers have collision | ||
294 | * with others in the same bundle. We jsut simply test all register | ||
295 | * operands case (RRR), ignored the case with immidate. If a bundle | ||
296 | * has no register alias, we may do fixup in a simple or fast manner. | ||
297 | * So if an immidata field happens to hit with a register, we may end | ||
298 | * up fall back to the generic handling. | ||
299 | */ | ||
300 | |||
301 | *r_alias = alias; | ||
302 | |||
303 | /* Flip bits on reg_map. */ | ||
304 | reg_map ^= -1ULL; | ||
305 | |||
306 | /* Scan reg_map lower 54(TREG_SP) bits to find 3 set bits. */ | ||
307 | for (i = 0; i < TREG_SP; i++) { | ||
308 | if (reg_map & (0x1ULL << i)) { | ||
309 | if (*clob1 == -1) { | ||
310 | *clob1 = i; | ||
311 | } else if (*clob2 == -1) { | ||
312 | *clob2 = i; | ||
313 | } else if (*clob3 == -1) { | ||
314 | *clob3 = i; | ||
315 | return; | ||
316 | } | ||
317 | } | ||
318 | } | ||
319 | } | ||
320 | |||
321 | /* | ||
322 | * Sanity check for register ra, rb, rd, clob1/2/3. Return true if any of them | ||
323 | * is unexpected. | ||
324 | */ | ||
325 | |||
326 | static bool check_regs(uint64_t rd, uint64_t ra, uint64_t rb, | ||
327 | uint64_t clob1, uint64_t clob2, uint64_t clob3) | ||
328 | { | ||
329 | bool unexpected = false; | ||
330 | if ((ra >= 56) && (ra != TREG_ZERO)) | ||
331 | unexpected = true; | ||
332 | |||
333 | if ((clob1 >= 56) || (clob2 >= 56) || (clob3 >= 56)) | ||
334 | unexpected = true; | ||
335 | |||
336 | if (rd != -1) { | ||
337 | if ((rd >= 56) && (rd != TREG_ZERO)) | ||
338 | unexpected = true; | ||
339 | } else { | ||
340 | if ((rb >= 56) && (rb != TREG_ZERO)) | ||
341 | unexpected = true; | ||
342 | } | ||
343 | return unexpected; | ||
344 | } | ||
345 | |||
346 | |||
347 | #define GX_INSN_X0_MASK ((1ULL << 31) - 1) | ||
348 | #define GX_INSN_X1_MASK (((1ULL << 31) - 1) << 31) | ||
349 | #define GX_INSN_Y0_MASK ((0xFULL << 27) | (0xFFFFFULL)) | ||
350 | #define GX_INSN_Y1_MASK (GX_INSN_Y0_MASK << 31) | ||
351 | #define GX_INSN_Y2_MASK ((0x7FULL << 51) | (0x7FULL << 20)) | ||
352 | |||
353 | #ifdef __LITTLE_ENDIAN | ||
354 | #define GX_INSN_BSWAP(_bundle_) (_bundle_) | ||
355 | #else | ||
356 | #define GX_INSN_BSWAP(_bundle_) swab64(_bundle_) | ||
357 | #endif /* __LITTLE_ENDIAN */ | ||
358 | |||
359 | /* | ||
360 | * __JIT_CODE(.) creates template bundles in .rodata.unalign_data section. | ||
361 | * The corresponding static function jix_x#_###(.) generates partial or | ||
362 | * whole bundle based on the template and given arguments. | ||
363 | */ | ||
364 | |||
365 | #define __JIT_CODE(_X_) \ | ||
366 | asm (".pushsection .rodata.unalign_data, \"a\"\n" \ | ||
367 | _X_"\n" \ | ||
368 | ".popsection\n") | ||
369 | |||
370 | __JIT_CODE("__unalign_jit_x1_mtspr: {mtspr 0, r0}"); | ||
371 | static tilegx_bundle_bits jit_x1_mtspr(int spr, int reg) | ||
372 | { | ||
373 | extern tilegx_bundle_bits __unalign_jit_x1_mtspr; | ||
374 | return (GX_INSN_BSWAP(__unalign_jit_x1_mtspr) & GX_INSN_X1_MASK) | | ||
375 | create_MT_Imm14_X1(spr) | create_SrcA_X1(reg); | ||
376 | } | ||
377 | |||
378 | __JIT_CODE("__unalign_jit_x1_mfspr: {mfspr r0, 0}"); | ||
379 | static tilegx_bundle_bits jit_x1_mfspr(int reg, int spr) | ||
380 | { | ||
381 | extern tilegx_bundle_bits __unalign_jit_x1_mfspr; | ||
382 | return (GX_INSN_BSWAP(__unalign_jit_x1_mfspr) & GX_INSN_X1_MASK) | | ||
383 | create_MF_Imm14_X1(spr) | create_Dest_X1(reg); | ||
384 | } | ||
385 | |||
386 | __JIT_CODE("__unalign_jit_x0_addi: {addi r0, r0, 0; iret}"); | ||
387 | static tilegx_bundle_bits jit_x0_addi(int rd, int ra, int imm8) | ||
388 | { | ||
389 | extern tilegx_bundle_bits __unalign_jit_x0_addi; | ||
390 | return (GX_INSN_BSWAP(__unalign_jit_x0_addi) & GX_INSN_X0_MASK) | | ||
391 | create_Dest_X0(rd) | create_SrcA_X0(ra) | | ||
392 | create_Imm8_X0(imm8); | ||
393 | } | ||
394 | |||
395 | __JIT_CODE("__unalign_jit_x1_ldna: {ldna r0, r0}"); | ||
396 | static tilegx_bundle_bits jit_x1_ldna(int rd, int ra) | ||
397 | { | ||
398 | extern tilegx_bundle_bits __unalign_jit_x1_ldna; | ||
399 | return (GX_INSN_BSWAP(__unalign_jit_x1_ldna) & GX_INSN_X1_MASK) | | ||
400 | create_Dest_X1(rd) | create_SrcA_X1(ra); | ||
401 | } | ||
402 | |||
403 | __JIT_CODE("__unalign_jit_x0_dblalign: {dblalign r0, r0 ,r0}"); | ||
404 | static tilegx_bundle_bits jit_x0_dblalign(int rd, int ra, int rb) | ||
405 | { | ||
406 | extern tilegx_bundle_bits __unalign_jit_x0_dblalign; | ||
407 | return (GX_INSN_BSWAP(__unalign_jit_x0_dblalign) & GX_INSN_X0_MASK) | | ||
408 | create_Dest_X0(rd) | create_SrcA_X0(ra) | | ||
409 | create_SrcB_X0(rb); | ||
410 | } | ||
411 | |||
412 | __JIT_CODE("__unalign_jit_x1_iret: {iret}"); | ||
413 | static tilegx_bundle_bits jit_x1_iret(void) | ||
414 | { | ||
415 | extern tilegx_bundle_bits __unalign_jit_x1_iret; | ||
416 | return GX_INSN_BSWAP(__unalign_jit_x1_iret) & GX_INSN_X1_MASK; | ||
417 | } | ||
418 | |||
419 | __JIT_CODE("__unalign_jit_x01_fnop: {fnop;fnop}"); | ||
420 | static tilegx_bundle_bits jit_x0_fnop(void) | ||
421 | { | ||
422 | extern tilegx_bundle_bits __unalign_jit_x01_fnop; | ||
423 | return GX_INSN_BSWAP(__unalign_jit_x01_fnop) & GX_INSN_X0_MASK; | ||
424 | } | ||
425 | |||
426 | static tilegx_bundle_bits jit_x1_fnop(void) | ||
427 | { | ||
428 | extern tilegx_bundle_bits __unalign_jit_x01_fnop; | ||
429 | return GX_INSN_BSWAP(__unalign_jit_x01_fnop) & GX_INSN_X1_MASK; | ||
430 | } | ||
431 | |||
432 | __JIT_CODE("__unalign_jit_y2_dummy: {fnop; fnop; ld zero, sp}"); | ||
433 | static tilegx_bundle_bits jit_y2_dummy(void) | ||
434 | { | ||
435 | extern tilegx_bundle_bits __unalign_jit_y2_dummy; | ||
436 | return GX_INSN_BSWAP(__unalign_jit_y2_dummy) & GX_INSN_Y2_MASK; | ||
437 | } | ||
438 | |||
439 | static tilegx_bundle_bits jit_y1_fnop(void) | ||
440 | { | ||
441 | extern tilegx_bundle_bits __unalign_jit_y2_dummy; | ||
442 | return GX_INSN_BSWAP(__unalign_jit_y2_dummy) & GX_INSN_Y1_MASK; | ||
443 | } | ||
444 | |||
445 | __JIT_CODE("__unalign_jit_x1_st1_add: {st1_add r1, r0, 0}"); | ||
446 | static tilegx_bundle_bits jit_x1_st1_add(int ra, int rb, int imm8) | ||
447 | { | ||
448 | extern tilegx_bundle_bits __unalign_jit_x1_st1_add; | ||
449 | return (GX_INSN_BSWAP(__unalign_jit_x1_st1_add) & | ||
450 | (~create_SrcA_X1(-1)) & | ||
451 | GX_INSN_X1_MASK) | create_SrcA_X1(ra) | | ||
452 | create_SrcB_X1(rb) | create_Dest_Imm8_X1(imm8); | ||
453 | } | ||
454 | |||
455 | __JIT_CODE("__unalign_jit_x1_st: {crc32_8 r1, r0, r0; st r0, r0}"); | ||
456 | static tilegx_bundle_bits jit_x1_st(int ra, int rb) | ||
457 | { | ||
458 | extern tilegx_bundle_bits __unalign_jit_x1_st; | ||
459 | return (GX_INSN_BSWAP(__unalign_jit_x1_st) & GX_INSN_X1_MASK) | | ||
460 | create_SrcA_X1(ra) | create_SrcB_X1(rb); | ||
461 | } | ||
462 | |||
463 | __JIT_CODE("__unalign_jit_x1_st_add: {st_add r1, r0, 0}"); | ||
464 | static tilegx_bundle_bits jit_x1_st_add(int ra, int rb, int imm8) | ||
465 | { | ||
466 | extern tilegx_bundle_bits __unalign_jit_x1_st_add; | ||
467 | return (GX_INSN_BSWAP(__unalign_jit_x1_st_add) & | ||
468 | (~create_SrcA_X1(-1)) & | ||
469 | GX_INSN_X1_MASK) | create_SrcA_X1(ra) | | ||
470 | create_SrcB_X1(rb) | create_Dest_Imm8_X1(imm8); | ||
471 | } | ||
472 | |||
473 | __JIT_CODE("__unalign_jit_x1_ld: {crc32_8 r1, r0, r0; ld r0, r0}"); | ||
474 | static tilegx_bundle_bits jit_x1_ld(int rd, int ra) | ||
475 | { | ||
476 | extern tilegx_bundle_bits __unalign_jit_x1_ld; | ||
477 | return (GX_INSN_BSWAP(__unalign_jit_x1_ld) & GX_INSN_X1_MASK) | | ||
478 | create_Dest_X1(rd) | create_SrcA_X1(ra); | ||
479 | } | ||
480 | |||
481 | __JIT_CODE("__unalign_jit_x1_ld_add: {ld_add r1, r0, 0}"); | ||
482 | static tilegx_bundle_bits jit_x1_ld_add(int rd, int ra, int imm8) | ||
483 | { | ||
484 | extern tilegx_bundle_bits __unalign_jit_x1_ld_add; | ||
485 | return (GX_INSN_BSWAP(__unalign_jit_x1_ld_add) & | ||
486 | (~create_Dest_X1(-1)) & | ||
487 | GX_INSN_X1_MASK) | create_Dest_X1(rd) | | ||
488 | create_SrcA_X1(ra) | create_Imm8_X1(imm8); | ||
489 | } | ||
490 | |||
491 | __JIT_CODE("__unalign_jit_x0_bfexts: {bfexts r0, r0, 0, 0}"); | ||
492 | static tilegx_bundle_bits jit_x0_bfexts(int rd, int ra, int bfs, int bfe) | ||
493 | { | ||
494 | extern tilegx_bundle_bits __unalign_jit_x0_bfexts; | ||
495 | return (GX_INSN_BSWAP(__unalign_jit_x0_bfexts) & | ||
496 | GX_INSN_X0_MASK) | | ||
497 | create_Dest_X0(rd) | create_SrcA_X0(ra) | | ||
498 | create_BFStart_X0(bfs) | create_BFEnd_X0(bfe); | ||
499 | } | ||
500 | |||
501 | __JIT_CODE("__unalign_jit_x0_bfextu: {bfextu r0, r0, 0, 0}"); | ||
502 | static tilegx_bundle_bits jit_x0_bfextu(int rd, int ra, int bfs, int bfe) | ||
503 | { | ||
504 | extern tilegx_bundle_bits __unalign_jit_x0_bfextu; | ||
505 | return (GX_INSN_BSWAP(__unalign_jit_x0_bfextu) & | ||
506 | GX_INSN_X0_MASK) | | ||
507 | create_Dest_X0(rd) | create_SrcA_X0(ra) | | ||
508 | create_BFStart_X0(bfs) | create_BFEnd_X0(bfe); | ||
509 | } | ||
510 | |||
511 | __JIT_CODE("__unalign_jit_x1_addi: {bfextu r1, r1, 0, 0; addi r0, r0, 0}"); | ||
512 | static tilegx_bundle_bits jit_x1_addi(int rd, int ra, int imm8) | ||
513 | { | ||
514 | extern tilegx_bundle_bits __unalign_jit_x1_addi; | ||
515 | return (GX_INSN_BSWAP(__unalign_jit_x1_addi) & GX_INSN_X1_MASK) | | ||
516 | create_Dest_X1(rd) | create_SrcA_X1(ra) | | ||
517 | create_Imm8_X1(imm8); | ||
518 | } | ||
519 | |||
520 | __JIT_CODE("__unalign_jit_x0_shrui: {shrui r0, r0, 0; iret}"); | ||
521 | static tilegx_bundle_bits jit_x0_shrui(int rd, int ra, int imm6) | ||
522 | { | ||
523 | extern tilegx_bundle_bits __unalign_jit_x0_shrui; | ||
524 | return (GX_INSN_BSWAP(__unalign_jit_x0_shrui) & | ||
525 | GX_INSN_X0_MASK) | | ||
526 | create_Dest_X0(rd) | create_SrcA_X0(ra) | | ||
527 | create_ShAmt_X0(imm6); | ||
528 | } | ||
529 | |||
530 | __JIT_CODE("__unalign_jit_x0_rotli: {rotli r0, r0, 0; iret}"); | ||
531 | static tilegx_bundle_bits jit_x0_rotli(int rd, int ra, int imm6) | ||
532 | { | ||
533 | extern tilegx_bundle_bits __unalign_jit_x0_rotli; | ||
534 | return (GX_INSN_BSWAP(__unalign_jit_x0_rotli) & | ||
535 | GX_INSN_X0_MASK) | | ||
536 | create_Dest_X0(rd) | create_SrcA_X0(ra) | | ||
537 | create_ShAmt_X0(imm6); | ||
538 | } | ||
539 | |||
540 | __JIT_CODE("__unalign_jit_x1_bnezt: {bnezt r0, __unalign_jit_x1_bnezt}"); | ||
541 | static tilegx_bundle_bits jit_x1_bnezt(int ra, int broff) | ||
542 | { | ||
543 | extern tilegx_bundle_bits __unalign_jit_x1_bnezt; | ||
544 | return (GX_INSN_BSWAP(__unalign_jit_x1_bnezt) & | ||
545 | GX_INSN_X1_MASK) | | ||
546 | create_SrcA_X1(ra) | create_BrOff_X1(broff); | ||
547 | } | ||
548 | |||
549 | #undef __JIT_CODE | ||
550 | |||
551 | /* | ||
552 | * This function generates unalign fixup JIT. | ||
553 | * | ||
554 | * We fist find unalign load/store instruction's destination, source | ||
555 | * reguisters: ra, rb and rd. and 3 scratch registers by calling | ||
556 | * find_regs(...). 3 scratch clobbers should not alias with any register | ||
557 | * used in the fault bundle. Then analyze the fault bundle to determine | ||
558 | * if it's a load or store, operand width, branch or address increment etc. | ||
559 | * At last generated JIT is copied into JIT code area in user space. | ||
560 | */ | ||
561 | |||
562 | static | ||
563 | void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle, | ||
564 | int align_ctl) | ||
565 | { | ||
566 | struct thread_info *info = current_thread_info(); | ||
567 | struct unaligned_jit_fragment frag; | ||
568 | struct unaligned_jit_fragment *jit_code_area; | ||
569 | tilegx_bundle_bits bundle_2 = 0; | ||
570 | /* If bundle_2_enable = false, bundle_2 is fnop/nop operation. */ | ||
571 | bool bundle_2_enable = true; | ||
572 | uint64_t ra, rb, rd = -1, clob1, clob2, clob3; | ||
573 | /* | ||
574 | * Indicate if the unalign access | ||
575 | * instruction's registers hit with | ||
576 | * others in the same bundle. | ||
577 | */ | ||
578 | bool alias = false; | ||
579 | bool load_n_store = true; | ||
580 | bool load_store_signed = false; | ||
581 | unsigned int load_store_size = 8; | ||
582 | bool y1_br = false; /* True, for a branch in same bundle at Y1.*/ | ||
583 | int y1_br_reg = 0; | ||
584 | /* True for link operation. i.e. jalr or lnk at Y1 */ | ||
585 | bool y1_lr = false; | ||
586 | int y1_lr_reg = 0; | ||
587 | bool x1_add = false;/* True, for load/store ADD instruction at X1*/ | ||
588 | int x1_add_imm8 = 0; | ||
589 | bool unexpected = false; | ||
590 | int n = 0, k; | ||
591 | |||
592 | jit_code_area = | ||
593 | (struct unaligned_jit_fragment *)(info->unalign_jit_base); | ||
594 | |||
595 | memset((void *)&frag, 0, sizeof(frag)); | ||
596 | |||
597 | /* 0: X mode, Otherwise: Y mode. */ | ||
598 | if (bundle & TILEGX_BUNDLE_MODE_MASK) { | ||
599 | unsigned int mod, opcode; | ||
600 | |||
601 | if (get_Opcode_Y1(bundle) == RRR_1_OPCODE_Y1 && | ||
602 | get_RRROpcodeExtension_Y1(bundle) == | ||
603 | UNARY_RRR_1_OPCODE_Y1) { | ||
604 | |||
605 | opcode = get_UnaryOpcodeExtension_Y1(bundle); | ||
606 | |||
607 | /* | ||
608 | * Test "jalr", "jalrp", "jr", "jrp" instruction at Y1 | ||
609 | * pipeline. | ||
610 | */ | ||
611 | switch (opcode) { | ||
612 | case JALR_UNARY_OPCODE_Y1: | ||
613 | case JALRP_UNARY_OPCODE_Y1: | ||
614 | y1_lr = true; | ||
615 | y1_lr_reg = 55; /* Link register. */ | ||
616 | /* FALLTHROUGH */ | ||
617 | case JR_UNARY_OPCODE_Y1: | ||
618 | case JRP_UNARY_OPCODE_Y1: | ||
619 | y1_br = true; | ||
620 | y1_br_reg = get_SrcA_Y1(bundle); | ||
621 | break; | ||
622 | case LNK_UNARY_OPCODE_Y1: | ||
623 | /* "lnk" at Y1 pipeline. */ | ||
624 | y1_lr = true; | ||
625 | y1_lr_reg = get_Dest_Y1(bundle); | ||
626 | break; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | opcode = get_Opcode_Y2(bundle); | ||
631 | mod = get_Mode(bundle); | ||
632 | |||
633 | /* | ||
634 | * bundle_2 is bundle after making Y2 as a dummy operation | ||
635 | * - ld zero, sp | ||
636 | */ | ||
637 | bundle_2 = (bundle & (~GX_INSN_Y2_MASK)) | jit_y2_dummy(); | ||
638 | |||
639 | /* Make Y1 as fnop if Y1 is a branch or lnk operation. */ | ||
640 | if (y1_br || y1_lr) { | ||
641 | bundle_2 &= ~(GX_INSN_Y1_MASK); | ||
642 | bundle_2 |= jit_y1_fnop(); | ||
643 | } | ||
644 | |||
645 | if (is_y0_y1_nop(bundle_2)) | ||
646 | bundle_2_enable = false; | ||
647 | |||
648 | if (mod == MODE_OPCODE_YC2) { | ||
649 | /* Store. */ | ||
650 | load_n_store = false; | ||
651 | load_store_size = 1 << opcode; | ||
652 | load_store_signed = false; | ||
653 | find_regs(bundle, 0, &ra, &rb, &clob1, &clob2, | ||
654 | &clob3, &alias); | ||
655 | if (load_store_size > 8) | ||
656 | unexpected = true; | ||
657 | } else { | ||
658 | /* Load. */ | ||
659 | load_n_store = true; | ||
660 | if (mod == MODE_OPCODE_YB2) { | ||
661 | switch (opcode) { | ||
662 | case LD_OPCODE_Y2: | ||
663 | load_store_signed = false; | ||
664 | load_store_size = 8; | ||
665 | break; | ||
666 | case LD4S_OPCODE_Y2: | ||
667 | load_store_signed = true; | ||
668 | load_store_size = 4; | ||
669 | break; | ||
670 | case LD4U_OPCODE_Y2: | ||
671 | load_store_signed = false; | ||
672 | load_store_size = 4; | ||
673 | break; | ||
674 | default: | ||
675 | unexpected = true; | ||
676 | } | ||
677 | } else if (mod == MODE_OPCODE_YA2) { | ||
678 | if (opcode == LD2S_OPCODE_Y2) { | ||
679 | load_store_signed = true; | ||
680 | load_store_size = 2; | ||
681 | } else if (opcode == LD2U_OPCODE_Y2) { | ||
682 | load_store_signed = false; | ||
683 | load_store_size = 2; | ||
684 | } else | ||
685 | unexpected = true; | ||
686 | } else | ||
687 | unexpected = true; | ||
688 | find_regs(bundle, &rd, &ra, &rb, &clob1, &clob2, | ||
689 | &clob3, &alias); | ||
690 | } | ||
691 | } else { | ||
692 | unsigned int opcode; | ||
693 | |||
694 | /* bundle_2 is bundle after making X1 as "fnop". */ | ||
695 | bundle_2 = (bundle & (~GX_INSN_X1_MASK)) | jit_x1_fnop(); | ||
696 | |||
697 | if (is_x0_x1_nop(bundle_2)) | ||
698 | bundle_2_enable = false; | ||
699 | |||
700 | if (get_Opcode_X1(bundle) == RRR_0_OPCODE_X1) { | ||
701 | opcode = get_UnaryOpcodeExtension_X1(bundle); | ||
702 | |||
703 | if (get_RRROpcodeExtension_X1(bundle) == | ||
704 | UNARY_RRR_0_OPCODE_X1) { | ||
705 | load_n_store = true; | ||
706 | find_regs(bundle, &rd, &ra, &rb, &clob1, | ||
707 | &clob2, &clob3, &alias); | ||
708 | |||
709 | switch (opcode) { | ||
710 | case LD_UNARY_OPCODE_X1: | ||
711 | load_store_signed = false; | ||
712 | load_store_size = 8; | ||
713 | break; | ||
714 | case LD4S_UNARY_OPCODE_X1: | ||
715 | load_store_signed = true; | ||
716 | /* FALLTHROUGH */ | ||
717 | case LD4U_UNARY_OPCODE_X1: | ||
718 | load_store_size = 4; | ||
719 | break; | ||
720 | |||
721 | case LD2S_UNARY_OPCODE_X1: | ||
722 | load_store_signed = true; | ||
723 | /* FALLTHROUGH */ | ||
724 | case LD2U_UNARY_OPCODE_X1: | ||
725 | load_store_size = 2; | ||
726 | break; | ||
727 | default: | ||
728 | unexpected = true; | ||
729 | } | ||
730 | } else { | ||
731 | load_n_store = false; | ||
732 | load_store_signed = false; | ||
733 | find_regs(bundle, 0, &ra, &rb, | ||
734 | &clob1, &clob2, &clob3, | ||
735 | &alias); | ||
736 | |||
737 | opcode = get_RRROpcodeExtension_X1(bundle); | ||
738 | switch (opcode) { | ||
739 | case ST_RRR_0_OPCODE_X1: | ||
740 | load_store_size = 8; | ||
741 | break; | ||
742 | case ST4_RRR_0_OPCODE_X1: | ||
743 | load_store_size = 4; | ||
744 | break; | ||
745 | case ST2_RRR_0_OPCODE_X1: | ||
746 | load_store_size = 2; | ||
747 | break; | ||
748 | default: | ||
749 | unexpected = true; | ||
750 | } | ||
751 | } | ||
752 | } else if (get_Opcode_X1(bundle) == IMM8_OPCODE_X1) { | ||
753 | load_n_store = true; | ||
754 | opcode = get_Imm8OpcodeExtension_X1(bundle); | ||
755 | switch (opcode) { | ||
756 | case LD_ADD_IMM8_OPCODE_X1: | ||
757 | load_store_size = 8; | ||
758 | break; | ||
759 | |||
760 | case LD4S_ADD_IMM8_OPCODE_X1: | ||
761 | load_store_signed = true; | ||
762 | /* FALLTHROUGH */ | ||
763 | case LD4U_ADD_IMM8_OPCODE_X1: | ||
764 | load_store_size = 4; | ||
765 | break; | ||
766 | |||
767 | case LD2S_ADD_IMM8_OPCODE_X1: | ||
768 | load_store_signed = true; | ||
769 | /* FALLTHROUGH */ | ||
770 | case LD2U_ADD_IMM8_OPCODE_X1: | ||
771 | load_store_size = 2; | ||
772 | break; | ||
773 | |||
774 | case ST_ADD_IMM8_OPCODE_X1: | ||
775 | load_n_store = false; | ||
776 | load_store_size = 8; | ||
777 | break; | ||
778 | case ST4_ADD_IMM8_OPCODE_X1: | ||
779 | load_n_store = false; | ||
780 | load_store_size = 4; | ||
781 | break; | ||
782 | case ST2_ADD_IMM8_OPCODE_X1: | ||
783 | load_n_store = false; | ||
784 | load_store_size = 2; | ||
785 | break; | ||
786 | default: | ||
787 | unexpected = true; | ||
788 | } | ||
789 | |||
790 | if (!unexpected) { | ||
791 | x1_add = true; | ||
792 | if (load_n_store) | ||
793 | x1_add_imm8 = get_Imm8_X1(bundle); | ||
794 | else | ||
795 | x1_add_imm8 = get_Dest_Imm8_X1(bundle); | ||
796 | } | ||
797 | |||
798 | find_regs(bundle, load_n_store ? (&rd) : NULL, | ||
799 | &ra, &rb, &clob1, &clob2, &clob3, &alias); | ||
800 | } else | ||
801 | unexpected = true; | ||
802 | } | ||
803 | |||
804 | /* | ||
805 | * Some sanity check for register numbers extracted from fault bundle. | ||
806 | */ | ||
807 | if (check_regs(rd, ra, rb, clob1, clob2, clob3) == true) | ||
808 | unexpected = true; | ||
809 | |||
810 | /* Give warning if register ra has an aligned address. */ | ||
811 | if (!unexpected) | ||
812 | WARN_ON(!((load_store_size - 1) & (regs->regs[ra]))); | ||
813 | |||
814 | |||
815 | /* | ||
816 | * Fault came from kernel space, here we only need take care of | ||
817 | * unaligned "get_user/put_user" macros defined in "uaccess.h". | ||
818 | * Basically, we will handle bundle like this: | ||
819 | * {ld/2u/4s rd, ra; movei rx, 0} or {st/2/4 ra, rb; movei rx, 0} | ||
820 | * (Refer to file "arch/tile/include/asm/uaccess.h" for details). | ||
821 | * For either load or store, byte-wise operation is performed by calling | ||
822 | * get_user() or put_user(). If the macro returns non-zero value, | ||
823 | * set the value to rx, otherwise set zero to rx. Finally make pc point | ||
824 | * to next bundle and return. | ||
825 | */ | ||
826 | |||
827 | if (EX1_PL(regs->ex1) != USER_PL) { | ||
828 | |||
829 | unsigned long rx = 0; | ||
830 | unsigned long x = 0, ret = 0; | ||
831 | |||
832 | if (y1_br || y1_lr || x1_add || | ||
833 | (load_store_signed != | ||
834 | (load_n_store && load_store_size == 4))) { | ||
835 | /* No branch, link, wrong sign-ext or load/store add. */ | ||
836 | unexpected = true; | ||
837 | } else if (!unexpected) { | ||
838 | if (bundle & TILEGX_BUNDLE_MODE_MASK) { | ||
839 | /* | ||
840 | * Fault bundle is Y mode. | ||
841 | * Check if the Y1 and Y0 is the form of | ||
842 | * { movei rx, 0; nop/fnop }, if yes, | ||
843 | * find the rx. | ||
844 | */ | ||
845 | |||
846 | if ((get_Opcode_Y1(bundle) == ADDI_OPCODE_Y1) | ||
847 | && (get_SrcA_Y1(bundle) == TREG_ZERO) && | ||
848 | (get_Imm8_Y1(bundle) == 0) && | ||
849 | is_bundle_y0_nop(bundle)) { | ||
850 | rx = get_Dest_Y1(bundle); | ||
851 | } else if ((get_Opcode_Y0(bundle) == | ||
852 | ADDI_OPCODE_Y0) && | ||
853 | (get_SrcA_Y0(bundle) == TREG_ZERO) && | ||
854 | (get_Imm8_Y0(bundle) == 0) && | ||
855 | is_bundle_y1_nop(bundle)) { | ||
856 | rx = get_Dest_Y0(bundle); | ||
857 | } else { | ||
858 | unexpected = true; | ||
859 | } | ||
860 | } else { | ||
861 | /* | ||
862 | * Fault bundle is X mode. | ||
863 | * Check if the X0 is 'movei rx, 0', | ||
864 | * if yes, find the rx. | ||
865 | */ | ||
866 | |||
867 | if ((get_Opcode_X0(bundle) == IMM8_OPCODE_X0) | ||
868 | && (get_Imm8OpcodeExtension_X0(bundle) == | ||
869 | ADDI_IMM8_OPCODE_X0) && | ||
870 | (get_SrcA_X0(bundle) == TREG_ZERO) && | ||
871 | (get_Imm8_X0(bundle) == 0)) { | ||
872 | rx = get_Dest_X0(bundle); | ||
873 | } else { | ||
874 | unexpected = true; | ||
875 | } | ||
876 | } | ||
877 | |||
878 | /* rx should be less than 56. */ | ||
879 | if (!unexpected && (rx >= 56)) | ||
880 | unexpected = true; | ||
881 | } | ||
882 | |||
883 | if (!search_exception_tables(regs->pc)) { | ||
884 | /* No fixup in the exception tables for the pc. */ | ||
885 | unexpected = true; | ||
886 | } | ||
887 | |||
888 | if (unexpected) { | ||
889 | /* Unexpected unalign kernel fault. */ | ||
890 | struct task_struct *tsk = validate_current(); | ||
891 | |||
892 | bust_spinlocks(1); | ||
893 | |||
894 | show_regs(regs); | ||
895 | |||
896 | if (unlikely(tsk->pid < 2)) { | ||
897 | panic("Kernel unalign fault running %s!", | ||
898 | tsk->pid ? "init" : "the idle task"); | ||
899 | } | ||
900 | #ifdef SUPPORT_DIE | ||
901 | die("Oops", regs); | ||
902 | #endif | ||
903 | bust_spinlocks(1); | ||
904 | |||
905 | do_group_exit(SIGKILL); | ||
906 | |||
907 | } else { | ||
908 | unsigned long i, b = 0; | ||
909 | unsigned char *ptr = | ||
910 | (unsigned char *)regs->regs[ra]; | ||
911 | if (load_n_store) { | ||
912 | /* handle get_user(x, ptr) */ | ||
913 | for (i = 0; i < load_store_size; i++) { | ||
914 | ret = get_user(b, ptr++); | ||
915 | if (!ret) { | ||
916 | /* Success! update x. */ | ||
917 | #ifdef __LITTLE_ENDIAN | ||
918 | x |= (b << (8 * i)); | ||
919 | #else | ||
920 | x <<= 8; | ||
921 | x |= b; | ||
922 | #endif /* __LITTLE_ENDIAN */ | ||
923 | } else { | ||
924 | x = 0; | ||
925 | break; | ||
926 | } | ||
927 | } | ||
928 | |||
929 | /* Sign-extend 4-byte loads. */ | ||
930 | if (load_store_size == 4) | ||
931 | x = (long)(int)x; | ||
932 | |||
933 | /* Set register rd. */ | ||
934 | regs->regs[rd] = x; | ||
935 | |||
936 | /* Set register rx. */ | ||
937 | regs->regs[rx] = ret; | ||
938 | |||
939 | /* Bump pc. */ | ||
940 | regs->pc += 8; | ||
941 | |||
942 | } else { | ||
943 | /* Handle put_user(x, ptr) */ | ||
944 | x = regs->regs[rb]; | ||
945 | #ifdef __LITTLE_ENDIAN | ||
946 | b = x; | ||
947 | #else | ||
948 | /* | ||
949 | * Swap x in order to store x from low | ||
950 | * to high memory same as the | ||
951 | * little-endian case. | ||
952 | */ | ||
953 | switch (load_store_size) { | ||
954 | case 8: | ||
955 | b = swab64(x); | ||
956 | break; | ||
957 | case 4: | ||
958 | b = swab32(x); | ||
959 | break; | ||
960 | case 2: | ||
961 | b = swab16(x); | ||
962 | break; | ||
963 | } | ||
964 | #endif /* __LITTLE_ENDIAN */ | ||
965 | for (i = 0; i < load_store_size; i++) { | ||
966 | ret = put_user(b, ptr++); | ||
967 | if (ret) | ||
968 | break; | ||
969 | /* Success! shift 1 byte. */ | ||
970 | b >>= 8; | ||
971 | } | ||
972 | /* Set register rx. */ | ||
973 | regs->regs[rx] = ret; | ||
974 | |||
975 | /* Bump pc. */ | ||
976 | regs->pc += 8; | ||
977 | } | ||
978 | } | ||
979 | |||
980 | unaligned_fixup_count++; | ||
981 | |||
982 | if (unaligned_printk) { | ||
983 | pr_info("%s/%d. Unalign fixup for kernel access " | ||
984 | "to userspace %lx.", | ||
985 | current->comm, current->pid, regs->regs[ra]); | ||
986 | } | ||
987 | |||
988 | /* Done! Return to the exception handler. */ | ||
989 | return; | ||
990 | } | ||
991 | |||
992 | if ((align_ctl == 0) || unexpected) { | ||
993 | siginfo_t info = { | ||
994 | .si_signo = SIGBUS, | ||
995 | .si_code = BUS_ADRALN, | ||
996 | .si_addr = (unsigned char __user *)0 | ||
997 | }; | ||
998 | if (unaligned_printk) | ||
999 | pr_info("Unalign bundle: unexp @%llx, %llx", | ||
1000 | (unsigned long long)regs->pc, | ||
1001 | (unsigned long long)bundle); | ||
1002 | |||
1003 | if (ra < 56) { | ||
1004 | unsigned long uaa = (unsigned long)regs->regs[ra]; | ||
1005 | /* Set bus Address. */ | ||
1006 | info.si_addr = (unsigned char __user *)uaa; | ||
1007 | } | ||
1008 | |||
1009 | unaligned_fixup_count++; | ||
1010 | |||
1011 | trace_unhandled_signal("unaligned fixup trap", regs, | ||
1012 | (unsigned long)info.si_addr, SIGBUS); | ||
1013 | force_sig_info(info.si_signo, &info, current); | ||
1014 | return; | ||
1015 | } | ||
1016 | |||
1017 | #ifdef __LITTLE_ENDIAN | ||
1018 | #define UA_FIXUP_ADDR_DELTA 1 | ||
1019 | #define UA_FIXUP_BFEXT_START(_B_) 0 | ||
1020 | #define UA_FIXUP_BFEXT_END(_B_) (8 * (_B_) - 1) | ||
1021 | #else /* __BIG_ENDIAN */ | ||
1022 | #define UA_FIXUP_ADDR_DELTA -1 | ||
1023 | #define UA_FIXUP_BFEXT_START(_B_) (64 - 8 * (_B_)) | ||
1024 | #define UA_FIXUP_BFEXT_END(_B_) 63 | ||
1025 | #endif /* __LITTLE_ENDIAN */ | ||
1026 | |||
1027 | |||
1028 | |||
1029 | if ((ra != rb) && (rd != TREG_SP) && !alias && | ||
1030 | !y1_br && !y1_lr && !x1_add) { | ||
1031 | /* | ||
1032 | * Simple case: ra != rb and no register alias found, | ||
1033 | * and no branch or link. This will be the majority. | ||
1034 | * We can do a little better for simplae case than the | ||
1035 | * generic scheme below. | ||
1036 | */ | ||
1037 | if (!load_n_store) { | ||
1038 | /* | ||
1039 | * Simple store: ra != rb, no need for scratch register. | ||
1040 | * Just store and rotate to right bytewise. | ||
1041 | */ | ||
1042 | #ifdef __BIG_ENDIAN | ||
1043 | frag.insn[n++] = | ||
1044 | jit_x0_addi(ra, ra, load_store_size - 1) | | ||
1045 | jit_x1_fnop(); | ||
1046 | #endif /* __BIG_ENDIAN */ | ||
1047 | for (k = 0; k < load_store_size; k++) { | ||
1048 | /* Store a byte. */ | ||
1049 | frag.insn[n++] = | ||
1050 | jit_x0_rotli(rb, rb, 56) | | ||
1051 | jit_x1_st1_add(ra, rb, | ||
1052 | UA_FIXUP_ADDR_DELTA); | ||
1053 | } | ||
1054 | #ifdef __BIG_ENDIAN | ||
1055 | frag.insn[n] = jit_x1_addi(ra, ra, 1); | ||
1056 | #else | ||
1057 | frag.insn[n] = jit_x1_addi(ra, ra, | ||
1058 | -1 * load_store_size); | ||
1059 | #endif /* __LITTLE_ENDIAN */ | ||
1060 | |||
1061 | if (load_store_size == 8) { | ||
1062 | frag.insn[n] |= jit_x0_fnop(); | ||
1063 | } else if (load_store_size == 4) { | ||
1064 | frag.insn[n] |= jit_x0_rotli(rb, rb, 32); | ||
1065 | } else { /* = 2 */ | ||
1066 | frag.insn[n] |= jit_x0_rotli(rb, rb, 16); | ||
1067 | } | ||
1068 | n++; | ||
1069 | if (bundle_2_enable) | ||
1070 | frag.insn[n++] = bundle_2; | ||
1071 | frag.insn[n++] = jit_x0_fnop() | jit_x1_iret(); | ||
1072 | } else { | ||
1073 | if (rd == ra) { | ||
1074 | /* Use two clobber registers: clob1/2. */ | ||
1075 | frag.insn[n++] = | ||
1076 | jit_x0_addi(TREG_SP, TREG_SP, -16) | | ||
1077 | jit_x1_fnop(); | ||
1078 | frag.insn[n++] = | ||
1079 | jit_x0_addi(clob1, ra, 7) | | ||
1080 | jit_x1_st_add(TREG_SP, clob1, -8); | ||
1081 | frag.insn[n++] = | ||
1082 | jit_x0_addi(clob2, ra, 0) | | ||
1083 | jit_x1_st(TREG_SP, clob2); | ||
1084 | frag.insn[n++] = | ||
1085 | jit_x0_fnop() | | ||
1086 | jit_x1_ldna(rd, ra); | ||
1087 | frag.insn[n++] = | ||
1088 | jit_x0_fnop() | | ||
1089 | jit_x1_ldna(clob1, clob1); | ||
1090 | /* | ||
1091 | * Note: we must make sure that rd must not | ||
1092 | * be sp. Recover clob1/2 from stack. | ||
1093 | */ | ||
1094 | frag.insn[n++] = | ||
1095 | jit_x0_dblalign(rd, clob1, clob2) | | ||
1096 | jit_x1_ld_add(clob2, TREG_SP, 8); | ||
1097 | frag.insn[n++] = | ||
1098 | jit_x0_fnop() | | ||
1099 | jit_x1_ld_add(clob1, TREG_SP, 16); | ||
1100 | } else { | ||
1101 | /* Use one clobber register: clob1 only. */ | ||
1102 | frag.insn[n++] = | ||
1103 | jit_x0_addi(TREG_SP, TREG_SP, -16) | | ||
1104 | jit_x1_fnop(); | ||
1105 | frag.insn[n++] = | ||
1106 | jit_x0_addi(clob1, ra, 7) | | ||
1107 | jit_x1_st(TREG_SP, clob1); | ||
1108 | frag.insn[n++] = | ||
1109 | jit_x0_fnop() | | ||
1110 | jit_x1_ldna(rd, ra); | ||
1111 | frag.insn[n++] = | ||
1112 | jit_x0_fnop() | | ||
1113 | jit_x1_ldna(clob1, clob1); | ||
1114 | /* | ||
1115 | * Note: we must make sure that rd must not | ||
1116 | * be sp. Recover clob1 from stack. | ||
1117 | */ | ||
1118 | frag.insn[n++] = | ||
1119 | jit_x0_dblalign(rd, clob1, ra) | | ||
1120 | jit_x1_ld_add(clob1, TREG_SP, 16); | ||
1121 | } | ||
1122 | |||
1123 | if (bundle_2_enable) | ||
1124 | frag.insn[n++] = bundle_2; | ||
1125 | /* | ||
1126 | * For non 8-byte load, extract corresponding bytes and | ||
1127 | * signed extension. | ||
1128 | */ | ||
1129 | if (load_store_size == 4) { | ||
1130 | if (load_store_signed) | ||
1131 | frag.insn[n++] = | ||
1132 | jit_x0_bfexts( | ||
1133 | rd, rd, | ||
1134 | UA_FIXUP_BFEXT_START(4), | ||
1135 | UA_FIXUP_BFEXT_END(4)) | | ||
1136 | jit_x1_fnop(); | ||
1137 | else | ||
1138 | frag.insn[n++] = | ||
1139 | jit_x0_bfextu( | ||
1140 | rd, rd, | ||
1141 | UA_FIXUP_BFEXT_START(4), | ||
1142 | UA_FIXUP_BFEXT_END(4)) | | ||
1143 | jit_x1_fnop(); | ||
1144 | } else if (load_store_size == 2) { | ||
1145 | if (load_store_signed) | ||
1146 | frag.insn[n++] = | ||
1147 | jit_x0_bfexts( | ||
1148 | rd, rd, | ||
1149 | UA_FIXUP_BFEXT_START(2), | ||
1150 | UA_FIXUP_BFEXT_END(2)) | | ||
1151 | jit_x1_fnop(); | ||
1152 | else | ||
1153 | frag.insn[n++] = | ||
1154 | jit_x0_bfextu( | ||
1155 | rd, rd, | ||
1156 | UA_FIXUP_BFEXT_START(2), | ||
1157 | UA_FIXUP_BFEXT_END(2)) | | ||
1158 | jit_x1_fnop(); | ||
1159 | } | ||
1160 | |||
1161 | frag.insn[n++] = | ||
1162 | jit_x0_fnop() | | ||
1163 | jit_x1_iret(); | ||
1164 | } | ||
1165 | } else if (!load_n_store) { | ||
1166 | |||
1167 | /* | ||
1168 | * Generic memory store cases: use 3 clobber registers. | ||
1169 | * | ||
1170 | * Alloc space for saveing clob2,1,3 on user's stack. | ||
1171 | * register clob3 points to where clob2 saved, followed by | ||
1172 | * clob1 and 3 from high to low memory. | ||
1173 | */ | ||
1174 | frag.insn[n++] = | ||
1175 | jit_x0_addi(TREG_SP, TREG_SP, -32) | | ||
1176 | jit_x1_fnop(); | ||
1177 | frag.insn[n++] = | ||
1178 | jit_x0_addi(clob3, TREG_SP, 16) | | ||
1179 | jit_x1_st_add(TREG_SP, clob3, 8); | ||
1180 | #ifdef __LITTLE_ENDIAN | ||
1181 | frag.insn[n++] = | ||
1182 | jit_x0_addi(clob1, ra, 0) | | ||
1183 | jit_x1_st_add(TREG_SP, clob1, 8); | ||
1184 | #else | ||
1185 | frag.insn[n++] = | ||
1186 | jit_x0_addi(clob1, ra, load_store_size - 1) | | ||
1187 | jit_x1_st_add(TREG_SP, clob1, 8); | ||
1188 | #endif | ||
1189 | if (load_store_size == 8) { | ||
1190 | /* | ||
1191 | * We save one byte a time, not for fast, but compact | ||
1192 | * code. After each store, data source register shift | ||
1193 | * right one byte. unchanged after 8 stores. | ||
1194 | */ | ||
1195 | frag.insn[n++] = | ||
1196 | jit_x0_addi(clob2, TREG_ZERO, 7) | | ||
1197 | jit_x1_st_add(TREG_SP, clob2, 16); | ||
1198 | frag.insn[n++] = | ||
1199 | jit_x0_rotli(rb, rb, 56) | | ||
1200 | jit_x1_st1_add(clob1, rb, UA_FIXUP_ADDR_DELTA); | ||
1201 | frag.insn[n++] = | ||
1202 | jit_x0_addi(clob2, clob2, -1) | | ||
1203 | jit_x1_bnezt(clob2, -1); | ||
1204 | frag.insn[n++] = | ||
1205 | jit_x0_fnop() | | ||
1206 | jit_x1_addi(clob2, y1_br_reg, 0); | ||
1207 | } else if (load_store_size == 4) { | ||
1208 | frag.insn[n++] = | ||
1209 | jit_x0_addi(clob2, TREG_ZERO, 3) | | ||
1210 | jit_x1_st_add(TREG_SP, clob2, 16); | ||
1211 | frag.insn[n++] = | ||
1212 | jit_x0_rotli(rb, rb, 56) | | ||
1213 | jit_x1_st1_add(clob1, rb, UA_FIXUP_ADDR_DELTA); | ||
1214 | frag.insn[n++] = | ||
1215 | jit_x0_addi(clob2, clob2, -1) | | ||
1216 | jit_x1_bnezt(clob2, -1); | ||
1217 | /* | ||
1218 | * same as 8-byte case, but need shift another 4 | ||
1219 | * byte to recover rb for 4-byte store. | ||
1220 | */ | ||
1221 | frag.insn[n++] = jit_x0_rotli(rb, rb, 32) | | ||
1222 | jit_x1_addi(clob2, y1_br_reg, 0); | ||
1223 | } else { /* =2 */ | ||
1224 | frag.insn[n++] = | ||
1225 | jit_x0_addi(clob2, rb, 0) | | ||
1226 | jit_x1_st_add(TREG_SP, clob2, 16); | ||
1227 | for (k = 0; k < 2; k++) { | ||
1228 | frag.insn[n++] = | ||
1229 | jit_x0_shrui(rb, rb, 8) | | ||
1230 | jit_x1_st1_add(clob1, rb, | ||
1231 | UA_FIXUP_ADDR_DELTA); | ||
1232 | } | ||
1233 | frag.insn[n++] = | ||
1234 | jit_x0_addi(rb, clob2, 0) | | ||
1235 | jit_x1_addi(clob2, y1_br_reg, 0); | ||
1236 | } | ||
1237 | |||
1238 | if (bundle_2_enable) | ||
1239 | frag.insn[n++] = bundle_2; | ||
1240 | |||
1241 | if (y1_lr) { | ||
1242 | frag.insn[n++] = | ||
1243 | jit_x0_fnop() | | ||
1244 | jit_x1_mfspr(y1_lr_reg, | ||
1245 | SPR_EX_CONTEXT_0_0); | ||
1246 | } | ||
1247 | if (y1_br) { | ||
1248 | frag.insn[n++] = | ||
1249 | jit_x0_fnop() | | ||
1250 | jit_x1_mtspr(SPR_EX_CONTEXT_0_0, | ||
1251 | clob2); | ||
1252 | } | ||
1253 | if (x1_add) { | ||
1254 | frag.insn[n++] = | ||
1255 | jit_x0_addi(ra, ra, x1_add_imm8) | | ||
1256 | jit_x1_ld_add(clob2, clob3, -8); | ||
1257 | } else { | ||
1258 | frag.insn[n++] = | ||
1259 | jit_x0_fnop() | | ||
1260 | jit_x1_ld_add(clob2, clob3, -8); | ||
1261 | } | ||
1262 | frag.insn[n++] = | ||
1263 | jit_x0_fnop() | | ||
1264 | jit_x1_ld_add(clob1, clob3, -8); | ||
1265 | frag.insn[n++] = jit_x0_fnop() | jit_x1_ld(clob3, clob3); | ||
1266 | frag.insn[n++] = jit_x0_fnop() | jit_x1_iret(); | ||
1267 | |||
1268 | } else { | ||
1269 | /* | ||
1270 | * Generic memory load cases. | ||
1271 | * | ||
1272 | * Alloc space for saveing clob1,2,3 on user's stack. | ||
1273 | * register clob3 points to where clob1 saved, followed | ||
1274 | * by clob2 and 3 from high to low memory. | ||
1275 | */ | ||
1276 | |||
1277 | frag.insn[n++] = | ||
1278 | jit_x0_addi(TREG_SP, TREG_SP, -32) | | ||
1279 | jit_x1_fnop(); | ||
1280 | frag.insn[n++] = | ||
1281 | jit_x0_addi(clob3, TREG_SP, 16) | | ||
1282 | jit_x1_st_add(TREG_SP, clob3, 8); | ||
1283 | frag.insn[n++] = | ||
1284 | jit_x0_addi(clob2, ra, 0) | | ||
1285 | jit_x1_st_add(TREG_SP, clob2, 8); | ||
1286 | |||
1287 | if (y1_br) { | ||
1288 | frag.insn[n++] = | ||
1289 | jit_x0_addi(clob1, y1_br_reg, 0) | | ||
1290 | jit_x1_st_add(TREG_SP, clob1, 16); | ||
1291 | } else { | ||
1292 | frag.insn[n++] = | ||
1293 | jit_x0_fnop() | | ||
1294 | jit_x1_st_add(TREG_SP, clob1, 16); | ||
1295 | } | ||
1296 | |||
1297 | if (bundle_2_enable) | ||
1298 | frag.insn[n++] = bundle_2; | ||
1299 | |||
1300 | if (y1_lr) { | ||
1301 | frag.insn[n++] = | ||
1302 | jit_x0_fnop() | | ||
1303 | jit_x1_mfspr(y1_lr_reg, | ||
1304 | SPR_EX_CONTEXT_0_0); | ||
1305 | } | ||
1306 | |||
1307 | if (y1_br) { | ||
1308 | frag.insn[n++] = | ||
1309 | jit_x0_fnop() | | ||
1310 | jit_x1_mtspr(SPR_EX_CONTEXT_0_0, | ||
1311 | clob1); | ||
1312 | } | ||
1313 | |||
1314 | frag.insn[n++] = | ||
1315 | jit_x0_addi(clob1, clob2, 7) | | ||
1316 | jit_x1_ldna(rd, clob2); | ||
1317 | frag.insn[n++] = | ||
1318 | jit_x0_fnop() | | ||
1319 | jit_x1_ldna(clob1, clob1); | ||
1320 | frag.insn[n++] = | ||
1321 | jit_x0_dblalign(rd, clob1, clob2) | | ||
1322 | jit_x1_ld_add(clob1, clob3, -8); | ||
1323 | if (x1_add) { | ||
1324 | frag.insn[n++] = | ||
1325 | jit_x0_addi(ra, ra, x1_add_imm8) | | ||
1326 | jit_x1_ld_add(clob2, clob3, -8); | ||
1327 | } else { | ||
1328 | frag.insn[n++] = | ||
1329 | jit_x0_fnop() | | ||
1330 | jit_x1_ld_add(clob2, clob3, -8); | ||
1331 | } | ||
1332 | |||
1333 | frag.insn[n++] = | ||
1334 | jit_x0_fnop() | | ||
1335 | jit_x1_ld(clob3, clob3); | ||
1336 | |||
1337 | if (load_store_size == 4) { | ||
1338 | if (load_store_signed) | ||
1339 | frag.insn[n++] = | ||
1340 | jit_x0_bfexts( | ||
1341 | rd, rd, | ||
1342 | UA_FIXUP_BFEXT_START(4), | ||
1343 | UA_FIXUP_BFEXT_END(4)) | | ||
1344 | jit_x1_fnop(); | ||
1345 | else | ||
1346 | frag.insn[n++] = | ||
1347 | jit_x0_bfextu( | ||
1348 | rd, rd, | ||
1349 | UA_FIXUP_BFEXT_START(4), | ||
1350 | UA_FIXUP_BFEXT_END(4)) | | ||
1351 | jit_x1_fnop(); | ||
1352 | } else if (load_store_size == 2) { | ||
1353 | if (load_store_signed) | ||
1354 | frag.insn[n++] = | ||
1355 | jit_x0_bfexts( | ||
1356 | rd, rd, | ||
1357 | UA_FIXUP_BFEXT_START(2), | ||
1358 | UA_FIXUP_BFEXT_END(2)) | | ||
1359 | jit_x1_fnop(); | ||
1360 | else | ||
1361 | frag.insn[n++] = | ||
1362 | jit_x0_bfextu( | ||
1363 | rd, rd, | ||
1364 | UA_FIXUP_BFEXT_START(2), | ||
1365 | UA_FIXUP_BFEXT_END(2)) | | ||
1366 | jit_x1_fnop(); | ||
1367 | } | ||
1368 | |||
1369 | frag.insn[n++] = jit_x0_fnop() | jit_x1_iret(); | ||
1370 | } | ||
1371 | |||
1372 | /* Max JIT bundle count is 14. */ | ||
1373 | WARN_ON(n > 14); | ||
1374 | |||
1375 | if (!unexpected) { | ||
1376 | int status = 0; | ||
1377 | int idx = (regs->pc >> 3) & | ||
1378 | ((1ULL << (PAGE_SHIFT - UNALIGN_JIT_SHIFT)) - 1); | ||
1379 | |||
1380 | frag.pc = regs->pc; | ||
1381 | frag.bundle = bundle; | ||
1382 | |||
1383 | if (unaligned_printk) { | ||
1384 | pr_info("%s/%d, Unalign fixup: pc=%lx " | ||
1385 | "bundle=%lx %d %d %d %d %d %d %d %d.", | ||
1386 | current->comm, current->pid, | ||
1387 | (unsigned long)frag.pc, | ||
1388 | (unsigned long)frag.bundle, | ||
1389 | (int)alias, (int)rd, (int)ra, | ||
1390 | (int)rb, (int)bundle_2_enable, | ||
1391 | (int)y1_lr, (int)y1_br, (int)x1_add); | ||
1392 | |||
1393 | for (k = 0; k < n; k += 2) | ||
1394 | pr_info("[%d] %016llx %016llx", k, | ||
1395 | (unsigned long long)frag.insn[k], | ||
1396 | (unsigned long long)frag.insn[k+1]); | ||
1397 | } | ||
1398 | |||
1399 | /* Swap bundle byte order for big endian sys. */ | ||
1400 | #ifdef __BIG_ENDIAN | ||
1401 | frag.bundle = GX_INSN_BSWAP(frag.bundle); | ||
1402 | for (k = 0; k < n; k++) | ||
1403 | frag.insn[k] = GX_INSN_BSWAP(frag.insn[k]); | ||
1404 | #endif /* __BIG_ENDIAN */ | ||
1405 | |||
1406 | status = copy_to_user((void __user *)&jit_code_area[idx], | ||
1407 | &frag, sizeof(frag)); | ||
1408 | if (status) { | ||
1409 | /* Fail to copy JIT into user land. send SIGSEGV. */ | ||
1410 | siginfo_t info = { | ||
1411 | .si_signo = SIGSEGV, | ||
1412 | .si_code = SEGV_MAPERR, | ||
1413 | .si_addr = (void __user *)&jit_code_area[idx] | ||
1414 | }; | ||
1415 | |||
1416 | pr_warn("Unalign fixup: pid=%d %s jit_code_area=%llx", | ||
1417 | current->pid, current->comm, | ||
1418 | (unsigned long long)&jit_code_area[idx]); | ||
1419 | |||
1420 | trace_unhandled_signal("segfault in unalign fixup", | ||
1421 | regs, | ||
1422 | (unsigned long)info.si_addr, | ||
1423 | SIGSEGV); | ||
1424 | force_sig_info(info.si_signo, &info, current); | ||
1425 | return; | ||
1426 | } | ||
1427 | |||
1428 | |||
1429 | /* Do a cheaper increment, not accurate. */ | ||
1430 | unaligned_fixup_count++; | ||
1431 | __flush_icache_range((unsigned long)&jit_code_area[idx], | ||
1432 | (unsigned long)&jit_code_area[idx] + | ||
1433 | sizeof(frag)); | ||
1434 | |||
1435 | /* Setup SPR_EX_CONTEXT_0_0/1 for returning to user program.*/ | ||
1436 | __insn_mtspr(SPR_EX_CONTEXT_0_0, regs->pc + 8); | ||
1437 | __insn_mtspr(SPR_EX_CONTEXT_0_1, PL_ICS_EX1(USER_PL, 0)); | ||
1438 | |||
1439 | /* Modify pc at the start of new JIT. */ | ||
1440 | regs->pc = (unsigned long)&jit_code_area[idx].insn[0]; | ||
1441 | /* Set ICS in SPR_EX_CONTEXT_K_1. */ | ||
1442 | regs->ex1 = PL_ICS_EX1(USER_PL, 1); | ||
1443 | } | ||
1444 | } | ||
1445 | |||
1446 | |||
1447 | /* | ||
1448 | * C function to generate unalign data JIT. Called from unalign data | ||
1449 | * interrupt handler. | ||
1450 | * | ||
1451 | * First check if unalign fix is disabled or exception did not not come from | ||
1452 | * user space or sp register points to unalign address, if true, generate a | ||
1453 | * SIGBUS. Then map a page into user space as JIT area if it is not mapped | ||
1454 | * yet. Genenerate JIT code by calling jit_bundle_gen(). After that return | ||
1455 | * back to exception handler. | ||
1456 | * | ||
1457 | * The exception handler will "iret" to new generated JIT code after | ||
1458 | * restoring caller saved registers. In theory, the JIT code will perform | ||
1459 | * another "iret" to resume user's program. | ||
1460 | */ | ||
1461 | |||
1462 | void do_unaligned(struct pt_regs *regs, int vecnum) | ||
1463 | { | ||
1464 | tilegx_bundle_bits __user *pc; | ||
1465 | tilegx_bundle_bits bundle; | ||
1466 | struct thread_info *info = current_thread_info(); | ||
1467 | int align_ctl; | ||
1468 | |||
1469 | /* Checks the per-process unaligned JIT flags */ | ||
1470 | align_ctl = unaligned_fixup; | ||
1471 | switch (task_thread_info(current)->align_ctl) { | ||
1472 | case PR_UNALIGN_NOPRINT: | ||
1473 | align_ctl = 1; | ||
1474 | break; | ||
1475 | case PR_UNALIGN_SIGBUS: | ||
1476 | align_ctl = 0; | ||
1477 | break; | ||
1478 | } | ||
1479 | |||
1480 | /* Enable iterrupt in order to access user land. */ | ||
1481 | local_irq_enable(); | ||
1482 | |||
1483 | /* | ||
1484 | * The fault came from kernel space. Two choices: | ||
1485 | * (a) unaligned_fixup < 1, we will first call get/put_user fixup | ||
1486 | * to return -EFAULT. If no fixup, simply panic the kernel. | ||
1487 | * (b) unaligned_fixup >=1, we will try to fix the unaligned access | ||
1488 | * if it was triggered by get_user/put_user() macros. Panic the | ||
1489 | * kernel if it is not fixable. | ||
1490 | */ | ||
1491 | |||
1492 | if (EX1_PL(regs->ex1) != USER_PL) { | ||
1493 | |||
1494 | if (align_ctl < 1) { | ||
1495 | unaligned_fixup_count++; | ||
1496 | /* If exception came from kernel, try fix it up. */ | ||
1497 | if (fixup_exception(regs)) { | ||
1498 | if (unaligned_printk) | ||
1499 | pr_info("Unalign fixup: %d %llx @%llx", | ||
1500 | (int)unaligned_fixup, | ||
1501 | (unsigned long long)regs->ex1, | ||
1502 | (unsigned long long)regs->pc); | ||
1503 | return; | ||
1504 | } | ||
1505 | /* Not fixable. Go panic. */ | ||
1506 | panic("Unalign exception in Kernel. pc=%lx", | ||
1507 | regs->pc); | ||
1508 | return; | ||
1509 | } else { | ||
1510 | /* | ||
1511 | * Try to fix the exception. If we can't, panic the | ||
1512 | * kernel. | ||
1513 | */ | ||
1514 | bundle = GX_INSN_BSWAP( | ||
1515 | *((tilegx_bundle_bits *)(regs->pc))); | ||
1516 | jit_bundle_gen(regs, bundle, align_ctl); | ||
1517 | return; | ||
1518 | } | ||
1519 | } | ||
1520 | |||
1521 | /* | ||
1522 | * Fault came from user with ICS or stack is not aligned. | ||
1523 | * If so, we will trigger SIGBUS. | ||
1524 | */ | ||
1525 | if ((regs->sp & 0x7) || (regs->ex1) || (align_ctl < 0)) { | ||
1526 | siginfo_t info = { | ||
1527 | .si_signo = SIGBUS, | ||
1528 | .si_code = BUS_ADRALN, | ||
1529 | .si_addr = (unsigned char __user *)0 | ||
1530 | }; | ||
1531 | |||
1532 | if (unaligned_printk) | ||
1533 | pr_info("Unalign fixup: %d %llx @%llx", | ||
1534 | (int)unaligned_fixup, | ||
1535 | (unsigned long long)regs->ex1, | ||
1536 | (unsigned long long)regs->pc); | ||
1537 | |||
1538 | unaligned_fixup_count++; | ||
1539 | |||
1540 | trace_unhandled_signal("unaligned fixup trap", regs, 0, SIGBUS); | ||
1541 | force_sig_info(info.si_signo, &info, current); | ||
1542 | return; | ||
1543 | } | ||
1544 | |||
1545 | |||
1546 | /* Read the bundle casued the exception! */ | ||
1547 | pc = (tilegx_bundle_bits __user *)(regs->pc); | ||
1548 | if (get_user(bundle, pc) != 0) { | ||
1549 | /* Probably never be here since pc is valid user address.*/ | ||
1550 | siginfo_t info = { | ||
1551 | .si_signo = SIGSEGV, | ||
1552 | .si_code = SEGV_MAPERR, | ||
1553 | .si_addr = (void __user *)pc | ||
1554 | }; | ||
1555 | pr_err("Couldn't read instruction at %p trying to step\n", pc); | ||
1556 | trace_unhandled_signal("segfault in unalign fixup", regs, | ||
1557 | (unsigned long)info.si_addr, SIGSEGV); | ||
1558 | force_sig_info(info.si_signo, &info, current); | ||
1559 | return; | ||
1560 | } | ||
1561 | |||
1562 | if (!info->unalign_jit_base) { | ||
1563 | void __user *user_page; | ||
1564 | |||
1565 | /* | ||
1566 | * Allocate a page in userland. | ||
1567 | * For 64-bit processes we try to place the mapping far | ||
1568 | * from anything else that might be going on (specifically | ||
1569 | * 64 GB below the top of the user address space). If it | ||
1570 | * happens not to be possible to put it there, it's OK; | ||
1571 | * the kernel will choose another location and we'll | ||
1572 | * remember it for later. | ||
1573 | */ | ||
1574 | if (is_compat_task()) | ||
1575 | user_page = NULL; | ||
1576 | else | ||
1577 | user_page = (void __user *)(TASK_SIZE - (1UL << 36)) + | ||
1578 | (current->pid << PAGE_SHIFT); | ||
1579 | |||
1580 | user_page = (void __user *) vm_mmap(NULL, | ||
1581 | (unsigned long)user_page, | ||
1582 | PAGE_SIZE, | ||
1583 | PROT_EXEC | PROT_READ | | ||
1584 | PROT_WRITE, | ||
1585 | #ifdef CONFIG_HOMECACHE | ||
1586 | MAP_CACHE_HOME_TASK | | ||
1587 | #endif | ||
1588 | MAP_PRIVATE | | ||
1589 | MAP_ANONYMOUS, | ||
1590 | 0); | ||
1591 | |||
1592 | if (IS_ERR((void __force *)user_page)) { | ||
1593 | pr_err("Out of kernel pages trying do_mmap.\n"); | ||
1594 | return; | ||
1595 | } | ||
1596 | |||
1597 | /* Save the address in the thread_info struct */ | ||
1598 | info->unalign_jit_base = user_page; | ||
1599 | if (unaligned_printk) | ||
1600 | pr_info("Unalign bundle: %d:%d, allocate page @%llx", | ||
1601 | raw_smp_processor_id(), current->pid, | ||
1602 | (unsigned long long)user_page); | ||
1603 | } | ||
1604 | |||
1605 | /* Generate unalign JIT */ | ||
1606 | jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl); | ||
1607 | } | ||
1608 | |||
1609 | #endif /* __tilegx__ */ | ||
diff --git a/arch/tile/kernel/vdso.c b/arch/tile/kernel/vdso.c new file mode 100644 index 000000000000..1533af24106e --- /dev/null +++ b/arch/tile/kernel/vdso.c | |||
@@ -0,0 +1,212 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/binfmts.h> | ||
16 | #include <linux/compat.h> | ||
17 | #include <linux/elf.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/pagemap.h> | ||
20 | |||
21 | #include <asm/vdso.h> | ||
22 | #include <asm/mman.h> | ||
23 | #include <asm/sections.h> | ||
24 | |||
25 | #include <arch/sim.h> | ||
26 | |||
27 | /* The alignment of the vDSO. */ | ||
28 | #define VDSO_ALIGNMENT PAGE_SIZE | ||
29 | |||
30 | |||
31 | static unsigned int vdso_pages; | ||
32 | static struct page **vdso_pagelist; | ||
33 | |||
34 | #ifdef CONFIG_COMPAT | ||
35 | static unsigned int vdso32_pages; | ||
36 | static struct page **vdso32_pagelist; | ||
37 | #endif | ||
38 | static int vdso_ready; | ||
39 | |||
40 | /* | ||
41 | * The vdso data page. | ||
42 | */ | ||
43 | static union { | ||
44 | struct vdso_data data; | ||
45 | u8 page[PAGE_SIZE]; | ||
46 | } vdso_data_store __page_aligned_data; | ||
47 | |||
48 | struct vdso_data *vdso_data = &vdso_data_store.data; | ||
49 | |||
50 | static unsigned int __read_mostly vdso_enabled = 1; | ||
51 | |||
52 | static struct page **vdso_setup(void *vdso_kbase, unsigned int pages) | ||
53 | { | ||
54 | int i; | ||
55 | struct page **pagelist; | ||
56 | |||
57 | pagelist = kzalloc(sizeof(struct page *) * (pages + 1), GFP_KERNEL); | ||
58 | BUG_ON(pagelist == NULL); | ||
59 | for (i = 0; i < pages - 1; i++) { | ||
60 | struct page *pg = virt_to_page(vdso_kbase + i*PAGE_SIZE); | ||
61 | ClearPageReserved(pg); | ||
62 | pagelist[i] = pg; | ||
63 | } | ||
64 | pagelist[pages - 1] = virt_to_page(vdso_data); | ||
65 | pagelist[pages] = NULL; | ||
66 | |||
67 | return pagelist; | ||
68 | } | ||
69 | |||
70 | static int __init vdso_init(void) | ||
71 | { | ||
72 | int data_pages = sizeof(vdso_data_store) >> PAGE_SHIFT; | ||
73 | |||
74 | /* | ||
75 | * We can disable vDSO support generally, but we need to retain | ||
76 | * one page to support the two-bundle (16-byte) rt_sigreturn path. | ||
77 | */ | ||
78 | if (!vdso_enabled) { | ||
79 | size_t offset = (unsigned long)&__vdso_rt_sigreturn; | ||
80 | static struct page *sigret_page; | ||
81 | sigret_page = alloc_page(GFP_KERNEL | __GFP_ZERO); | ||
82 | BUG_ON(sigret_page == NULL); | ||
83 | vdso_pagelist = &sigret_page; | ||
84 | vdso_pages = 1; | ||
85 | BUG_ON(offset >= PAGE_SIZE); | ||
86 | memcpy(page_address(sigret_page) + offset, | ||
87 | vdso_start + offset, 16); | ||
88 | #ifdef CONFIG_COMPAT | ||
89 | vdso32_pages = vdso_pages; | ||
90 | vdso32_pagelist = vdso_pagelist; | ||
91 | #endif | ||
92 | vdso_ready = 1; | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT; | ||
97 | vdso_pages += data_pages; | ||
98 | vdso_pagelist = vdso_setup(vdso_start, vdso_pages); | ||
99 | |||
100 | #ifdef CONFIG_COMPAT | ||
101 | vdso32_pages = (vdso32_end - vdso32_start) >> PAGE_SHIFT; | ||
102 | vdso32_pages += data_pages; | ||
103 | vdso32_pagelist = vdso_setup(vdso32_start, vdso32_pages); | ||
104 | #endif | ||
105 | |||
106 | smp_wmb(); | ||
107 | vdso_ready = 1; | ||
108 | |||
109 | return 0; | ||
110 | } | ||
111 | arch_initcall(vdso_init); | ||
112 | |||
113 | const char *arch_vma_name(struct vm_area_struct *vma) | ||
114 | { | ||
115 | if (vma->vm_mm && vma->vm_start == VDSO_BASE) | ||
116 | return "[vdso]"; | ||
117 | #ifndef __tilegx__ | ||
118 | if (vma->vm_start == MEM_USER_INTRPT) | ||
119 | return "[intrpt]"; | ||
120 | #endif | ||
121 | return NULL; | ||
122 | } | ||
123 | |||
124 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) | ||
125 | { | ||
126 | return NULL; | ||
127 | } | ||
128 | |||
129 | int in_gate_area(struct mm_struct *mm, unsigned long address) | ||
130 | { | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | int in_gate_area_no_mm(unsigned long address) | ||
135 | { | ||
136 | return 0; | ||
137 | } | ||
138 | |||
139 | int setup_vdso_pages(void) | ||
140 | { | ||
141 | struct page **pagelist; | ||
142 | unsigned long pages; | ||
143 | struct mm_struct *mm = current->mm; | ||
144 | unsigned long vdso_base = 0; | ||
145 | int retval = 0; | ||
146 | |||
147 | if (!vdso_ready) | ||
148 | return 0; | ||
149 | |||
150 | mm->context.vdso_base = 0; | ||
151 | |||
152 | pagelist = vdso_pagelist; | ||
153 | pages = vdso_pages; | ||
154 | #ifdef CONFIG_COMPAT | ||
155 | if (is_compat_task()) { | ||
156 | pagelist = vdso32_pagelist; | ||
157 | pages = vdso32_pages; | ||
158 | } | ||
159 | #endif | ||
160 | |||
161 | /* | ||
162 | * vDSO has a problem and was disabled, just don't "enable" it for the | ||
163 | * process. | ||
164 | */ | ||
165 | if (pages == 0) | ||
166 | return 0; | ||
167 | |||
168 | vdso_base = get_unmapped_area(NULL, vdso_base, | ||
169 | (pages << PAGE_SHIFT) + | ||
170 | ((VDSO_ALIGNMENT - 1) & PAGE_MASK), | ||
171 | 0, 0); | ||
172 | if (IS_ERR_VALUE(vdso_base)) { | ||
173 | retval = vdso_base; | ||
174 | return retval; | ||
175 | } | ||
176 | |||
177 | /* Add required alignment. */ | ||
178 | vdso_base = ALIGN(vdso_base, VDSO_ALIGNMENT); | ||
179 | |||
180 | /* | ||
181 | * Put vDSO base into mm struct. We need to do this before calling | ||
182 | * install_special_mapping or the perf counter mmap tracking code | ||
183 | * will fail to recognise it as a vDSO (since arch_vma_name fails). | ||
184 | */ | ||
185 | mm->context.vdso_base = vdso_base; | ||
186 | |||
187 | /* | ||
188 | * our vma flags don't have VM_WRITE so by default, the process isn't | ||
189 | * allowed to write those pages. | ||
190 | * gdb can break that with ptrace interface, and thus trigger COW on | ||
191 | * those pages but it's then your responsibility to never do that on | ||
192 | * the "data" page of the vDSO or you'll stop getting kernel updates | ||
193 | * and your nice userland gettimeofday will be totally dead. | ||
194 | * It's fine to use that for setting breakpoints in the vDSO code | ||
195 | * pages though | ||
196 | */ | ||
197 | retval = install_special_mapping(mm, vdso_base, | ||
198 | pages << PAGE_SHIFT, | ||
199 | VM_READ|VM_EXEC | | ||
200 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, | ||
201 | pagelist); | ||
202 | if (retval) | ||
203 | mm->context.vdso_base = 0; | ||
204 | |||
205 | return retval; | ||
206 | } | ||
207 | |||
208 | static __init int vdso_func(char *s) | ||
209 | { | ||
210 | return kstrtouint(s, 0, &vdso_enabled); | ||
211 | } | ||
212 | __setup("vdso=", vdso_func); | ||
diff --git a/arch/tile/kernel/vdso/Makefile b/arch/tile/kernel/vdso/Makefile new file mode 100644 index 000000000000..e2b7a2f4ee41 --- /dev/null +++ b/arch/tile/kernel/vdso/Makefile | |||
@@ -0,0 +1,118 @@ | |||
1 | # Symbols present in the vdso | ||
2 | vdso-syms = rt_sigreturn gettimeofday | ||
3 | |||
4 | # Files to link into the vdso | ||
5 | obj-vdso = $(patsubst %, v%.o, $(vdso-syms)) | ||
6 | |||
7 | # Build rules | ||
8 | targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds | ||
9 | obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) | ||
10 | |||
11 | # vdso32 is only for tilegx -m32 compat task. | ||
12 | VDSO32-$(CONFIG_COMPAT) := y | ||
13 | |||
14 | obj-y += vdso.o | ||
15 | obj-$(VDSO32-y) += vdso32.o | ||
16 | extra-y += vdso.lds | ||
17 | CPPFLAGS_vdso.lds += -P -C -U$(ARCH) | ||
18 | |||
19 | # vDSO code runs in userspace and -pg doesn't help with profiling anyway. | ||
20 | CFLAGS_REMOVE_vdso.o = -pg | ||
21 | CFLAGS_REMOVE_vdso32.o = -pg | ||
22 | CFLAGS_REMOVE_vrt_sigreturn.o = -pg | ||
23 | CFLAGS_REMOVE_vrt_sigreturn32.o = -pg | ||
24 | CFLAGS_REMOVE_vgettimeofday.o = -pg | ||
25 | CFLAGS_REMOVE_vgettimeofday32.o = -pg | ||
26 | |||
27 | ifdef CONFIG_FEEDBACK_COLLECT | ||
28 | # vDSO code runs in userspace, not collecting feedback data. | ||
29 | CFLAGS_REMOVE_vdso.o = -ffeedback-generate | ||
30 | CFLAGS_REMOVE_vdso32.o = -ffeedback-generate | ||
31 | CFLAGS_REMOVE_vrt_sigreturn.o = -ffeedback-generate | ||
32 | CFLAGS_REMOVE_vrt_sigreturn32.o = -ffeedback-generate | ||
33 | CFLAGS_REMOVE_vgettimeofday.o = -ffeedback-generate | ||
34 | CFLAGS_REMOVE_vgettimeofday32.o = -ffeedback-generate | ||
35 | endif | ||
36 | |||
37 | # Disable gcov profiling for VDSO code | ||
38 | GCOV_PROFILE := n | ||
39 | |||
40 | # Force dependency | ||
41 | $(obj)/vdso.o: $(obj)/vdso.so | ||
42 | |||
43 | # link rule for the .so file, .lds has to be first | ||
44 | SYSCFLAGS_vdso.so.dbg = $(c_flags) | ||
45 | $(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) | ||
46 | $(call if_changed,vdsold) | ||
47 | |||
48 | |||
49 | # We also create a special relocatable object that should mirror the symbol | ||
50 | # table and layout of the linked DSO. With ld -R we can then refer to | ||
51 | # these symbols in the kernel code rather than hand-coded addresses. | ||
52 | extra-y += vdso-syms.o | ||
53 | $(obj)/built-in.o: $(obj)/vdso-syms.o | ||
54 | $(obj)/built-in.o: ld_flags += -R $(obj)/vdso-syms.o | ||
55 | |||
56 | SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \ | ||
57 | $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) | ||
58 | SYSCFLAGS_vdso_syms.o = -r | ||
59 | $(obj)/vdso-syms.o: $(src)/vdso.lds $(obj)/vrt_sigreturn.o FORCE | ||
60 | $(call if_changed,vdsold) | ||
61 | |||
62 | |||
63 | # strip rule for the .so file | ||
64 | $(obj)/%.so: OBJCOPYFLAGS := -S | ||
65 | $(obj)/%.so: $(obj)/%.so.dbg FORCE | ||
66 | $(call if_changed,objcopy) | ||
67 | |||
68 | # actual build commands | ||
69 | # The DSO images are built using a special linker script | ||
70 | # Add -lgcc so tilepro gets static muldi3 and lshrdi3 definitions. | ||
71 | # Make sure only to export the intended __vdso_xxx symbol offsets. | ||
72 | quiet_cmd_vdsold = VDSOLD $@ | ||
73 | cmd_vdsold = $(CC) $(KCFLAGS) -nostdlib $(SYSCFLAGS_$(@F)) \ | ||
74 | -Wl,-T,$(filter-out FORCE,$^) -o $@.tmp -lgcc && \ | ||
75 | $(CROSS_COMPILE)objcopy \ | ||
76 | $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ | ||
77 | |||
78 | # install commands for the unstripped file | ||
79 | quiet_cmd_vdso_install = INSTALL $@ | ||
80 | cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ | ||
81 | |||
82 | vdso.so: $(obj)/vdso.so.dbg | ||
83 | @mkdir -p $(MODLIB)/vdso | ||
84 | $(call cmd,vdso_install) | ||
85 | |||
86 | vdso32.so: $(obj)/vdso32.so.dbg | ||
87 | $(call cmd,vdso_install) | ||
88 | |||
89 | vdso_install: vdso.so | ||
90 | vdso32_install: vdso32.so | ||
91 | |||
92 | |||
93 | KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS)) | ||
94 | KBUILD_AFLAGS_32 += -m32 -s | ||
95 | KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS)) | ||
96 | KBUILD_CFLAGS_32 += -m32 -fPIC -shared | ||
97 | |||
98 | obj-vdso32 = $(patsubst %, v%32.o, $(vdso-syms)) | ||
99 | obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32)) | ||
100 | |||
101 | targets += $(obj-vdso32) vdso32.so vdso32.so.dbg | ||
102 | |||
103 | $(obj-vdso32:%=%): KBUILD_AFLAGS = $(KBUILD_AFLAGS_32) | ||
104 | $(obj-vdso32:%=%): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32) | ||
105 | |||
106 | $(obj)/vgettimeofday32.o: $(obj)/vgettimeofday.c | ||
107 | $(call if_changed,cc_o_c) | ||
108 | |||
109 | $(obj)/vrt_sigreturn32.o: $(obj)/vrt_sigreturn.S | ||
110 | $(call if_changed,as_o_S) | ||
111 | |||
112 | # Force dependency | ||
113 | $(obj)/vdso32.o: $(obj)/vdso32.so | ||
114 | |||
115 | SYSCFLAGS_vdso32.so.dbg = -m32 -shared -s -Wl,-soname=linux-vdso32.so.1 \ | ||
116 | $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) | ||
117 | $(obj)/vdso32.so.dbg: $(src)/vdso.lds $(obj-vdso32) | ||
118 | $(call if_changed,vdsold) | ||
diff --git a/arch/tile/kernel/vdso/vdso.S b/arch/tile/kernel/vdso/vdso.S new file mode 100644 index 000000000000..3467adb41630 --- /dev/null +++ b/arch/tile/kernel/vdso/vdso.S | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/linkage.h> | ||
17 | #include <asm/page.h> | ||
18 | |||
19 | __PAGE_ALIGNED_DATA | ||
20 | |||
21 | .global vdso_start, vdso_end | ||
22 | .align PAGE_SIZE | ||
23 | vdso_start: | ||
24 | .incbin "arch/tile/kernel/vdso/vdso.so" | ||
25 | .align PAGE_SIZE | ||
26 | vdso_end: | ||
27 | |||
28 | .previous | ||
diff --git a/arch/tile/kernel/vdso/vdso.lds.S b/arch/tile/kernel/vdso/vdso.lds.S new file mode 100644 index 000000000000..041cd6c39c83 --- /dev/null +++ b/arch/tile/kernel/vdso/vdso.lds.S | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #define VDSO_VERSION_STRING LINUX_2.6 | ||
16 | |||
17 | |||
18 | OUTPUT_ARCH(tile) | ||
19 | |||
20 | /* The ELF entry point can be used to set the AT_SYSINFO value. */ | ||
21 | ENTRY(__vdso_rt_sigreturn); | ||
22 | |||
23 | |||
24 | SECTIONS | ||
25 | { | ||
26 | . = SIZEOF_HEADERS; | ||
27 | |||
28 | .hash : { *(.hash) } :text | ||
29 | .gnu.hash : { *(.gnu.hash) } | ||
30 | .dynsym : { *(.dynsym) } | ||
31 | .dynstr : { *(.dynstr) } | ||
32 | .gnu.version : { *(.gnu.version) } | ||
33 | .gnu.version_d : { *(.gnu.version_d) } | ||
34 | .gnu.version_r : { *(.gnu.version_r) } | ||
35 | |||
36 | .note : { *(.note.*) } :text :note | ||
37 | .dynamic : { *(.dynamic) } :text :dynamic | ||
38 | |||
39 | .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr | ||
40 | .eh_frame : { KEEP (*(.eh_frame)) } :text | ||
41 | |||
42 | .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } | ||
43 | |||
44 | /* | ||
45 | * This linker script is used both with -r and with -shared. | ||
46 | * For the layouts to match, we need to skip more than enough | ||
47 | * space for the dynamic symbol table et al. If this amount | ||
48 | * is insufficient, ld -shared will barf. Just increase it here. | ||
49 | */ | ||
50 | . = 0x1000; | ||
51 | .text : { *(.text .text.*) } :text | ||
52 | |||
53 | .data : { | ||
54 | *(.got.plt) *(.got) | ||
55 | *(.data .data.* .gnu.linkonce.d.*) | ||
56 | *(.dynbss) | ||
57 | *(.bss .bss.* .gnu.linkonce.b.*) | ||
58 | } | ||
59 | } | ||
60 | |||
61 | |||
62 | /* | ||
63 | * We must supply the ELF program headers explicitly to get just one | ||
64 | * PT_LOAD segment, and set the flags explicitly to make segments read-only. | ||
65 | */ | ||
66 | PHDRS | ||
67 | { | ||
68 | text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */ | ||
69 | dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ | ||
70 | note PT_NOTE FLAGS(4); /* PF_R */ | ||
71 | eh_frame_hdr PT_GNU_EH_FRAME; | ||
72 | } | ||
73 | |||
74 | |||
75 | /* | ||
76 | * This controls what userland symbols we export from the vDSO. | ||
77 | */ | ||
78 | VERSION | ||
79 | { | ||
80 | VDSO_VERSION_STRING { | ||
81 | global: | ||
82 | __vdso_rt_sigreturn; | ||
83 | __vdso_gettimeofday; | ||
84 | gettimeofday; | ||
85 | local:*; | ||
86 | }; | ||
87 | } | ||
diff --git a/arch/tile/kernel/vdso/vdso32.S b/arch/tile/kernel/vdso/vdso32.S new file mode 100644 index 000000000000..1d1ac3257e11 --- /dev/null +++ b/arch/tile/kernel/vdso/vdso32.S | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/init.h> | ||
16 | #include <linux/linkage.h> | ||
17 | #include <asm/page.h> | ||
18 | |||
19 | __PAGE_ALIGNED_DATA | ||
20 | |||
21 | .global vdso32_start, vdso32_end | ||
22 | .align PAGE_SIZE | ||
23 | vdso32_start: | ||
24 | .incbin "arch/tile/kernel/vdso/vdso32.so" | ||
25 | .align PAGE_SIZE | ||
26 | vdso32_end: | ||
27 | |||
28 | .previous | ||
diff --git a/arch/tile/kernel/vdso/vgettimeofday.c b/arch/tile/kernel/vdso/vgettimeofday.c new file mode 100644 index 000000000000..51ec8e46f5f9 --- /dev/null +++ b/arch/tile/kernel/vdso/vgettimeofday.c | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #define VDSO_BUILD /* avoid some shift warnings for -m32 in <asm/page.h> */ | ||
16 | #include <linux/time.h> | ||
17 | #include <asm/timex.h> | ||
18 | #include <asm/vdso.h> | ||
19 | |||
20 | #if CHIP_HAS_SPLIT_CYCLE() | ||
21 | static inline cycles_t get_cycles_inline(void) | ||
22 | { | ||
23 | unsigned int high = __insn_mfspr(SPR_CYCLE_HIGH); | ||
24 | unsigned int low = __insn_mfspr(SPR_CYCLE_LOW); | ||
25 | unsigned int high2 = __insn_mfspr(SPR_CYCLE_HIGH); | ||
26 | |||
27 | while (unlikely(high != high2)) { | ||
28 | low = __insn_mfspr(SPR_CYCLE_LOW); | ||
29 | high = high2; | ||
30 | high2 = __insn_mfspr(SPR_CYCLE_HIGH); | ||
31 | } | ||
32 | |||
33 | return (((cycles_t)high) << 32) | low; | ||
34 | } | ||
35 | #define get_cycles get_cycles_inline | ||
36 | #endif | ||
37 | |||
38 | /* | ||
39 | * Find out the vDSO data page address in the process address space. | ||
40 | */ | ||
41 | inline unsigned long get_datapage(void) | ||
42 | { | ||
43 | unsigned long ret; | ||
44 | |||
45 | /* vdso data page located in the 2nd vDSO page. */ | ||
46 | asm volatile ("lnk %0" : "=r"(ret)); | ||
47 | ret &= ~(PAGE_SIZE - 1); | ||
48 | ret += PAGE_SIZE; | ||
49 | |||
50 | return ret; | ||
51 | } | ||
52 | |||
53 | int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) | ||
54 | { | ||
55 | cycles_t cycles; | ||
56 | unsigned long count, sec, ns; | ||
57 | volatile struct vdso_data *vdso_data; | ||
58 | |||
59 | vdso_data = (struct vdso_data *)get_datapage(); | ||
60 | /* The use of the timezone is obsolete, normally tz is NULL. */ | ||
61 | if (unlikely(tz != NULL)) { | ||
62 | while (1) { | ||
63 | /* Spin until the update finish. */ | ||
64 | count = vdso_data->tz_update_count; | ||
65 | if (count & 1) | ||
66 | continue; | ||
67 | |||
68 | tz->tz_minuteswest = vdso_data->tz_minuteswest; | ||
69 | tz->tz_dsttime = vdso_data->tz_dsttime; | ||
70 | |||
71 | /* Check whether updated, read again if so. */ | ||
72 | if (count == vdso_data->tz_update_count) | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | |||
77 | if (unlikely(tv == NULL)) | ||
78 | return 0; | ||
79 | |||
80 | while (1) { | ||
81 | /* Spin until the update finish. */ | ||
82 | count = vdso_data->tb_update_count; | ||
83 | if (count & 1) | ||
84 | continue; | ||
85 | |||
86 | cycles = (get_cycles() - vdso_data->xtime_tod_stamp); | ||
87 | ns = (cycles * vdso_data->mult) >> vdso_data->shift; | ||
88 | sec = vdso_data->xtime_clock_sec; | ||
89 | ns += vdso_data->xtime_clock_nsec; | ||
90 | if (ns >= NSEC_PER_SEC) { | ||
91 | ns -= NSEC_PER_SEC; | ||
92 | sec += 1; | ||
93 | } | ||
94 | |||
95 | /* Check whether updated, read again if so. */ | ||
96 | if (count == vdso_data->tb_update_count) | ||
97 | break; | ||
98 | } | ||
99 | |||
100 | tv->tv_sec = sec; | ||
101 | tv->tv_usec = ns / 1000; | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | int gettimeofday(struct timeval *tv, struct timezone *tz) | ||
107 | __attribute__((weak, alias("__vdso_gettimeofday"))); | ||
diff --git a/arch/tile/kernel/vdso/vrt_sigreturn.S b/arch/tile/kernel/vdso/vrt_sigreturn.S new file mode 100644 index 000000000000..6326caf4a039 --- /dev/null +++ b/arch/tile/kernel/vdso/vrt_sigreturn.S | |||
@@ -0,0 +1,30 @@ | |||
1 | /* | ||
2 | * Copyright 2012 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/linkage.h> | ||
16 | #include <arch/abi.h> | ||
17 | #include <asm/unistd.h> | ||
18 | |||
19 | /* | ||
20 | * Note that libc has a copy of this function that it uses to compare | ||
21 | * against the PC when a stack backtrace ends, so if this code is | ||
22 | * changed, the libc implementation(s) should also be updated. | ||
23 | */ | ||
24 | ENTRY(__vdso_rt_sigreturn) | ||
25 | moveli TREG_SYSCALL_NR_NAME, __NR_rt_sigreturn | ||
26 | swint1 | ||
27 | /* We don't use ENDPROC to avoid tagging this symbol as FUNC, | ||
28 | * which confuses the perf tool. | ||
29 | */ | ||
30 | END(__vdso_rt_sigreturn) | ||
diff --git a/arch/tile/kernel/vmlinux.lds.S b/arch/tile/kernel/vmlinux.lds.S index a13ed902afbb..f1819423ffc9 100644 --- a/arch/tile/kernel/vmlinux.lds.S +++ b/arch/tile/kernel/vmlinux.lds.S | |||
@@ -5,7 +5,7 @@ | |||
5 | #include <hv/hypervisor.h> | 5 | #include <hv/hypervisor.h> |
6 | 6 | ||
7 | /* Text loads starting from the supervisor interrupt vector address. */ | 7 | /* Text loads starting from the supervisor interrupt vector address. */ |
8 | #define TEXT_OFFSET MEM_SV_INTRPT | 8 | #define TEXT_OFFSET MEM_SV_START |
9 | 9 | ||
10 | OUTPUT_ARCH(tile) | 10 | OUTPUT_ARCH(tile) |
11 | ENTRY(_start) | 11 | ENTRY(_start) |
@@ -13,7 +13,7 @@ jiffies = jiffies_64; | |||
13 | 13 | ||
14 | PHDRS | 14 | PHDRS |
15 | { | 15 | { |
16 | intrpt1 PT_LOAD ; | 16 | intrpt PT_LOAD ; |
17 | text PT_LOAD ; | 17 | text PT_LOAD ; |
18 | data PT_LOAD ; | 18 | data PT_LOAD ; |
19 | } | 19 | } |
@@ -24,14 +24,17 @@ SECTIONS | |||
24 | #define LOAD_OFFSET TEXT_OFFSET | 24 | #define LOAD_OFFSET TEXT_OFFSET |
25 | 25 | ||
26 | /* Interrupt vectors */ | 26 | /* Interrupt vectors */ |
27 | .intrpt1 (LOAD_OFFSET) : AT ( 0 ) /* put at the start of physical memory */ | 27 | .intrpt (LOAD_OFFSET) : AT ( 0 ) /* put at the start of physical memory */ |
28 | { | 28 | { |
29 | _text = .; | 29 | _text = .; |
30 | *(.intrpt1) | 30 | *(.intrpt) |
31 | } :intrpt1 =0 | 31 | } :intrpt =0 |
32 | 32 | ||
33 | /* Hypervisor call vectors */ | 33 | /* Hypervisor call vectors */ |
34 | #include "hvglue.lds" | 34 | . = ALIGN(0x10000); |
35 | .hvglue : AT (ADDR(.hvglue) - LOAD_OFFSET) { | ||
36 | *(.hvglue) | ||
37 | } :NONE | ||
35 | 38 | ||
36 | /* Now the real code */ | 39 | /* Now the real code */ |
37 | . = ALIGN(0x20000); | 40 | . = ALIGN(0x20000); |
@@ -40,7 +43,11 @@ SECTIONS | |||
40 | HEAD_TEXT | 43 | HEAD_TEXT |
41 | SCHED_TEXT | 44 | SCHED_TEXT |
42 | LOCK_TEXT | 45 | LOCK_TEXT |
46 | KPROBES_TEXT | ||
47 | IRQENTRY_TEXT | ||
43 | __fix_text_end = .; /* tile-cpack won't rearrange before this */ | 48 | __fix_text_end = .; /* tile-cpack won't rearrange before this */ |
49 | ALIGN_FUNCTION(); | ||
50 | *(.hottext*) | ||
44 | TEXT_TEXT | 51 | TEXT_TEXT |
45 | *(.text.*) | 52 | *(.text.*) |
46 | *(.coldtext*) | 53 | *(.coldtext*) |
@@ -67,20 +74,8 @@ SECTIONS | |||
67 | __init_end = .; | 74 | __init_end = .; |
68 | 75 | ||
69 | _sdata = .; /* Start of data section */ | 76 | _sdata = .; /* Start of data section */ |
70 | |||
71 | RO_DATA_SECTION(PAGE_SIZE) | 77 | RO_DATA_SECTION(PAGE_SIZE) |
72 | |||
73 | /* initially writeable, then read-only */ | ||
74 | . = ALIGN(PAGE_SIZE); | ||
75 | __w1data_begin = .; | ||
76 | .w1data : AT(ADDR(.w1data) - LOAD_OFFSET) { | ||
77 | VMLINUX_SYMBOL(__w1data_begin) = .; | ||
78 | *(.w1data) | ||
79 | VMLINUX_SYMBOL(__w1data_end) = .; | ||
80 | } | ||
81 | |||
82 | RW_DATA_SECTION(L2_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) | 78 | RW_DATA_SECTION(L2_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) |
83 | |||
84 | _edata = .; | 79 | _edata = .; |
85 | 80 | ||
86 | EXCEPTION_TABLE(L2_CACHE_BYTES) | 81 | EXCEPTION_TABLE(L2_CACHE_BYTES) |
diff --git a/arch/tile/lib/Makefile b/arch/tile/lib/Makefile index 985f59858234..c4211cbb2021 100644 --- a/arch/tile/lib/Makefile +++ b/arch/tile/lib/Makefile | |||
@@ -4,15 +4,15 @@ | |||
4 | 4 | ||
5 | lib-y = cacheflush.o checksum.o cpumask.o delay.o uaccess.o \ | 5 | lib-y = cacheflush.o checksum.o cpumask.o delay.o uaccess.o \ |
6 | memmove.o memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \ | 6 | memmove.o memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \ |
7 | strchr_$(BITS).o strlen_$(BITS).o | 7 | strchr_$(BITS).o strlen_$(BITS).o strnlen_$(BITS).o |
8 | |||
9 | ifeq ($(CONFIG_TILEGX),y) | ||
10 | CFLAGS_REMOVE_memcpy_user_64.o = -fno-omit-frame-pointer | ||
11 | lib-y += memcpy_user_64.o | ||
12 | else | ||
13 | lib-y += atomic_32.o atomic_asm_32.o memcpy_tile64.o | ||
14 | endif | ||
15 | 8 | ||
9 | lib-$(CONFIG_TILEGX) += memcpy_user_64.o | ||
10 | lib-$(CONFIG_TILEPRO) += atomic_32.o atomic_asm_32.o | ||
16 | lib-$(CONFIG_SMP) += spinlock_$(BITS).o usercopy_$(BITS).o | 11 | lib-$(CONFIG_SMP) += spinlock_$(BITS).o usercopy_$(BITS).o |
17 | 12 | ||
18 | obj-$(CONFIG_MODULES) += exports.o | 13 | obj-$(CONFIG_MODULES) += exports.o |
14 | |||
15 | # The finv_buffer_remote() and copy_{to,from}_user() routines can't | ||
16 | # have -pg added, since they both rely on being leaf functions. | ||
17 | CFLAGS_REMOVE_cacheflush.o = -pg | ||
18 | CFLAGS_REMOVE_memcpy_user_64.o = -pg | ||
diff --git a/arch/tile/lib/atomic_32.c b/arch/tile/lib/atomic_32.c index f5cada70c3c8..759efa337be8 100644 --- a/arch/tile/lib/atomic_32.c +++ b/arch/tile/lib/atomic_32.c | |||
@@ -20,50 +20,12 @@ | |||
20 | #include <linux/atomic.h> | 20 | #include <linux/atomic.h> |
21 | #include <arch/chip.h> | 21 | #include <arch/chip.h> |
22 | 22 | ||
23 | /* See <asm/atomic_32.h> */ | ||
24 | #if ATOMIC_LOCKS_FOUND_VIA_TABLE() | ||
25 | |||
26 | /* | ||
27 | * A block of memory containing locks for atomic ops. Each instance of this | ||
28 | * struct will be homed on a different CPU. | ||
29 | */ | ||
30 | struct atomic_locks_on_cpu { | ||
31 | int lock[ATOMIC_HASH_L2_SIZE]; | ||
32 | } __attribute__((aligned(ATOMIC_HASH_L2_SIZE * 4))); | ||
33 | |||
34 | static DEFINE_PER_CPU(struct atomic_locks_on_cpu, atomic_lock_pool); | ||
35 | |||
36 | /* The locks we'll use until __init_atomic_per_cpu is called. */ | ||
37 | static struct atomic_locks_on_cpu __initdata initial_atomic_locks; | ||
38 | |||
39 | /* Hash into this vector to get a pointer to lock for the given atomic. */ | ||
40 | struct atomic_locks_on_cpu *atomic_lock_ptr[ATOMIC_HASH_L1_SIZE] | ||
41 | __write_once = { | ||
42 | [0 ... ATOMIC_HASH_L1_SIZE-1] (&initial_atomic_locks) | ||
43 | }; | ||
44 | |||
45 | #else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */ | ||
46 | |||
47 | /* This page is remapped on startup to be hash-for-home. */ | 23 | /* This page is remapped on startup to be hash-for-home. */ |
48 | int atomic_locks[PAGE_SIZE / sizeof(int)] __page_aligned_bss; | 24 | int atomic_locks[PAGE_SIZE / sizeof(int)] __page_aligned_bss; |
49 | 25 | ||
50 | #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */ | ||
51 | |||
52 | int *__atomic_hashed_lock(volatile void *v) | 26 | int *__atomic_hashed_lock(volatile void *v) |
53 | { | 27 | { |
54 | /* NOTE: this code must match "sys_cmpxchg" in kernel/intvec_32.S */ | 28 | /* NOTE: this code must match "sys_cmpxchg" in kernel/intvec_32.S */ |
55 | #if ATOMIC_LOCKS_FOUND_VIA_TABLE() | ||
56 | unsigned long i = | ||
57 | (unsigned long) v & ((PAGE_SIZE-1) & -sizeof(long long)); | ||
58 | unsigned long n = __insn_crc32_32(0, i); | ||
59 | |||
60 | /* Grab high bits for L1 index. */ | ||
61 | unsigned long l1_index = n >> ((sizeof(n) * 8) - ATOMIC_HASH_L1_SHIFT); | ||
62 | /* Grab low bits for L2 index. */ | ||
63 | unsigned long l2_index = n & (ATOMIC_HASH_L2_SIZE - 1); | ||
64 | |||
65 | return &atomic_lock_ptr[l1_index]->lock[l2_index]; | ||
66 | #else | ||
67 | /* | 29 | /* |
68 | * Use bits [3, 3 + ATOMIC_HASH_SHIFT) as the lock index. | 30 | * Use bits [3, 3 + ATOMIC_HASH_SHIFT) as the lock index. |
69 | * Using mm works here because atomic_locks is page aligned. | 31 | * Using mm works here because atomic_locks is page aligned. |
@@ -72,26 +34,13 @@ int *__atomic_hashed_lock(volatile void *v) | |||
72 | (unsigned long)atomic_locks, | 34 | (unsigned long)atomic_locks, |
73 | 2, (ATOMIC_HASH_SHIFT + 2) - 1); | 35 | 2, (ATOMIC_HASH_SHIFT + 2) - 1); |
74 | return (int *)ptr; | 36 | return (int *)ptr; |
75 | #endif | ||
76 | } | 37 | } |
77 | 38 | ||
78 | #ifdef CONFIG_SMP | 39 | #ifdef CONFIG_SMP |
79 | /* Return whether the passed pointer is a valid atomic lock pointer. */ | 40 | /* Return whether the passed pointer is a valid atomic lock pointer. */ |
80 | static int is_atomic_lock(int *p) | 41 | static int is_atomic_lock(int *p) |
81 | { | 42 | { |
82 | #if ATOMIC_LOCKS_FOUND_VIA_TABLE() | ||
83 | int i; | ||
84 | for (i = 0; i < ATOMIC_HASH_L1_SIZE; ++i) { | ||
85 | |||
86 | if (p >= &atomic_lock_ptr[i]->lock[0] && | ||
87 | p < &atomic_lock_ptr[i]->lock[ATOMIC_HASH_L2_SIZE]) { | ||
88 | return 1; | ||
89 | } | ||
90 | } | ||
91 | return 0; | ||
92 | #else | ||
93 | return p >= &atomic_locks[0] && p < &atomic_locks[ATOMIC_HASH_SIZE]; | 43 | return p >= &atomic_locks[0] && p < &atomic_locks[ATOMIC_HASH_SIZE]; |
94 | #endif | ||
95 | } | 44 | } |
96 | 45 | ||
97 | void __atomic_fault_unlock(int *irqlock_word) | 46 | void __atomic_fault_unlock(int *irqlock_word) |
@@ -110,33 +59,32 @@ static inline int *__atomic_setup(volatile void *v) | |||
110 | return __atomic_hashed_lock(v); | 59 | return __atomic_hashed_lock(v); |
111 | } | 60 | } |
112 | 61 | ||
113 | int _atomic_xchg(atomic_t *v, int n) | 62 | int _atomic_xchg(int *v, int n) |
114 | { | 63 | { |
115 | return __atomic_xchg(&v->counter, __atomic_setup(v), n).val; | 64 | return __atomic_xchg(v, __atomic_setup(v), n).val; |
116 | } | 65 | } |
117 | EXPORT_SYMBOL(_atomic_xchg); | 66 | EXPORT_SYMBOL(_atomic_xchg); |
118 | 67 | ||
119 | int _atomic_xchg_add(atomic_t *v, int i) | 68 | int _atomic_xchg_add(int *v, int i) |
120 | { | 69 | { |
121 | return __atomic_xchg_add(&v->counter, __atomic_setup(v), i).val; | 70 | return __atomic_xchg_add(v, __atomic_setup(v), i).val; |
122 | } | 71 | } |
123 | EXPORT_SYMBOL(_atomic_xchg_add); | 72 | EXPORT_SYMBOL(_atomic_xchg_add); |
124 | 73 | ||
125 | int _atomic_xchg_add_unless(atomic_t *v, int a, int u) | 74 | int _atomic_xchg_add_unless(int *v, int a, int u) |
126 | { | 75 | { |
127 | /* | 76 | /* |
128 | * Note: argument order is switched here since it is easier | 77 | * Note: argument order is switched here since it is easier |
129 | * to use the first argument consistently as the "old value" | 78 | * to use the first argument consistently as the "old value" |
130 | * in the assembly, as is done for _atomic_cmpxchg(). | 79 | * in the assembly, as is done for _atomic_cmpxchg(). |
131 | */ | 80 | */ |
132 | return __atomic_xchg_add_unless(&v->counter, __atomic_setup(v), u, a) | 81 | return __atomic_xchg_add_unless(v, __atomic_setup(v), u, a).val; |
133 | .val; | ||
134 | } | 82 | } |
135 | EXPORT_SYMBOL(_atomic_xchg_add_unless); | 83 | EXPORT_SYMBOL(_atomic_xchg_add_unless); |
136 | 84 | ||
137 | int _atomic_cmpxchg(atomic_t *v, int o, int n) | 85 | int _atomic_cmpxchg(int *v, int o, int n) |
138 | { | 86 | { |
139 | return __atomic_cmpxchg(&v->counter, __atomic_setup(v), o, n).val; | 87 | return __atomic_cmpxchg(v, __atomic_setup(v), o, n).val; |
140 | } | 88 | } |
141 | EXPORT_SYMBOL(_atomic_cmpxchg); | 89 | EXPORT_SYMBOL(_atomic_cmpxchg); |
142 | 90 | ||
@@ -159,33 +107,32 @@ unsigned long _atomic_xor(volatile unsigned long *p, unsigned long mask) | |||
159 | EXPORT_SYMBOL(_atomic_xor); | 107 | EXPORT_SYMBOL(_atomic_xor); |
160 | 108 | ||
161 | 109 | ||
162 | u64 _atomic64_xchg(atomic64_t *v, u64 n) | 110 | u64 _atomic64_xchg(u64 *v, u64 n) |
163 | { | 111 | { |
164 | return __atomic64_xchg(&v->counter, __atomic_setup(v), n); | 112 | return __atomic64_xchg(v, __atomic_setup(v), n); |
165 | } | 113 | } |
166 | EXPORT_SYMBOL(_atomic64_xchg); | 114 | EXPORT_SYMBOL(_atomic64_xchg); |
167 | 115 | ||
168 | u64 _atomic64_xchg_add(atomic64_t *v, u64 i) | 116 | u64 _atomic64_xchg_add(u64 *v, u64 i) |
169 | { | 117 | { |
170 | return __atomic64_xchg_add(&v->counter, __atomic_setup(v), i); | 118 | return __atomic64_xchg_add(v, __atomic_setup(v), i); |
171 | } | 119 | } |
172 | EXPORT_SYMBOL(_atomic64_xchg_add); | 120 | EXPORT_SYMBOL(_atomic64_xchg_add); |
173 | 121 | ||
174 | u64 _atomic64_xchg_add_unless(atomic64_t *v, u64 a, u64 u) | 122 | u64 _atomic64_xchg_add_unless(u64 *v, u64 a, u64 u) |
175 | { | 123 | { |
176 | /* | 124 | /* |
177 | * Note: argument order is switched here since it is easier | 125 | * Note: argument order is switched here since it is easier |
178 | * to use the first argument consistently as the "old value" | 126 | * to use the first argument consistently as the "old value" |
179 | * in the assembly, as is done for _atomic_cmpxchg(). | 127 | * in the assembly, as is done for _atomic_cmpxchg(). |
180 | */ | 128 | */ |
181 | return __atomic64_xchg_add_unless(&v->counter, __atomic_setup(v), | 129 | return __atomic64_xchg_add_unless(v, __atomic_setup(v), u, a); |
182 | u, a); | ||
183 | } | 130 | } |
184 | EXPORT_SYMBOL(_atomic64_xchg_add_unless); | 131 | EXPORT_SYMBOL(_atomic64_xchg_add_unless); |
185 | 132 | ||
186 | u64 _atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n) | 133 | u64 _atomic64_cmpxchg(u64 *v, u64 o, u64 n) |
187 | { | 134 | { |
188 | return __atomic64_cmpxchg(&v->counter, __atomic_setup(v), o, n); | 135 | return __atomic64_cmpxchg(v, __atomic_setup(v), o, n); |
189 | } | 136 | } |
190 | EXPORT_SYMBOL(_atomic64_cmpxchg); | 137 | EXPORT_SYMBOL(_atomic64_cmpxchg); |
191 | 138 | ||
@@ -208,54 +155,8 @@ struct __get_user __atomic_bad_address(int __user *addr) | |||
208 | } | 155 | } |
209 | 156 | ||
210 | 157 | ||
211 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
212 | static int __init noatomichash(char *str) | ||
213 | { | ||
214 | pr_warning("noatomichash is deprecated.\n"); | ||
215 | return 1; | ||
216 | } | ||
217 | __setup("noatomichash", noatomichash); | ||
218 | #endif | ||
219 | |||
220 | void __init __init_atomic_per_cpu(void) | 158 | void __init __init_atomic_per_cpu(void) |
221 | { | 159 | { |
222 | #if ATOMIC_LOCKS_FOUND_VIA_TABLE() | ||
223 | |||
224 | unsigned int i; | ||
225 | int actual_cpu; | ||
226 | |||
227 | /* | ||
228 | * Before this is called from setup, we just have one lock for | ||
229 | * all atomic objects/operations. Here we replace the | ||
230 | * elements of atomic_lock_ptr so that they point at per_cpu | ||
231 | * integers. This seemingly over-complex approach stems from | ||
232 | * the fact that DEFINE_PER_CPU defines an entry for each cpu | ||
233 | * in the grid, not each cpu from 0..ATOMIC_HASH_SIZE-1. But | ||
234 | * for efficient hashing of atomics to their locks we want a | ||
235 | * compile time constant power of 2 for the size of this | ||
236 | * table, so we use ATOMIC_HASH_SIZE. | ||
237 | * | ||
238 | * Here we populate atomic_lock_ptr from the per cpu | ||
239 | * atomic_lock_pool, interspersing by actual cpu so that | ||
240 | * subsequent elements are homed on consecutive cpus. | ||
241 | */ | ||
242 | |||
243 | actual_cpu = cpumask_first(cpu_possible_mask); | ||
244 | |||
245 | for (i = 0; i < ATOMIC_HASH_L1_SIZE; ++i) { | ||
246 | /* | ||
247 | * Preincrement to slightly bias against using cpu 0, | ||
248 | * which has plenty of stuff homed on it already. | ||
249 | */ | ||
250 | actual_cpu = cpumask_next(actual_cpu, cpu_possible_mask); | ||
251 | if (actual_cpu >= nr_cpu_ids) | ||
252 | actual_cpu = cpumask_first(cpu_possible_mask); | ||
253 | |||
254 | atomic_lock_ptr[i] = &per_cpu(atomic_lock_pool, actual_cpu); | ||
255 | } | ||
256 | |||
257 | #else /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */ | ||
258 | |||
259 | /* Validate power-of-two and "bigger than cpus" assumption */ | 160 | /* Validate power-of-two and "bigger than cpus" assumption */ |
260 | BUILD_BUG_ON(ATOMIC_HASH_SIZE & (ATOMIC_HASH_SIZE-1)); | 161 | BUILD_BUG_ON(ATOMIC_HASH_SIZE & (ATOMIC_HASH_SIZE-1)); |
261 | BUG_ON(ATOMIC_HASH_SIZE < nr_cpu_ids); | 162 | BUG_ON(ATOMIC_HASH_SIZE < nr_cpu_ids); |
@@ -279,6 +180,4 @@ void __init __init_atomic_per_cpu(void) | |||
279 | * That should not produce more indices than ATOMIC_HASH_SIZE. | 180 | * That should not produce more indices than ATOMIC_HASH_SIZE. |
280 | */ | 181 | */ |
281 | BUILD_BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE); | 182 | BUILD_BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE); |
282 | |||
283 | #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */ | ||
284 | } | 183 | } |
diff --git a/arch/tile/lib/atomic_asm_32.S b/arch/tile/lib/atomic_asm_32.S index 30638042691d..6bda3132cd61 100644 --- a/arch/tile/lib/atomic_asm_32.S +++ b/arch/tile/lib/atomic_asm_32.S | |||
@@ -164,6 +164,7 @@ STD_ENTRY_SECTION(__atomic\name, .text.atomic) | |||
164 | STD_ENDPROC(__atomic\name) | 164 | STD_ENDPROC(__atomic\name) |
165 | .ifc \bitwidth,32 | 165 | .ifc \bitwidth,32 |
166 | .pushsection __ex_table,"a" | 166 | .pushsection __ex_table,"a" |
167 | .align 4 | ||
167 | .word 1b, __atomic\name | 168 | .word 1b, __atomic\name |
168 | .word 2b, __atomic\name | 169 | .word 2b, __atomic\name |
169 | .word __atomic\name, __atomic_bad_address | 170 | .word __atomic\name, __atomic_bad_address |
diff --git a/arch/tile/lib/cacheflush.c b/arch/tile/lib/cacheflush.c index 8f8ad814b139..9c0ec22009a5 100644 --- a/arch/tile/lib/cacheflush.c +++ b/arch/tile/lib/cacheflush.c | |||
@@ -36,7 +36,8 @@ static inline void force_load(char *p) | |||
36 | * core (if "!hfh") or homed via hash-for-home (if "hfh"), waiting | 36 | * core (if "!hfh") or homed via hash-for-home (if "hfh"), waiting |
37 | * until the memory controller holds the flushed values. | 37 | * until the memory controller holds the flushed values. |
38 | */ | 38 | */ |
39 | void finv_buffer_remote(void *buffer, size_t size, int hfh) | 39 | void __attribute__((optimize("omit-frame-pointer"))) |
40 | finv_buffer_remote(void *buffer, size_t size, int hfh) | ||
40 | { | 41 | { |
41 | char *p, *base; | 42 | char *p, *base; |
42 | size_t step_size, load_count; | 43 | size_t step_size, load_count; |
@@ -147,18 +148,21 @@ void finv_buffer_remote(void *buffer, size_t size, int hfh) | |||
147 | force_load(p); | 148 | force_load(p); |
148 | 149 | ||
149 | /* | 150 | /* |
150 | * Repeat, but with inv's instead of loads, to get rid of the | 151 | * Repeat, but with finv's instead of loads, to get rid of the |
151 | * data we just loaded into our own cache and the old home L3. | 152 | * data we just loaded into our own cache and the old home L3. |
152 | * No need to unroll since inv's don't target a register. | 153 | * No need to unroll since finv's don't target a register. |
154 | * The finv's are guaranteed not to actually flush the data in | ||
155 | * the buffer back to their home, since we just read it, so the | ||
156 | * lines are clean in cache; we will only invalidate those lines. | ||
153 | */ | 157 | */ |
154 | p = (char *)buffer + size - 1; | 158 | p = (char *)buffer + size - 1; |
155 | __insn_inv(p); | 159 | __insn_finv(p); |
156 | p -= step_size; | 160 | p -= step_size; |
157 | p = (char *)((unsigned long)p | (step_size - 1)); | 161 | p = (char *)((unsigned long)p | (step_size - 1)); |
158 | for (; p >= base; p -= step_size) | 162 | for (; p >= base; p -= step_size) |
159 | __insn_inv(p); | 163 | __insn_finv(p); |
160 | 164 | ||
161 | /* Wait for the load+inv's (and thus finvs) to have completed. */ | 165 | /* Wait for these finv's (and thus the first finvs) to be done. */ |
162 | __insn_mf(); | 166 | __insn_mf(); |
163 | 167 | ||
164 | #ifdef __tilegx__ | 168 | #ifdef __tilegx__ |
diff --git a/arch/tile/lib/exports.c b/arch/tile/lib/exports.c index a93b02a25222..82733c87d67e 100644 --- a/arch/tile/lib/exports.c +++ b/arch/tile/lib/exports.c | |||
@@ -22,7 +22,6 @@ EXPORT_SYMBOL(strnlen_user_asm); | |||
22 | EXPORT_SYMBOL(strncpy_from_user_asm); | 22 | EXPORT_SYMBOL(strncpy_from_user_asm); |
23 | EXPORT_SYMBOL(clear_user_asm); | 23 | EXPORT_SYMBOL(clear_user_asm); |
24 | EXPORT_SYMBOL(flush_user_asm); | 24 | EXPORT_SYMBOL(flush_user_asm); |
25 | EXPORT_SYMBOL(inv_user_asm); | ||
26 | EXPORT_SYMBOL(finv_user_asm); | 25 | EXPORT_SYMBOL(finv_user_asm); |
27 | 26 | ||
28 | /* arch/tile/kernel/entry.S */ | 27 | /* arch/tile/kernel/entry.S */ |
@@ -34,6 +33,12 @@ EXPORT_SYMBOL(dump_stack); | |||
34 | /* arch/tile/kernel/head.S */ | 33 | /* arch/tile/kernel/head.S */ |
35 | EXPORT_SYMBOL(empty_zero_page); | 34 | EXPORT_SYMBOL(empty_zero_page); |
36 | 35 | ||
36 | #ifdef CONFIG_FUNCTION_TRACER | ||
37 | /* arch/tile/kernel/mcount_64.S */ | ||
38 | #include <asm/ftrace.h> | ||
39 | EXPORT_SYMBOL(__mcount); | ||
40 | #endif /* CONFIG_FUNCTION_TRACER */ | ||
41 | |||
37 | /* arch/tile/lib/, various memcpy files */ | 42 | /* arch/tile/lib/, various memcpy files */ |
38 | EXPORT_SYMBOL(memcpy); | 43 | EXPORT_SYMBOL(memcpy); |
39 | EXPORT_SYMBOL(__copy_to_user_inatomic); | 44 | EXPORT_SYMBOL(__copy_to_user_inatomic); |
diff --git a/arch/tile/lib/memchr_64.c b/arch/tile/lib/memchr_64.c index 6f867dbf7c56..f8196b3a950e 100644 --- a/arch/tile/lib/memchr_64.c +++ b/arch/tile/lib/memchr_64.c | |||
@@ -36,7 +36,7 @@ void *memchr(const void *s, int c, size_t n) | |||
36 | p = (const uint64_t *)(s_int & -8); | 36 | p = (const uint64_t *)(s_int & -8); |
37 | 37 | ||
38 | /* Create eight copies of the byte for which we are looking. */ | 38 | /* Create eight copies of the byte for which we are looking. */ |
39 | goal = 0x0101010101010101ULL * (uint8_t) c; | 39 | goal = copy_byte(c); |
40 | 40 | ||
41 | /* Read the first word, but munge it so that bytes before the array | 41 | /* Read the first word, but munge it so that bytes before the array |
42 | * will not match goal. | 42 | * will not match goal. |
diff --git a/arch/tile/lib/memcpy_32.S b/arch/tile/lib/memcpy_32.S index 2a419a6122db..a2771ae5da53 100644 --- a/arch/tile/lib/memcpy_32.S +++ b/arch/tile/lib/memcpy_32.S | |||
@@ -22,14 +22,6 @@ | |||
22 | 22 | ||
23 | #include <linux/linkage.h> | 23 | #include <linux/linkage.h> |
24 | 24 | ||
25 | /* On TILE64, we wrap these functions via arch/tile/lib/memcpy_tile64.c */ | ||
26 | #if !CHIP_HAS_COHERENT_LOCAL_CACHE() | ||
27 | #define memcpy __memcpy_asm | ||
28 | #define __copy_to_user_inatomic __copy_to_user_inatomic_asm | ||
29 | #define __copy_from_user_inatomic __copy_from_user_inatomic_asm | ||
30 | #define __copy_from_user_zeroing __copy_from_user_zeroing_asm | ||
31 | #endif | ||
32 | |||
33 | #define IS_MEMCPY 0 | 25 | #define IS_MEMCPY 0 |
34 | #define IS_COPY_FROM_USER 1 | 26 | #define IS_COPY_FROM_USER 1 |
35 | #define IS_COPY_FROM_USER_ZEROING 2 | 27 | #define IS_COPY_FROM_USER_ZEROING 2 |
@@ -44,6 +36,7 @@ | |||
44 | */ | 36 | */ |
45 | #define EX \ | 37 | #define EX \ |
46 | .pushsection __ex_table, "a"; \ | 38 | .pushsection __ex_table, "a"; \ |
39 | .align 4; \ | ||
47 | .word 9f, memcpy_common_fixup; \ | 40 | .word 9f, memcpy_common_fixup; \ |
48 | .popsection; \ | 41 | .popsection; \ |
49 | 9 | 42 | 9 |
@@ -158,12 +151,9 @@ EX: { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 } | |||
158 | 151 | ||
159 | { addi r3, r1, 60; andi r9, r9, -64 } | 152 | { addi r3, r1, 60; andi r9, r9, -64 } |
160 | 153 | ||
161 | #if CHIP_HAS_WH64() | ||
162 | /* No need to prefetch dst, we'll just do the wh64 | 154 | /* No need to prefetch dst, we'll just do the wh64 |
163 | * right before we copy a line. | 155 | * right before we copy a line. |
164 | */ | 156 | */ |
165 | #endif | ||
166 | |||
167 | EX: { lw r5, r3; addi r3, r3, 64; movei r4, 1 } | 157 | EX: { lw r5, r3; addi r3, r3, 64; movei r4, 1 } |
168 | /* Intentionally stall for a few cycles to leave L2 cache alone. */ | 158 | /* Intentionally stall for a few cycles to leave L2 cache alone. */ |
169 | { bnzt zero, .; move r27, lr } | 159 | { bnzt zero, .; move r27, lr } |
@@ -171,21 +161,6 @@ EX: { lw r6, r3; addi r3, r3, 64 } | |||
171 | /* Intentionally stall for a few cycles to leave L2 cache alone. */ | 161 | /* Intentionally stall for a few cycles to leave L2 cache alone. */ |
172 | { bnzt zero, . } | 162 | { bnzt zero, . } |
173 | EX: { lw r7, r3; addi r3, r3, 64 } | 163 | EX: { lw r7, r3; addi r3, r3, 64 } |
174 | #if !CHIP_HAS_WH64() | ||
175 | /* Prefetch the dest */ | ||
176 | /* Intentionally stall for a few cycles to leave L2 cache alone. */ | ||
177 | { bnzt zero, . } | ||
178 | /* Use a real load to cause a TLB miss if necessary. We aren't using | ||
179 | * r28, so this should be fine. | ||
180 | */ | ||
181 | EX: { lw r28, r9; addi r9, r9, 64 } | ||
182 | /* Intentionally stall for a few cycles to leave L2 cache alone. */ | ||
183 | { bnzt zero, . } | ||
184 | { prefetch r9; addi r9, r9, 64 } | ||
185 | /* Intentionally stall for a few cycles to leave L2 cache alone. */ | ||
186 | { bnzt zero, . } | ||
187 | { prefetch r9; addi r9, r9, 64 } | ||
188 | #endif | ||
189 | /* Intentionally stall for a few cycles to leave L2 cache alone. */ | 164 | /* Intentionally stall for a few cycles to leave L2 cache alone. */ |
190 | { bz zero, .Lbig_loop2 } | 165 | { bz zero, .Lbig_loop2 } |
191 | 166 | ||
@@ -286,13 +261,8 @@ EX: { lw r7, r3; addi r3, r3, 64 } | |||
286 | /* Fill second L1D line. */ | 261 | /* Fill second L1D line. */ |
287 | EX: { lw r17, r17; addi r1, r1, 48; mvz r3, r13, r1 } /* r17 = WORD_4 */ | 262 | EX: { lw r17, r17; addi r1, r1, 48; mvz r3, r13, r1 } /* r17 = WORD_4 */ |
288 | 263 | ||
289 | #if CHIP_HAS_WH64() | ||
290 | /* Prepare destination line for writing. */ | 264 | /* Prepare destination line for writing. */ |
291 | EX: { wh64 r9; addi r9, r9, 64 } | 265 | EX: { wh64 r9; addi r9, r9, 64 } |
292 | #else | ||
293 | /* Prefetch dest line */ | ||
294 | { prefetch r9; addi r9, r9, 64 } | ||
295 | #endif | ||
296 | /* Load seven words that are L1D hits to cover wh64 L2 usage. */ | 266 | /* Load seven words that are L1D hits to cover wh64 L2 usage. */ |
297 | 267 | ||
298 | /* Load the three remaining words from the last L1D line, which | 268 | /* Load the three remaining words from the last L1D line, which |
@@ -330,16 +300,7 @@ EX: { lw r18, r1; addi r1, r1, 4 } /* r18 = WORD_8 */ | |||
330 | EX: { sw r0, r16; addi r0, r0, 4; add r16, r0, r2 } /* store(WORD_0) */ | 300 | EX: { sw r0, r16; addi r0, r0, 4; add r16, r0, r2 } /* store(WORD_0) */ |
331 | EX: { sw r0, r13; addi r0, r0, 4; andi r16, r16, -64 } /* store(WORD_1) */ | 301 | EX: { sw r0, r13; addi r0, r0, 4; andi r16, r16, -64 } /* store(WORD_1) */ |
332 | EX: { sw r0, r14; addi r0, r0, 4; slt_u r16, r9, r16 } /* store(WORD_2) */ | 302 | EX: { sw r0, r14; addi r0, r0, 4; slt_u r16, r9, r16 } /* store(WORD_2) */ |
333 | #if CHIP_HAS_WH64() | ||
334 | EX: { sw r0, r15; addi r0, r0, 4; addi r13, sp, -64 } /* store(WORD_3) */ | 303 | EX: { sw r0, r15; addi r0, r0, 4; addi r13, sp, -64 } /* store(WORD_3) */ |
335 | #else | ||
336 | /* Back up the r9 to a cache line we are already storing to | ||
337 | * if it gets past the end of the dest vector. Strictly speaking, | ||
338 | * we don't need to back up to the start of a cache line, but it's free | ||
339 | * and tidy, so why not? | ||
340 | */ | ||
341 | EX: { sw r0, r15; addi r0, r0, 4; andi r13, r0, -64 } /* store(WORD_3) */ | ||
342 | #endif | ||
343 | /* Store second L1D line. */ | 304 | /* Store second L1D line. */ |
344 | EX: { sw r0, r17; addi r0, r0, 4; mvz r9, r16, r13 }/* store(WORD_4) */ | 305 | EX: { sw r0, r17; addi r0, r0, 4; mvz r9, r16, r13 }/* store(WORD_4) */ |
345 | EX: { sw r0, r19; addi r0, r0, 4 } /* store(WORD_5) */ | 306 | EX: { sw r0, r19; addi r0, r0, 4 } /* store(WORD_5) */ |
@@ -403,7 +364,6 @@ EX: { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 } | |||
403 | 364 | ||
404 | .Ldest_is_word_aligned: | 365 | .Ldest_is_word_aligned: |
405 | 366 | ||
406 | #if CHIP_HAS_DWORD_ALIGN() | ||
407 | EX: { andi r8, r0, 63; lwadd_na r6, r1, 4} | 367 | EX: { andi r8, r0, 63; lwadd_na r6, r1, 4} |
408 | { slti_u r9, r2, 64; bz r8, .Ldest_is_L2_line_aligned } | 368 | { slti_u r9, r2, 64; bz r8, .Ldest_is_L2_line_aligned } |
409 | 369 | ||
@@ -511,26 +471,6 @@ EX: { swadd r0, r13, 4; addi r2, r2, -32 } | |||
511 | /* Move r1 back to the point where it corresponds to r0. */ | 471 | /* Move r1 back to the point where it corresponds to r0. */ |
512 | { addi r1, r1, -4 } | 472 | { addi r1, r1, -4 } |
513 | 473 | ||
514 | #else /* !CHIP_HAS_DWORD_ALIGN() */ | ||
515 | |||
516 | /* Compute right/left shift counts and load initial source words. */ | ||
517 | { andi r5, r1, -4; andi r3, r1, 3 } | ||
518 | EX: { lw r6, r5; addi r5, r5, 4; shli r3, r3, 3 } | ||
519 | EX: { lw r7, r5; addi r5, r5, 4; sub r4, zero, r3 } | ||
520 | |||
521 | /* Load and store one word at a time, using shifts and ORs | ||
522 | * to correct for the misaligned src. | ||
523 | */ | ||
524 | .Lcopy_unaligned_src_loop: | ||
525 | { shr r6, r6, r3; shl r8, r7, r4 } | ||
526 | EX: { lw r7, r5; or r8, r8, r6; move r6, r7 } | ||
527 | EX: { sw r0, r8; addi r0, r0, 4; addi r2, r2, -4 } | ||
528 | { addi r5, r5, 4; slti_u r8, r2, 8 } | ||
529 | { bzt r8, .Lcopy_unaligned_src_loop; addi r1, r1, 4 } | ||
530 | |||
531 | { bz r2, .Lcopy_unaligned_done } | ||
532 | #endif /* !CHIP_HAS_DWORD_ALIGN() */ | ||
533 | |||
534 | /* Fall through */ | 474 | /* Fall through */ |
535 | 475 | ||
536 | /* | 476 | /* |
@@ -614,5 +554,6 @@ memcpy_fixup_loop: | |||
614 | .size memcpy_common_fixup, . - memcpy_common_fixup | 554 | .size memcpy_common_fixup, . - memcpy_common_fixup |
615 | 555 | ||
616 | .section __ex_table,"a" | 556 | .section __ex_table,"a" |
557 | .align 4 | ||
617 | .word .Lcfu, .Lcopy_from_user_fixup_zero_remainder | 558 | .word .Lcfu, .Lcopy_from_user_fixup_zero_remainder |
618 | .word .Lctu, .Lcopy_to_user_fixup_done | 559 | .word .Lctu, .Lcopy_to_user_fixup_done |
diff --git a/arch/tile/lib/memcpy_64.c b/arch/tile/lib/memcpy_64.c index c79b8e7c6828..4815354b8cd2 100644 --- a/arch/tile/lib/memcpy_64.c +++ b/arch/tile/lib/memcpy_64.c | |||
@@ -18,14 +18,17 @@ | |||
18 | /* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */ | 18 | /* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */ |
19 | 19 | ||
20 | /* Must be 8 bytes in size. */ | 20 | /* Must be 8 bytes in size. */ |
21 | #define word_t uint64_t | 21 | #define op_t uint64_t |
22 | 22 | ||
23 | #if CHIP_L2_LINE_SIZE() != 64 && CHIP_L2_LINE_SIZE() != 128 | 23 | /* Threshold value for when to enter the unrolled loops. */ |
24 | #error "Assumes 64 or 128 byte line size" | 24 | #define OP_T_THRES 16 |
25 | |||
26 | #if CHIP_L2_LINE_SIZE() != 64 | ||
27 | #error "Assumes 64 byte line size" | ||
25 | #endif | 28 | #endif |
26 | 29 | ||
27 | /* How many cache lines ahead should we prefetch? */ | 30 | /* How many cache lines ahead should we prefetch? */ |
28 | #define PREFETCH_LINES_AHEAD 3 | 31 | #define PREFETCH_LINES_AHEAD 4 |
29 | 32 | ||
30 | /* | 33 | /* |
31 | * Provide "base versions" of load and store for the normal code path. | 34 | * Provide "base versions" of load and store for the normal code path. |
@@ -51,15 +54,16 @@ void *memcpy(void *__restrict dstv, const void *__restrict srcv, size_t n) | |||
51 | * macros to return a count of uncopied bytes due to mm fault. | 54 | * macros to return a count of uncopied bytes due to mm fault. |
52 | */ | 55 | */ |
53 | #define RETVAL 0 | 56 | #define RETVAL 0 |
54 | int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n) | 57 | int __attribute__((optimize("omit-frame-pointer"))) |
58 | USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n) | ||
55 | #endif | 59 | #endif |
56 | { | 60 | { |
57 | char *__restrict dst1 = (char *)dstv; | 61 | char *__restrict dst1 = (char *)dstv; |
58 | const char *__restrict src1 = (const char *)srcv; | 62 | const char *__restrict src1 = (const char *)srcv; |
59 | const char *__restrict src1_end; | 63 | const char *__restrict src1_end; |
60 | const char *__restrict prefetch; | 64 | const char *__restrict prefetch; |
61 | word_t *__restrict dst8; /* 8-byte pointer to destination memory. */ | 65 | op_t *__restrict dst8; /* 8-byte pointer to destination memory. */ |
62 | word_t final; /* Final bytes to write to trailing word, if any */ | 66 | op_t final; /* Final bytes to write to trailing word, if any */ |
63 | long i; | 67 | long i; |
64 | 68 | ||
65 | if (n < 16) { | 69 | if (n < 16) { |
@@ -79,104 +83,228 @@ int USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n) | |||
79 | for (i = 0; i < PREFETCH_LINES_AHEAD; i++) { | 83 | for (i = 0; i < PREFETCH_LINES_AHEAD; i++) { |
80 | __insn_prefetch(prefetch); | 84 | __insn_prefetch(prefetch); |
81 | prefetch += CHIP_L2_LINE_SIZE(); | 85 | prefetch += CHIP_L2_LINE_SIZE(); |
82 | prefetch = (prefetch > src1_end) ? prefetch : src1; | 86 | prefetch = (prefetch < src1_end) ? prefetch : src1; |
83 | } | 87 | } |
84 | 88 | ||
85 | /* Copy bytes until dst is word-aligned. */ | 89 | /* Copy bytes until dst is word-aligned. */ |
86 | for (; (uintptr_t)dst1 & (sizeof(word_t) - 1); n--) | 90 | for (; (uintptr_t)dst1 & (sizeof(op_t) - 1); n--) |
87 | ST1(dst1++, LD1(src1++)); | 91 | ST1(dst1++, LD1(src1++)); |
88 | 92 | ||
89 | /* 8-byte pointer to destination memory. */ | 93 | /* 8-byte pointer to destination memory. */ |
90 | dst8 = (word_t *)dst1; | 94 | dst8 = (op_t *)dst1; |
91 | 95 | ||
92 | if (__builtin_expect((uintptr_t)src1 & (sizeof(word_t) - 1), 0)) { | 96 | if (__builtin_expect((uintptr_t)src1 & (sizeof(op_t) - 1), 0)) { |
93 | /* | 97 | /* Unaligned copy. */ |
94 | * Misaligned copy. Copy 8 bytes at a time, but don't | 98 | |
95 | * bother with other fanciness. | 99 | op_t tmp0 = 0, tmp1 = 0, tmp2, tmp3; |
96 | * | 100 | const op_t *src8 = (const op_t *) ((uintptr_t)src1 & |
97 | * TODO: Consider prefetching and using wh64 as well. | 101 | -sizeof(op_t)); |
98 | */ | 102 | const void *srci = (void *)src1; |
99 | 103 | int m; | |
100 | /* Create an aligned src8. */ | 104 | |
101 | const word_t *__restrict src8 = | 105 | m = (CHIP_L2_LINE_SIZE() << 2) - |
102 | (const word_t *)((uintptr_t)src1 & -sizeof(word_t)); | 106 | (((uintptr_t)dst8) & ((CHIP_L2_LINE_SIZE() << 2) - 1)); |
103 | word_t b; | 107 | m = (n < m) ? n : m; |
104 | 108 | m /= sizeof(op_t); | |
105 | word_t a = LD8(src8++); | 109 | |
106 | for (; n >= sizeof(word_t); n -= sizeof(word_t)) { | 110 | /* Copy until 'dst' is cache-line-aligned. */ |
107 | b = LD8(src8++); | 111 | n -= (sizeof(op_t) * m); |
108 | a = __insn_dblalign(a, b, src1); | 112 | |
109 | ST8(dst8++, a); | 113 | switch (m % 4) { |
110 | a = b; | 114 | case 0: |
115 | if (__builtin_expect(!m, 0)) | ||
116 | goto _M0; | ||
117 | tmp1 = LD8(src8++); | ||
118 | tmp2 = LD8(src8++); | ||
119 | goto _8B3; | ||
120 | case 2: | ||
121 | m += 2; | ||
122 | tmp3 = LD8(src8++); | ||
123 | tmp0 = LD8(src8++); | ||
124 | goto _8B1; | ||
125 | case 3: | ||
126 | m += 1; | ||
127 | tmp2 = LD8(src8++); | ||
128 | tmp3 = LD8(src8++); | ||
129 | goto _8B2; | ||
130 | case 1: | ||
131 | m--; | ||
132 | tmp0 = LD8(src8++); | ||
133 | tmp1 = LD8(src8++); | ||
134 | if (__builtin_expect(!m, 0)) | ||
135 | goto _8B0; | ||
136 | } | ||
137 | |||
138 | do { | ||
139 | tmp2 = LD8(src8++); | ||
140 | tmp0 = __insn_dblalign(tmp0, tmp1, srci); | ||
141 | ST8(dst8++, tmp0); | ||
142 | _8B3: | ||
143 | tmp3 = LD8(src8++); | ||
144 | tmp1 = __insn_dblalign(tmp1, tmp2, srci); | ||
145 | ST8(dst8++, tmp1); | ||
146 | _8B2: | ||
147 | tmp0 = LD8(src8++); | ||
148 | tmp2 = __insn_dblalign(tmp2, tmp3, srci); | ||
149 | ST8(dst8++, tmp2); | ||
150 | _8B1: | ||
151 | tmp1 = LD8(src8++); | ||
152 | tmp3 = __insn_dblalign(tmp3, tmp0, srci); | ||
153 | ST8(dst8++, tmp3); | ||
154 | m -= 4; | ||
155 | } while (m); | ||
156 | |||
157 | _8B0: | ||
158 | tmp0 = __insn_dblalign(tmp0, tmp1, srci); | ||
159 | ST8(dst8++, tmp0); | ||
160 | src8--; | ||
161 | |||
162 | _M0: | ||
163 | if (__builtin_expect(n >= CHIP_L2_LINE_SIZE(), 0)) { | ||
164 | op_t tmp4, tmp5, tmp6, tmp7, tmp8; | ||
165 | |||
166 | prefetch = ((const char *)src8) + | ||
167 | CHIP_L2_LINE_SIZE() * PREFETCH_LINES_AHEAD; | ||
168 | |||
169 | for (tmp0 = LD8(src8++); n >= CHIP_L2_LINE_SIZE(); | ||
170 | n -= CHIP_L2_LINE_SIZE()) { | ||
171 | /* Prefetch and advance to next line to | ||
172 | prefetch, but don't go past the end. */ | ||
173 | __insn_prefetch(prefetch); | ||
174 | |||
175 | /* Make sure prefetch got scheduled | ||
176 | earlier. */ | ||
177 | __asm__ ("" : : : "memory"); | ||
178 | |||
179 | prefetch += CHIP_L2_LINE_SIZE(); | ||
180 | prefetch = (prefetch < src1_end) ? prefetch : | ||
181 | (const char *) src8; | ||
182 | |||
183 | tmp1 = LD8(src8++); | ||
184 | tmp2 = LD8(src8++); | ||
185 | tmp3 = LD8(src8++); | ||
186 | tmp4 = LD8(src8++); | ||
187 | tmp5 = LD8(src8++); | ||
188 | tmp6 = LD8(src8++); | ||
189 | tmp7 = LD8(src8++); | ||
190 | tmp8 = LD8(src8++); | ||
191 | |||
192 | tmp0 = __insn_dblalign(tmp0, tmp1, srci); | ||
193 | tmp1 = __insn_dblalign(tmp1, tmp2, srci); | ||
194 | tmp2 = __insn_dblalign(tmp2, tmp3, srci); | ||
195 | tmp3 = __insn_dblalign(tmp3, tmp4, srci); | ||
196 | tmp4 = __insn_dblalign(tmp4, tmp5, srci); | ||
197 | tmp5 = __insn_dblalign(tmp5, tmp6, srci); | ||
198 | tmp6 = __insn_dblalign(tmp6, tmp7, srci); | ||
199 | tmp7 = __insn_dblalign(tmp7, tmp8, srci); | ||
200 | |||
201 | __insn_wh64(dst8); | ||
202 | |||
203 | ST8(dst8++, tmp0); | ||
204 | ST8(dst8++, tmp1); | ||
205 | ST8(dst8++, tmp2); | ||
206 | ST8(dst8++, tmp3); | ||
207 | ST8(dst8++, tmp4); | ||
208 | ST8(dst8++, tmp5); | ||
209 | ST8(dst8++, tmp6); | ||
210 | ST8(dst8++, tmp7); | ||
211 | |||
212 | tmp0 = tmp8; | ||
213 | } | ||
214 | src8--; | ||
215 | } | ||
216 | |||
217 | /* Copy the rest 8-byte chunks. */ | ||
218 | if (n >= sizeof(op_t)) { | ||
219 | tmp0 = LD8(src8++); | ||
220 | for (; n >= sizeof(op_t); n -= sizeof(op_t)) { | ||
221 | tmp1 = LD8(src8++); | ||
222 | tmp0 = __insn_dblalign(tmp0, tmp1, srci); | ||
223 | ST8(dst8++, tmp0); | ||
224 | tmp0 = tmp1; | ||
225 | } | ||
226 | src8--; | ||
111 | } | 227 | } |
112 | 228 | ||
113 | if (n == 0) | 229 | if (n == 0) |
114 | return RETVAL; | 230 | return RETVAL; |
115 | 231 | ||
116 | b = ((const char *)src8 <= src1_end) ? *src8 : 0; | 232 | tmp0 = LD8(src8++); |
233 | tmp1 = ((const char *)src8 <= src1_end) | ||
234 | ? LD8((op_t *)src8) : 0; | ||
235 | final = __insn_dblalign(tmp0, tmp1, srci); | ||
117 | 236 | ||
118 | /* | ||
119 | * Final source bytes to write to trailing partial | ||
120 | * word, if any. | ||
121 | */ | ||
122 | final = __insn_dblalign(a, b, src1); | ||
123 | } else { | 237 | } else { |
124 | /* Aligned copy. */ | 238 | /* Aligned copy. */ |
125 | 239 | ||
126 | const word_t* __restrict src8 = (const word_t *)src1; | 240 | const op_t *__restrict src8 = (const op_t *)src1; |
127 | 241 | ||
128 | /* src8 and dst8 are both word-aligned. */ | 242 | /* src8 and dst8 are both word-aligned. */ |
129 | if (n >= CHIP_L2_LINE_SIZE()) { | 243 | if (n >= CHIP_L2_LINE_SIZE()) { |
130 | /* Copy until 'dst' is cache-line-aligned. */ | 244 | /* Copy until 'dst' is cache-line-aligned. */ |
131 | for (; (uintptr_t)dst8 & (CHIP_L2_LINE_SIZE() - 1); | 245 | for (; (uintptr_t)dst8 & (CHIP_L2_LINE_SIZE() - 1); |
132 | n -= sizeof(word_t)) | 246 | n -= sizeof(op_t)) |
133 | ST8(dst8++, LD8(src8++)); | 247 | ST8(dst8++, LD8(src8++)); |
134 | 248 | ||
135 | for (; n >= CHIP_L2_LINE_SIZE(); ) { | 249 | for (; n >= CHIP_L2_LINE_SIZE(); ) { |
136 | __insn_wh64(dst8); | 250 | op_t tmp0, tmp1, tmp2, tmp3; |
251 | op_t tmp4, tmp5, tmp6, tmp7; | ||
137 | 252 | ||
138 | /* | 253 | /* |
139 | * Prefetch and advance to next line | 254 | * Prefetch and advance to next line |
140 | * to prefetch, but don't go past the end | 255 | * to prefetch, but don't go past the |
256 | * end. | ||
141 | */ | 257 | */ |
142 | __insn_prefetch(prefetch); | 258 | __insn_prefetch(prefetch); |
259 | |||
260 | /* Make sure prefetch got scheduled | ||
261 | earlier. */ | ||
262 | __asm__ ("" : : : "memory"); | ||
263 | |||
143 | prefetch += CHIP_L2_LINE_SIZE(); | 264 | prefetch += CHIP_L2_LINE_SIZE(); |
144 | prefetch = (prefetch > src1_end) ? prefetch : | 265 | prefetch = (prefetch < src1_end) ? prefetch : |
145 | (const char *)src8; | 266 | (const char *)src8; |
146 | 267 | ||
147 | /* | 268 | /* |
148 | * Copy an entire cache line. Manually | 269 | * Do all the loads before wh64. This |
149 | * unrolled to avoid idiosyncracies of | 270 | * is necessary if [src8, src8+7] and |
150 | * compiler unrolling. | 271 | * [dst8, dst8+7] share the same cache |
272 | * line and dst8 <= src8, as can be | ||
273 | * the case when called from memmove, | ||
274 | * or with code tested on x86 whose | ||
275 | * memcpy always works with forward | ||
276 | * copies. | ||
151 | */ | 277 | */ |
152 | #define COPY_WORD(offset) ({ ST8(dst8+offset, LD8(src8+offset)); n -= 8; }) | 278 | tmp0 = LD8(src8++); |
153 | COPY_WORD(0); | 279 | tmp1 = LD8(src8++); |
154 | COPY_WORD(1); | 280 | tmp2 = LD8(src8++); |
155 | COPY_WORD(2); | 281 | tmp3 = LD8(src8++); |
156 | COPY_WORD(3); | 282 | tmp4 = LD8(src8++); |
157 | COPY_WORD(4); | 283 | tmp5 = LD8(src8++); |
158 | COPY_WORD(5); | 284 | tmp6 = LD8(src8++); |
159 | COPY_WORD(6); | 285 | tmp7 = LD8(src8++); |
160 | COPY_WORD(7); | 286 | |
161 | #if CHIP_L2_LINE_SIZE() == 128 | 287 | /* wh64 and wait for tmp7 load completion. */ |
162 | COPY_WORD(8); | 288 | __asm__ ("move %0, %0; wh64 %1\n" |
163 | COPY_WORD(9); | 289 | : : "r"(tmp7), "r"(dst8)); |
164 | COPY_WORD(10); | ||
165 | COPY_WORD(11); | ||
166 | COPY_WORD(12); | ||
167 | COPY_WORD(13); | ||
168 | COPY_WORD(14); | ||
169 | COPY_WORD(15); | ||
170 | #elif CHIP_L2_LINE_SIZE() != 64 | ||
171 | # error Fix code that assumes particular L2 cache line sizes | ||
172 | #endif | ||
173 | 290 | ||
174 | dst8 += CHIP_L2_LINE_SIZE() / sizeof(word_t); | 291 | ST8(dst8++, tmp0); |
175 | src8 += CHIP_L2_LINE_SIZE() / sizeof(word_t); | 292 | ST8(dst8++, tmp1); |
293 | ST8(dst8++, tmp2); | ||
294 | ST8(dst8++, tmp3); | ||
295 | ST8(dst8++, tmp4); | ||
296 | ST8(dst8++, tmp5); | ||
297 | ST8(dst8++, tmp6); | ||
298 | ST8(dst8++, tmp7); | ||
299 | |||
300 | n -= CHIP_L2_LINE_SIZE(); | ||
176 | } | 301 | } |
302 | #if CHIP_L2_LINE_SIZE() != 64 | ||
303 | # error "Fix code that assumes particular L2 cache line size." | ||
304 | #endif | ||
177 | } | 305 | } |
178 | 306 | ||
179 | for (; n >= sizeof(word_t); n -= sizeof(word_t)) | 307 | for (; n >= sizeof(op_t); n -= sizeof(op_t)) |
180 | ST8(dst8++, LD8(src8++)); | 308 | ST8(dst8++, LD8(src8++)); |
181 | 309 | ||
182 | if (__builtin_expect(n == 0, 1)) | 310 | if (__builtin_expect(n == 0, 1)) |
diff --git a/arch/tile/lib/memcpy_tile64.c b/arch/tile/lib/memcpy_tile64.c deleted file mode 100644 index 3bc4b4e40d93..000000000000 --- a/arch/tile/lib/memcpy_tile64.c +++ /dev/null | |||
@@ -1,276 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright 2010 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/string.h> | ||
16 | #include <linux/smp.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/uaccess.h> | ||
19 | #include <asm/fixmap.h> | ||
20 | #include <asm/kmap_types.h> | ||
21 | #include <asm/tlbflush.h> | ||
22 | #include <hv/hypervisor.h> | ||
23 | #include <arch/chip.h> | ||
24 | |||
25 | |||
26 | #if !CHIP_HAS_COHERENT_LOCAL_CACHE() | ||
27 | |||
28 | /* Defined in memcpy.S */ | ||
29 | extern unsigned long __memcpy_asm(void *to, const void *from, unsigned long n); | ||
30 | extern unsigned long __copy_to_user_inatomic_asm( | ||
31 | void __user *to, const void *from, unsigned long n); | ||
32 | extern unsigned long __copy_from_user_inatomic_asm( | ||
33 | void *to, const void __user *from, unsigned long n); | ||
34 | extern unsigned long __copy_from_user_zeroing_asm( | ||
35 | void *to, const void __user *from, unsigned long n); | ||
36 | |||
37 | typedef unsigned long (*memcpy_t)(void *, const void *, unsigned long); | ||
38 | |||
39 | /* Size above which to consider TLB games for performance */ | ||
40 | #define LARGE_COPY_CUTOFF 2048 | ||
41 | |||
42 | /* Communicate to the simulator what we are trying to do. */ | ||
43 | #define sim_allow_multiple_caching(b) \ | ||
44 | __insn_mtspr(SPR_SIM_CONTROL, \ | ||
45 | SIM_CONTROL_ALLOW_MULTIPLE_CACHING | ((b) << _SIM_CONTROL_OPERATOR_BITS)) | ||
46 | |||
47 | /* | ||
48 | * Copy memory by briefly enabling incoherent cacheline-at-a-time mode. | ||
49 | * | ||
50 | * We set up our own source and destination PTEs that we fully control. | ||
51 | * This is the only way to guarantee that we don't race with another | ||
52 | * thread that is modifying the PTE; we can't afford to try the | ||
53 | * copy_{to,from}_user() technique of catching the interrupt, since | ||
54 | * we must run with interrupts disabled to avoid the risk of some | ||
55 | * other code seeing the incoherent data in our cache. (Recall that | ||
56 | * our cache is indexed by PA, so even if the other code doesn't use | ||
57 | * our kmap_atomic virtual addresses, they'll still hit in cache using | ||
58 | * the normal VAs that aren't supposed to hit in cache.) | ||
59 | */ | ||
60 | static void memcpy_multicache(void *dest, const void *source, | ||
61 | pte_t dst_pte, pte_t src_pte, int len) | ||
62 | { | ||
63 | int idx; | ||
64 | unsigned long flags, newsrc, newdst; | ||
65 | pmd_t *pmdp; | ||
66 | pte_t *ptep; | ||
67 | int type0, type1; | ||
68 | int cpu = get_cpu(); | ||
69 | |||
70 | /* | ||
71 | * Disable interrupts so that we don't recurse into memcpy() | ||
72 | * in an interrupt handler, nor accidentally reference | ||
73 | * the PA of the source from an interrupt routine. Also | ||
74 | * notify the simulator that we're playing games so we don't | ||
75 | * generate spurious coherency warnings. | ||
76 | */ | ||
77 | local_irq_save(flags); | ||
78 | sim_allow_multiple_caching(1); | ||
79 | |||
80 | /* Set up the new dest mapping */ | ||
81 | type0 = kmap_atomic_idx_push(); | ||
82 | idx = FIX_KMAP_BEGIN + (KM_TYPE_NR * cpu) + type0; | ||
83 | newdst = __fix_to_virt(idx) + ((unsigned long)dest & (PAGE_SIZE-1)); | ||
84 | pmdp = pmd_offset(pud_offset(pgd_offset_k(newdst), newdst), newdst); | ||
85 | ptep = pte_offset_kernel(pmdp, newdst); | ||
86 | if (pte_val(*ptep) != pte_val(dst_pte)) { | ||
87 | set_pte(ptep, dst_pte); | ||
88 | local_flush_tlb_page(NULL, newdst, PAGE_SIZE); | ||
89 | } | ||
90 | |||
91 | /* Set up the new source mapping */ | ||
92 | type1 = kmap_atomic_idx_push(); | ||
93 | idx += (type0 - type1); | ||
94 | src_pte = hv_pte_set_nc(src_pte); | ||
95 | src_pte = hv_pte_clear_writable(src_pte); /* be paranoid */ | ||
96 | newsrc = __fix_to_virt(idx) + ((unsigned long)source & (PAGE_SIZE-1)); | ||
97 | pmdp = pmd_offset(pud_offset(pgd_offset_k(newsrc), newsrc), newsrc); | ||
98 | ptep = pte_offset_kernel(pmdp, newsrc); | ||
99 | __set_pte(ptep, src_pte); /* set_pte() would be confused by this */ | ||
100 | local_flush_tlb_page(NULL, newsrc, PAGE_SIZE); | ||
101 | |||
102 | /* Actually move the data. */ | ||
103 | __memcpy_asm((void *)newdst, (const void *)newsrc, len); | ||
104 | |||
105 | /* | ||
106 | * Remap the source as locally-cached and not OLOC'ed so that | ||
107 | * we can inval without also invaling the remote cpu's cache. | ||
108 | * This also avoids known errata with inv'ing cacheable oloc data. | ||
109 | */ | ||
110 | src_pte = hv_pte_set_mode(src_pte, HV_PTE_MODE_CACHE_NO_L3); | ||
111 | src_pte = hv_pte_set_writable(src_pte); /* need write access for inv */ | ||
112 | __set_pte(ptep, src_pte); /* set_pte() would be confused by this */ | ||
113 | local_flush_tlb_page(NULL, newsrc, PAGE_SIZE); | ||
114 | |||
115 | /* | ||
116 | * Do the actual invalidation, covering the full L2 cache line | ||
117 | * at the end since __memcpy_asm() is somewhat aggressive. | ||
118 | */ | ||
119 | __inv_buffer((void *)newsrc, len); | ||
120 | |||
121 | /* | ||
122 | * We're done: notify the simulator that all is back to normal, | ||
123 | * and re-enable interrupts and pre-emption. | ||
124 | */ | ||
125 | kmap_atomic_idx_pop(); | ||
126 | kmap_atomic_idx_pop(); | ||
127 | sim_allow_multiple_caching(0); | ||
128 | local_irq_restore(flags); | ||
129 | put_cpu(); | ||
130 | } | ||
131 | |||
132 | /* | ||
133 | * Identify large copies from remotely-cached memory, and copy them | ||
134 | * via memcpy_multicache() if they look good, otherwise fall back | ||
135 | * to the particular kind of copying passed as the memcpy_t function. | ||
136 | */ | ||
137 | static unsigned long fast_copy(void *dest, const void *source, int len, | ||
138 | memcpy_t func) | ||
139 | { | ||
140 | /* | ||
141 | * Check if it's big enough to bother with. We may end up doing a | ||
142 | * small copy via TLB manipulation if we're near a page boundary, | ||
143 | * but presumably we'll make it up when we hit the second page. | ||
144 | */ | ||
145 | while (len >= LARGE_COPY_CUTOFF) { | ||
146 | int copy_size, bytes_left_on_page; | ||
147 | pte_t *src_ptep, *dst_ptep; | ||
148 | pte_t src_pte, dst_pte; | ||
149 | struct page *src_page, *dst_page; | ||
150 | |||
151 | /* Is the source page oloc'ed to a remote cpu? */ | ||
152 | retry_source: | ||
153 | src_ptep = virt_to_pte(current->mm, (unsigned long)source); | ||
154 | if (src_ptep == NULL) | ||
155 | break; | ||
156 | src_pte = *src_ptep; | ||
157 | if (!hv_pte_get_present(src_pte) || | ||
158 | !hv_pte_get_readable(src_pte) || | ||
159 | hv_pte_get_mode(src_pte) != HV_PTE_MODE_CACHE_TILE_L3) | ||
160 | break; | ||
161 | if (get_remote_cache_cpu(src_pte) == smp_processor_id()) | ||
162 | break; | ||
163 | src_page = pfn_to_page(pte_pfn(src_pte)); | ||
164 | get_page(src_page); | ||
165 | if (pte_val(src_pte) != pte_val(*src_ptep)) { | ||
166 | put_page(src_page); | ||
167 | goto retry_source; | ||
168 | } | ||
169 | if (pte_huge(src_pte)) { | ||
170 | /* Adjust the PTE to correspond to a small page */ | ||
171 | int pfn = pte_pfn(src_pte); | ||
172 | pfn += (((unsigned long)source & (HPAGE_SIZE-1)) | ||
173 | >> PAGE_SHIFT); | ||
174 | src_pte = pfn_pte(pfn, src_pte); | ||
175 | src_pte = pte_mksmall(src_pte); | ||
176 | } | ||
177 | |||
178 | /* Is the destination page writable? */ | ||
179 | retry_dest: | ||
180 | dst_ptep = virt_to_pte(current->mm, (unsigned long)dest); | ||
181 | if (dst_ptep == NULL) { | ||
182 | put_page(src_page); | ||
183 | break; | ||
184 | } | ||
185 | dst_pte = *dst_ptep; | ||
186 | if (!hv_pte_get_present(dst_pte) || | ||
187 | !hv_pte_get_writable(dst_pte)) { | ||
188 | put_page(src_page); | ||
189 | break; | ||
190 | } | ||
191 | dst_page = pfn_to_page(pte_pfn(dst_pte)); | ||
192 | if (dst_page == src_page) { | ||
193 | /* | ||
194 | * Source and dest are on the same page; this | ||
195 | * potentially exposes us to incoherence if any | ||
196 | * part of src and dest overlap on a cache line. | ||
197 | * Just give up rather than trying to be precise. | ||
198 | */ | ||
199 | put_page(src_page); | ||
200 | break; | ||
201 | } | ||
202 | get_page(dst_page); | ||
203 | if (pte_val(dst_pte) != pte_val(*dst_ptep)) { | ||
204 | put_page(dst_page); | ||
205 | goto retry_dest; | ||
206 | } | ||
207 | if (pte_huge(dst_pte)) { | ||
208 | /* Adjust the PTE to correspond to a small page */ | ||
209 | int pfn = pte_pfn(dst_pte); | ||
210 | pfn += (((unsigned long)dest & (HPAGE_SIZE-1)) | ||
211 | >> PAGE_SHIFT); | ||
212 | dst_pte = pfn_pte(pfn, dst_pte); | ||
213 | dst_pte = pte_mksmall(dst_pte); | ||
214 | } | ||
215 | |||
216 | /* All looks good: create a cachable PTE and copy from it */ | ||
217 | copy_size = len; | ||
218 | bytes_left_on_page = | ||
219 | PAGE_SIZE - (((int)source) & (PAGE_SIZE-1)); | ||
220 | if (copy_size > bytes_left_on_page) | ||
221 | copy_size = bytes_left_on_page; | ||
222 | bytes_left_on_page = | ||
223 | PAGE_SIZE - (((int)dest) & (PAGE_SIZE-1)); | ||
224 | if (copy_size > bytes_left_on_page) | ||
225 | copy_size = bytes_left_on_page; | ||
226 | memcpy_multicache(dest, source, dst_pte, src_pte, copy_size); | ||
227 | |||
228 | /* Release the pages */ | ||
229 | put_page(dst_page); | ||
230 | put_page(src_page); | ||
231 | |||
232 | /* Continue on the next page */ | ||
233 | dest += copy_size; | ||
234 | source += copy_size; | ||
235 | len -= copy_size; | ||
236 | } | ||
237 | |||
238 | return func(dest, source, len); | ||
239 | } | ||
240 | |||
241 | void *memcpy(void *to, const void *from, __kernel_size_t n) | ||
242 | { | ||
243 | if (n < LARGE_COPY_CUTOFF) | ||
244 | return (void *)__memcpy_asm(to, from, n); | ||
245 | else | ||
246 | return (void *)fast_copy(to, from, n, __memcpy_asm); | ||
247 | } | ||
248 | |||
249 | unsigned long __copy_to_user_inatomic(void __user *to, const void *from, | ||
250 | unsigned long n) | ||
251 | { | ||
252 | if (n < LARGE_COPY_CUTOFF) | ||
253 | return __copy_to_user_inatomic_asm(to, from, n); | ||
254 | else | ||
255 | return fast_copy(to, from, n, __copy_to_user_inatomic_asm); | ||
256 | } | ||
257 | |||
258 | unsigned long __copy_from_user_inatomic(void *to, const void __user *from, | ||
259 | unsigned long n) | ||
260 | { | ||
261 | if (n < LARGE_COPY_CUTOFF) | ||
262 | return __copy_from_user_inatomic_asm(to, from, n); | ||
263 | else | ||
264 | return fast_copy(to, from, n, __copy_from_user_inatomic_asm); | ||
265 | } | ||
266 | |||
267 | unsigned long __copy_from_user_zeroing(void *to, const void __user *from, | ||
268 | unsigned long n) | ||
269 | { | ||
270 | if (n < LARGE_COPY_CUTOFF) | ||
271 | return __copy_from_user_zeroing_asm(to, from, n); | ||
272 | else | ||
273 | return fast_copy(to, from, n, __copy_from_user_zeroing_asm); | ||
274 | } | ||
275 | |||
276 | #endif /* !CHIP_HAS_COHERENT_LOCAL_CACHE() */ | ||
diff --git a/arch/tile/lib/memcpy_user_64.c b/arch/tile/lib/memcpy_user_64.c index 37440caa7370..88c7016492c4 100644 --- a/arch/tile/lib/memcpy_user_64.c +++ b/arch/tile/lib/memcpy_user_64.c | |||
@@ -31,6 +31,7 @@ | |||
31 | ".pushsection .coldtext.memcpy,\"ax\";" \ | 31 | ".pushsection .coldtext.memcpy,\"ax\";" \ |
32 | "2: { move r0, %2; jrp lr };" \ | 32 | "2: { move r0, %2; jrp lr };" \ |
33 | ".section __ex_table,\"a\";" \ | 33 | ".section __ex_table,\"a\";" \ |
34 | ".align 8;" \ | ||
34 | ".quad 1b, 2b;" \ | 35 | ".quad 1b, 2b;" \ |
35 | ".popsection" \ | 36 | ".popsection" \ |
36 | : "=m" (*(p)) : "r" (v), "r" (n)); \ | 37 | : "=m" (*(p)) : "r" (v), "r" (n)); \ |
@@ -43,6 +44,7 @@ | |||
43 | ".pushsection .coldtext.memcpy,\"ax\";" \ | 44 | ".pushsection .coldtext.memcpy,\"ax\";" \ |
44 | "2: { move r0, %2; jrp lr };" \ | 45 | "2: { move r0, %2; jrp lr };" \ |
45 | ".section __ex_table,\"a\";" \ | 46 | ".section __ex_table,\"a\";" \ |
47 | ".align 8;" \ | ||
46 | ".quad 1b, 2b;" \ | 48 | ".quad 1b, 2b;" \ |
47 | ".popsection" \ | 49 | ".popsection" \ |
48 | : "=r" (__v) : "m" (*(p)), "r" (n)); \ | 50 | : "=r" (__v) : "m" (*(p)), "r" (n)); \ |
diff --git a/arch/tile/lib/memset_32.c b/arch/tile/lib/memset_32.c index 57dbb3a5bff8..2042bfe6595f 100644 --- a/arch/tile/lib/memset_32.c +++ b/arch/tile/lib/memset_32.c | |||
@@ -12,13 +12,10 @@ | |||
12 | * more details. | 12 | * more details. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <arch/chip.h> | ||
16 | |||
17 | #include <linux/types.h> | 15 | #include <linux/types.h> |
18 | #include <linux/string.h> | 16 | #include <linux/string.h> |
19 | #include <linux/module.h> | 17 | #include <linux/module.h> |
20 | 18 | #include <arch/chip.h> | |
21 | #undef memset | ||
22 | 19 | ||
23 | void *memset(void *s, int c, size_t n) | 20 | void *memset(void *s, int c, size_t n) |
24 | { | 21 | { |
@@ -26,11 +23,7 @@ void *memset(void *s, int c, size_t n) | |||
26 | int n32; | 23 | int n32; |
27 | uint32_t v16, v32; | 24 | uint32_t v16, v32; |
28 | uint8_t *out8 = s; | 25 | uint8_t *out8 = s; |
29 | #if !CHIP_HAS_WH64() | ||
30 | int ahead32; | ||
31 | #else | ||
32 | int to_align32; | 26 | int to_align32; |
33 | #endif | ||
34 | 27 | ||
35 | /* Experimentation shows that a trivial tight loop is a win up until | 28 | /* Experimentation shows that a trivial tight loop is a win up until |
36 | * around a size of 20, where writing a word at a time starts to win. | 29 | * around a size of 20, where writing a word at a time starts to win. |
@@ -61,21 +54,6 @@ void *memset(void *s, int c, size_t n) | |||
61 | return s; | 54 | return s; |
62 | } | 55 | } |
63 | 56 | ||
64 | #if !CHIP_HAS_WH64() | ||
65 | /* Use a spare issue slot to start prefetching the first cache | ||
66 | * line early. This instruction is free as the store can be buried | ||
67 | * in otherwise idle issue slots doing ALU ops. | ||
68 | */ | ||
69 | __insn_prefetch(out8); | ||
70 | |||
71 | /* We prefetch the end so that a short memset that spans two cache | ||
72 | * lines gets some prefetching benefit. Again we believe this is free | ||
73 | * to issue. | ||
74 | */ | ||
75 | __insn_prefetch(&out8[n - 1]); | ||
76 | #endif /* !CHIP_HAS_WH64() */ | ||
77 | |||
78 | |||
79 | /* Align 'out8'. We know n >= 3 so this won't write past the end. */ | 57 | /* Align 'out8'. We know n >= 3 so this won't write past the end. */ |
80 | while (((uintptr_t) out8 & 3) != 0) { | 58 | while (((uintptr_t) out8 & 3) != 0) { |
81 | *out8++ = c; | 59 | *out8++ = c; |
@@ -96,90 +74,6 @@ void *memset(void *s, int c, size_t n) | |||
96 | /* This must be at least 8 or the following loop doesn't work. */ | 74 | /* This must be at least 8 or the following loop doesn't work. */ |
97 | #define CACHE_LINE_SIZE_IN_WORDS (CHIP_L2_LINE_SIZE() / 4) | 75 | #define CACHE_LINE_SIZE_IN_WORDS (CHIP_L2_LINE_SIZE() / 4) |
98 | 76 | ||
99 | #if !CHIP_HAS_WH64() | ||
100 | |||
101 | ahead32 = CACHE_LINE_SIZE_IN_WORDS; | ||
102 | |||
103 | /* We already prefetched the first and last cache lines, so | ||
104 | * we only need to do more prefetching if we are storing | ||
105 | * to more than two cache lines. | ||
106 | */ | ||
107 | if (n32 > CACHE_LINE_SIZE_IN_WORDS * 2) { | ||
108 | int i; | ||
109 | |||
110 | /* Prefetch the next several cache lines. | ||
111 | * This is the setup code for the software-pipelined | ||
112 | * loop below. | ||
113 | */ | ||
114 | #define MAX_PREFETCH 5 | ||
115 | ahead32 = n32 & -CACHE_LINE_SIZE_IN_WORDS; | ||
116 | if (ahead32 > MAX_PREFETCH * CACHE_LINE_SIZE_IN_WORDS) | ||
117 | ahead32 = MAX_PREFETCH * CACHE_LINE_SIZE_IN_WORDS; | ||
118 | |||
119 | for (i = CACHE_LINE_SIZE_IN_WORDS; | ||
120 | i < ahead32; i += CACHE_LINE_SIZE_IN_WORDS) | ||
121 | __insn_prefetch(&out32[i]); | ||
122 | } | ||
123 | |||
124 | if (n32 > ahead32) { | ||
125 | while (1) { | ||
126 | int j; | ||
127 | |||
128 | /* Prefetch by reading one word several cache lines | ||
129 | * ahead. Since loads are non-blocking this will | ||
130 | * cause the full cache line to be read while we are | ||
131 | * finishing earlier cache lines. Using a store | ||
132 | * here causes microarchitectural performance | ||
133 | * problems where a victimizing store miss goes to | ||
134 | * the head of the retry FIFO and locks the pipe for | ||
135 | * a few cycles. So a few subsequent stores in this | ||
136 | * loop go into the retry FIFO, and then later | ||
137 | * stores see other stores to the same cache line | ||
138 | * are already in the retry FIFO and themselves go | ||
139 | * into the retry FIFO, filling it up and grinding | ||
140 | * to a halt waiting for the original miss to be | ||
141 | * satisfied. | ||
142 | */ | ||
143 | __insn_prefetch(&out32[ahead32]); | ||
144 | |||
145 | #if CACHE_LINE_SIZE_IN_WORDS % 4 != 0 | ||
146 | #error "Unhandled CACHE_LINE_SIZE_IN_WORDS" | ||
147 | #endif | ||
148 | |||
149 | n32 -= CACHE_LINE_SIZE_IN_WORDS; | ||
150 | |||
151 | /* Save icache space by only partially unrolling | ||
152 | * this loop. | ||
153 | */ | ||
154 | for (j = CACHE_LINE_SIZE_IN_WORDS / 4; j > 0; j--) { | ||
155 | *out32++ = v32; | ||
156 | *out32++ = v32; | ||
157 | *out32++ = v32; | ||
158 | *out32++ = v32; | ||
159 | } | ||
160 | |||
161 | /* To save compiled code size, reuse this loop even | ||
162 | * when we run out of prefetching to do by dropping | ||
163 | * ahead32 down. | ||
164 | */ | ||
165 | if (n32 <= ahead32) { | ||
166 | /* Not even a full cache line left, | ||
167 | * so stop now. | ||
168 | */ | ||
169 | if (n32 < CACHE_LINE_SIZE_IN_WORDS) | ||
170 | break; | ||
171 | |||
172 | /* Choose a small enough value that we don't | ||
173 | * prefetch past the end. There's no sense | ||
174 | * in touching cache lines we don't have to. | ||
175 | */ | ||
176 | ahead32 = CACHE_LINE_SIZE_IN_WORDS - 1; | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
181 | #else /* CHIP_HAS_WH64() */ | ||
182 | |||
183 | /* Determine how many words we need to emit before the 'out32' | 77 | /* Determine how many words we need to emit before the 'out32' |
184 | * pointer becomes aligned modulo the cache line size. | 78 | * pointer becomes aligned modulo the cache line size. |
185 | */ | 79 | */ |
@@ -236,8 +130,6 @@ void *memset(void *s, int c, size_t n) | |||
236 | n32 &= CACHE_LINE_SIZE_IN_WORDS - 1; | 130 | n32 &= CACHE_LINE_SIZE_IN_WORDS - 1; |
237 | } | 131 | } |
238 | 132 | ||
239 | #endif /* CHIP_HAS_WH64() */ | ||
240 | |||
241 | /* Now handle any leftover values. */ | 133 | /* Now handle any leftover values. */ |
242 | if (n32 != 0) { | 134 | if (n32 != 0) { |
243 | do { | 135 | do { |
diff --git a/arch/tile/lib/memset_64.c b/arch/tile/lib/memset_64.c index 3873085711d5..03ef69cd73de 100644 --- a/arch/tile/lib/memset_64.c +++ b/arch/tile/lib/memset_64.c | |||
@@ -12,13 +12,11 @@ | |||
12 | * more details. | 12 | * more details. |
13 | */ | 13 | */ |
14 | 14 | ||
15 | #include <arch/chip.h> | ||
16 | |||
17 | #include <linux/types.h> | 15 | #include <linux/types.h> |
18 | #include <linux/string.h> | 16 | #include <linux/string.h> |
19 | #include <linux/module.h> | 17 | #include <linux/module.h> |
20 | 18 | #include <arch/chip.h> | |
21 | #undef memset | 19 | #include "string-endian.h" |
22 | 20 | ||
23 | void *memset(void *s, int c, size_t n) | 21 | void *memset(void *s, int c, size_t n) |
24 | { | 22 | { |
@@ -70,8 +68,7 @@ void *memset(void *s, int c, size_t n) | |||
70 | n64 = n >> 3; | 68 | n64 = n >> 3; |
71 | 69 | ||
72 | /* Tile input byte out to 64 bits. */ | 70 | /* Tile input byte out to 64 bits. */ |
73 | /* KLUDGE */ | 71 | v64 = copy_byte(c); |
74 | v64 = 0x0101010101010101ULL * (uint8_t)c; | ||
75 | 72 | ||
76 | /* This must be at least 8 or the following loop doesn't work. */ | 73 | /* This must be at least 8 or the following loop doesn't work. */ |
77 | #define CACHE_LINE_SIZE_IN_DOUBLEWORDS (CHIP_L2_LINE_SIZE() / 8) | 74 | #define CACHE_LINE_SIZE_IN_DOUBLEWORDS (CHIP_L2_LINE_SIZE() / 8) |
diff --git a/arch/tile/lib/strchr_32.c b/arch/tile/lib/strchr_32.c index c94e6f7ae7b5..841fe6963019 100644 --- a/arch/tile/lib/strchr_32.c +++ b/arch/tile/lib/strchr_32.c | |||
@@ -16,8 +16,6 @@ | |||
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | 18 | ||
19 | #undef strchr | ||
20 | |||
21 | char *strchr(const char *s, int c) | 19 | char *strchr(const char *s, int c) |
22 | { | 20 | { |
23 | int z, g; | 21 | int z, g; |
diff --git a/arch/tile/lib/strchr_64.c b/arch/tile/lib/strchr_64.c index f39f9dc422b0..fe6e31c06f8d 100644 --- a/arch/tile/lib/strchr_64.c +++ b/arch/tile/lib/strchr_64.c | |||
@@ -26,7 +26,7 @@ char *strchr(const char *s, int c) | |||
26 | const uint64_t *p = (const uint64_t *)(s_int & -8); | 26 | const uint64_t *p = (const uint64_t *)(s_int & -8); |
27 | 27 | ||
28 | /* Create eight copies of the byte for which we are looking. */ | 28 | /* Create eight copies of the byte for which we are looking. */ |
29 | const uint64_t goal = 0x0101010101010101ULL * (uint8_t) c; | 29 | const uint64_t goal = copy_byte(c); |
30 | 30 | ||
31 | /* Read the first aligned word, but force bytes before the string to | 31 | /* Read the first aligned word, but force bytes before the string to |
32 | * match neither zero nor goal (we make sure the high bit of each | 32 | * match neither zero nor goal (we make sure the high bit of each |
diff --git a/arch/tile/lib/string-endian.h b/arch/tile/lib/string-endian.h index c0eed7ce69c3..2e49cbfe9371 100644 --- a/arch/tile/lib/string-endian.h +++ b/arch/tile/lib/string-endian.h | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2011 Tilera Corporation. All Rights Reserved. | 2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. |
3 | * | 3 | * |
4 | * This program is free software; you can redistribute it and/or | 4 | * This program is free software; you can redistribute it and/or |
5 | * modify it under the terms of the GNU General Public License | 5 | * modify it under the terms of the GNU General Public License |
@@ -31,3 +31,14 @@ | |||
31 | #define CFZ(x) __insn_clz(x) | 31 | #define CFZ(x) __insn_clz(x) |
32 | #define REVCZ(x) __insn_ctz(x) | 32 | #define REVCZ(x) __insn_ctz(x) |
33 | #endif | 33 | #endif |
34 | |||
35 | /* | ||
36 | * Create eight copies of the byte in a uint64_t. Byte Shuffle uses | ||
37 | * the bytes of srcB as the index into the dest vector to select a | ||
38 | * byte. With all indices of zero, the first byte is copied into all | ||
39 | * the other bytes. | ||
40 | */ | ||
41 | static inline uint64_t copy_byte(uint8_t byte) | ||
42 | { | ||
43 | return __insn_shufflebytes(byte, 0, 0); | ||
44 | } | ||
diff --git a/arch/tile/lib/strlen_32.c b/arch/tile/lib/strlen_32.c index 4974292a5534..f26f88e11e4a 100644 --- a/arch/tile/lib/strlen_32.c +++ b/arch/tile/lib/strlen_32.c | |||
@@ -16,8 +16,6 @@ | |||
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | 18 | ||
19 | #undef strlen | ||
20 | |||
21 | size_t strlen(const char *s) | 19 | size_t strlen(const char *s) |
22 | { | 20 | { |
23 | /* Get an aligned pointer. */ | 21 | /* Get an aligned pointer. */ |
diff --git a/arch/tile/lib/strnlen_32.c b/arch/tile/lib/strnlen_32.c new file mode 100644 index 000000000000..1434141d9e01 --- /dev/null +++ b/arch/tile/lib/strnlen_32.c | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/types.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/module.h> | ||
18 | |||
19 | size_t strnlen(const char *s, size_t count) | ||
20 | { | ||
21 | /* Get an aligned pointer. */ | ||
22 | const uintptr_t s_int = (uintptr_t) s; | ||
23 | const uint32_t *p = (const uint32_t *)(s_int & -4); | ||
24 | size_t bytes_read = sizeof(*p) - (s_int & (sizeof(*p) - 1)); | ||
25 | size_t len; | ||
26 | uint32_t v, bits; | ||
27 | |||
28 | /* Avoid page fault risk by not reading any bytes when count is 0. */ | ||
29 | if (count == 0) | ||
30 | return 0; | ||
31 | |||
32 | /* Read first word, but force bytes before the string to be nonzero. */ | ||
33 | v = *p | ((1 << ((s_int << 3) & 31)) - 1); | ||
34 | |||
35 | while ((bits = __insn_seqb(v, 0)) == 0) { | ||
36 | if (bytes_read >= count) { | ||
37 | /* Read COUNT bytes and didn't find the terminator. */ | ||
38 | return count; | ||
39 | } | ||
40 | v = *++p; | ||
41 | bytes_read += sizeof(v); | ||
42 | } | ||
43 | |||
44 | len = ((const char *) p) + (__insn_ctz(bits) >> 3) - s; | ||
45 | return (len < count ? len : count); | ||
46 | } | ||
47 | EXPORT_SYMBOL(strnlen); | ||
diff --git a/arch/tile/lib/strnlen_64.c b/arch/tile/lib/strnlen_64.c new file mode 100644 index 000000000000..2e8de6a5136f --- /dev/null +++ b/arch/tile/lib/strnlen_64.c | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | */ | ||
14 | |||
15 | #include <linux/types.h> | ||
16 | #include <linux/string.h> | ||
17 | #include <linux/module.h> | ||
18 | #include "string-endian.h" | ||
19 | |||
20 | size_t strnlen(const char *s, size_t count) | ||
21 | { | ||
22 | /* Get an aligned pointer. */ | ||
23 | const uintptr_t s_int = (uintptr_t) s; | ||
24 | const uint64_t *p = (const uint64_t *)(s_int & -8); | ||
25 | size_t bytes_read = sizeof(*p) - (s_int & (sizeof(*p) - 1)); | ||
26 | size_t len; | ||
27 | uint64_t v, bits; | ||
28 | |||
29 | /* Avoid page fault risk by not reading any bytes when count is 0. */ | ||
30 | if (count == 0) | ||
31 | return 0; | ||
32 | |||
33 | /* Read and MASK the first word. */ | ||
34 | v = *p | MASK(s_int); | ||
35 | |||
36 | while ((bits = __insn_v1cmpeqi(v, 0)) == 0) { | ||
37 | if (bytes_read >= count) { | ||
38 | /* Read COUNT bytes and didn't find the terminator. */ | ||
39 | return count; | ||
40 | } | ||
41 | v = *++p; | ||
42 | bytes_read += sizeof(v); | ||
43 | } | ||
44 | |||
45 | len = ((const char *) p) + (CFZ(bits) >> 3) - s; | ||
46 | return (len < count ? len : count); | ||
47 | } | ||
48 | EXPORT_SYMBOL(strnlen); | ||
diff --git a/arch/tile/lib/usercopy_32.S b/arch/tile/lib/usercopy_32.S index b62d002af009..1bc162224638 100644 --- a/arch/tile/lib/usercopy_32.S +++ b/arch/tile/lib/usercopy_32.S | |||
@@ -36,6 +36,7 @@ strnlen_user_fault: | |||
36 | { move r0, zero; jrp lr } | 36 | { move r0, zero; jrp lr } |
37 | ENDPROC(strnlen_user_fault) | 37 | ENDPROC(strnlen_user_fault) |
38 | .section __ex_table,"a" | 38 | .section __ex_table,"a" |
39 | .align 4 | ||
39 | .word 1b, strnlen_user_fault | 40 | .word 1b, strnlen_user_fault |
40 | .popsection | 41 | .popsection |
41 | 42 | ||
@@ -47,18 +48,20 @@ strnlen_user_fault: | |||
47 | */ | 48 | */ |
48 | STD_ENTRY(strncpy_from_user_asm) | 49 | STD_ENTRY(strncpy_from_user_asm) |
49 | { bz r2, 2f; move r3, r0 } | 50 | { bz r2, 2f; move r3, r0 } |
50 | 1: { lb_u r4, r1; addi r1, r1, 1; addi r2, r2, -1 } | 51 | 1: { lb_u r4, r1; addi r1, r1, 1; addi r2, r2, -1 } |
51 | { sb r0, r4; addi r0, r0, 1 } | 52 | { sb r0, r4; addi r0, r0, 1 } |
52 | bz r2, 2f | 53 | bz r4, 2f |
53 | bnzt r4, 1b | 54 | bnzt r2, 1b |
54 | addi r0, r0, -1 /* don't count the trailing NUL */ | 55 | { sub r0, r0, r3; jrp lr } |
55 | 2: { sub r0, r0, r3; jrp lr } | 56 | 2: addi r0, r0, -1 /* don't count the trailing NUL */ |
57 | { sub r0, r0, r3; jrp lr } | ||
56 | STD_ENDPROC(strncpy_from_user_asm) | 58 | STD_ENDPROC(strncpy_from_user_asm) |
57 | .pushsection .fixup,"ax" | 59 | .pushsection .fixup,"ax" |
58 | strncpy_from_user_fault: | 60 | strncpy_from_user_fault: |
59 | { movei r0, -EFAULT; jrp lr } | 61 | { movei r0, -EFAULT; jrp lr } |
60 | ENDPROC(strncpy_from_user_fault) | 62 | ENDPROC(strncpy_from_user_fault) |
61 | .section __ex_table,"a" | 63 | .section __ex_table,"a" |
64 | .align 4 | ||
62 | .word 1b, strncpy_from_user_fault | 65 | .word 1b, strncpy_from_user_fault |
63 | .popsection | 66 | .popsection |
64 | 67 | ||
@@ -77,6 +80,7 @@ STD_ENTRY(clear_user_asm) | |||
77 | bnzt r1, 1b | 80 | bnzt r1, 1b |
78 | 2: { move r0, r1; jrp lr } | 81 | 2: { move r0, r1; jrp lr } |
79 | .pushsection __ex_table,"a" | 82 | .pushsection __ex_table,"a" |
83 | .align 4 | ||
80 | .word 1b, 2b | 84 | .word 1b, 2b |
81 | .popsection | 85 | .popsection |
82 | 86 | ||
@@ -86,6 +90,7 @@ STD_ENTRY(clear_user_asm) | |||
86 | 2: { move r0, r1; jrp lr } | 90 | 2: { move r0, r1; jrp lr } |
87 | STD_ENDPROC(clear_user_asm) | 91 | STD_ENDPROC(clear_user_asm) |
88 | .pushsection __ex_table,"a" | 92 | .pushsection __ex_table,"a" |
93 | .align 4 | ||
89 | .word 1b, 2b | 94 | .word 1b, 2b |
90 | .popsection | 95 | .popsection |
91 | 96 | ||
@@ -105,25 +110,7 @@ STD_ENTRY(flush_user_asm) | |||
105 | 2: { move r0, r1; jrp lr } | 110 | 2: { move r0, r1; jrp lr } |
106 | STD_ENDPROC(flush_user_asm) | 111 | STD_ENDPROC(flush_user_asm) |
107 | .pushsection __ex_table,"a" | 112 | .pushsection __ex_table,"a" |
108 | .word 1b, 2b | 113 | .align 4 |
109 | .popsection | ||
110 | |||
111 | /* | ||
112 | * inv_user_asm takes the user target address in r0 and the | ||
113 | * number of bytes to invalidate in r1. | ||
114 | * It returns the number of not inv'able bytes (hopefully zero) in r0. | ||
115 | */ | ||
116 | STD_ENTRY(inv_user_asm) | ||
117 | bz r1, 2f | ||
118 | { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } | ||
119 | { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } | ||
120 | { and r0, r0, r2; and r1, r1, r2 } | ||
121 | { sub r1, r1, r0 } | ||
122 | 1: { inv r0; addi r1, r1, -CHIP_INV_STRIDE() } | ||
123 | { addi r0, r0, CHIP_INV_STRIDE(); bnzt r1, 1b } | ||
124 | 2: { move r0, r1; jrp lr } | ||
125 | STD_ENDPROC(inv_user_asm) | ||
126 | .pushsection __ex_table,"a" | ||
127 | .word 1b, 2b | 114 | .word 1b, 2b |
128 | .popsection | 115 | .popsection |
129 | 116 | ||
@@ -143,5 +130,6 @@ STD_ENTRY(finv_user_asm) | |||
143 | 2: { move r0, r1; jrp lr } | 130 | 2: { move r0, r1; jrp lr } |
144 | STD_ENDPROC(finv_user_asm) | 131 | STD_ENDPROC(finv_user_asm) |
145 | .pushsection __ex_table,"a" | 132 | .pushsection __ex_table,"a" |
133 | .align 4 | ||
146 | .word 1b, 2b | 134 | .word 1b, 2b |
147 | .popsection | 135 | .popsection |
diff --git a/arch/tile/lib/usercopy_64.S b/arch/tile/lib/usercopy_64.S index adb2dbbc70cd..b3b31a3306f8 100644 --- a/arch/tile/lib/usercopy_64.S +++ b/arch/tile/lib/usercopy_64.S | |||
@@ -36,6 +36,7 @@ strnlen_user_fault: | |||
36 | { move r0, zero; jrp lr } | 36 | { move r0, zero; jrp lr } |
37 | ENDPROC(strnlen_user_fault) | 37 | ENDPROC(strnlen_user_fault) |
38 | .section __ex_table,"a" | 38 | .section __ex_table,"a" |
39 | .align 8 | ||
39 | .quad 1b, strnlen_user_fault | 40 | .quad 1b, strnlen_user_fault |
40 | .popsection | 41 | .popsection |
41 | 42 | ||
@@ -47,18 +48,20 @@ strnlen_user_fault: | |||
47 | */ | 48 | */ |
48 | STD_ENTRY(strncpy_from_user_asm) | 49 | STD_ENTRY(strncpy_from_user_asm) |
49 | { beqz r2, 2f; move r3, r0 } | 50 | { beqz r2, 2f; move r3, r0 } |
50 | 1: { ld1u r4, r1; addi r1, r1, 1; addi r2, r2, -1 } | 51 | 1: { ld1u r4, r1; addi r1, r1, 1; addi r2, r2, -1 } |
51 | { st1 r0, r4; addi r0, r0, 1 } | 52 | { st1 r0, r4; addi r0, r0, 1 } |
52 | beqz r2, 2f | 53 | beqz r4, 2f |
53 | bnezt r4, 1b | 54 | bnezt r2, 1b |
54 | addi r0, r0, -1 /* don't count the trailing NUL */ | 55 | { sub r0, r0, r3; jrp lr } |
55 | 2: { sub r0, r0, r3; jrp lr } | 56 | 2: addi r0, r0, -1 /* don't count the trailing NUL */ |
57 | { sub r0, r0, r3; jrp lr } | ||
56 | STD_ENDPROC(strncpy_from_user_asm) | 58 | STD_ENDPROC(strncpy_from_user_asm) |
57 | .pushsection .fixup,"ax" | 59 | .pushsection .fixup,"ax" |
58 | strncpy_from_user_fault: | 60 | strncpy_from_user_fault: |
59 | { movei r0, -EFAULT; jrp lr } | 61 | { movei r0, -EFAULT; jrp lr } |
60 | ENDPROC(strncpy_from_user_fault) | 62 | ENDPROC(strncpy_from_user_fault) |
61 | .section __ex_table,"a" | 63 | .section __ex_table,"a" |
64 | .align 8 | ||
62 | .quad 1b, strncpy_from_user_fault | 65 | .quad 1b, strncpy_from_user_fault |
63 | .popsection | 66 | .popsection |
64 | 67 | ||
@@ -77,6 +80,7 @@ STD_ENTRY(clear_user_asm) | |||
77 | bnezt r1, 1b | 80 | bnezt r1, 1b |
78 | 2: { move r0, r1; jrp lr } | 81 | 2: { move r0, r1; jrp lr } |
79 | .pushsection __ex_table,"a" | 82 | .pushsection __ex_table,"a" |
83 | .align 8 | ||
80 | .quad 1b, 2b | 84 | .quad 1b, 2b |
81 | .popsection | 85 | .popsection |
82 | 86 | ||
@@ -86,6 +90,7 @@ STD_ENTRY(clear_user_asm) | |||
86 | 2: { move r0, r1; jrp lr } | 90 | 2: { move r0, r1; jrp lr } |
87 | STD_ENDPROC(clear_user_asm) | 91 | STD_ENDPROC(clear_user_asm) |
88 | .pushsection __ex_table,"a" | 92 | .pushsection __ex_table,"a" |
93 | .align 8 | ||
89 | .quad 1b, 2b | 94 | .quad 1b, 2b |
90 | .popsection | 95 | .popsection |
91 | 96 | ||
@@ -105,25 +110,7 @@ STD_ENTRY(flush_user_asm) | |||
105 | 2: { move r0, r1; jrp lr } | 110 | 2: { move r0, r1; jrp lr } |
106 | STD_ENDPROC(flush_user_asm) | 111 | STD_ENDPROC(flush_user_asm) |
107 | .pushsection __ex_table,"a" | 112 | .pushsection __ex_table,"a" |
108 | .quad 1b, 2b | 113 | .align 8 |
109 | .popsection | ||
110 | |||
111 | /* | ||
112 | * inv_user_asm takes the user target address in r0 and the | ||
113 | * number of bytes to invalidate in r1. | ||
114 | * It returns the number of not inv'able bytes (hopefully zero) in r0. | ||
115 | */ | ||
116 | STD_ENTRY(inv_user_asm) | ||
117 | beqz r1, 2f | ||
118 | { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } | ||
119 | { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } | ||
120 | { and r0, r0, r2; and r1, r1, r2 } | ||
121 | { sub r1, r1, r0 } | ||
122 | 1: { inv r0; addi r1, r1, -CHIP_INV_STRIDE() } | ||
123 | { addi r0, r0, CHIP_INV_STRIDE(); bnezt r1, 1b } | ||
124 | 2: { move r0, r1; jrp lr } | ||
125 | STD_ENDPROC(inv_user_asm) | ||
126 | .pushsection __ex_table,"a" | ||
127 | .quad 1b, 2b | 114 | .quad 1b, 2b |
128 | .popsection | 115 | .popsection |
129 | 116 | ||
@@ -143,5 +130,6 @@ STD_ENTRY(finv_user_asm) | |||
143 | 2: { move r0, r1; jrp lr } | 130 | 2: { move r0, r1; jrp lr } |
144 | STD_ENDPROC(finv_user_asm) | 131 | STD_ENDPROC(finv_user_asm) |
145 | .pushsection __ex_table,"a" | 132 | .pushsection __ex_table,"a" |
133 | .align 8 | ||
146 | .quad 1b, 2b | 134 | .quad 1b, 2b |
147 | .popsection | 135 | .popsection |
diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c index 743c951c61b0..23f044e8a7ab 100644 --- a/arch/tile/mm/elf.c +++ b/arch/tile/mm/elf.c | |||
@@ -21,7 +21,8 @@ | |||
21 | #include <asm/pgtable.h> | 21 | #include <asm/pgtable.h> |
22 | #include <asm/pgalloc.h> | 22 | #include <asm/pgalloc.h> |
23 | #include <asm/sections.h> | 23 | #include <asm/sections.h> |
24 | #include <arch/sim_def.h> | 24 | #include <asm/vdso.h> |
25 | #include <arch/sim.h> | ||
25 | 26 | ||
26 | /* Notify a running simulator, if any, that an exec just occurred. */ | 27 | /* Notify a running simulator, if any, that an exec just occurred. */ |
27 | static void sim_notify_exec(const char *binary_name) | 28 | static void sim_notify_exec(const char *binary_name) |
@@ -38,21 +39,55 @@ static void sim_notify_exec(const char *binary_name) | |||
38 | 39 | ||
39 | static int notify_exec(struct mm_struct *mm) | 40 | static int notify_exec(struct mm_struct *mm) |
40 | { | 41 | { |
41 | int retval = 0; /* failure */ | 42 | char *buf, *path; |
42 | 43 | struct vm_area_struct *vma; | |
43 | if (mm->exe_file) { | 44 | |
44 | char *buf = (char *) __get_free_page(GFP_KERNEL); | 45 | if (!sim_is_simulator()) |
45 | if (buf) { | 46 | return 1; |
46 | char *path = d_path(&mm->exe_file->f_path, | 47 | |
47 | buf, PAGE_SIZE); | 48 | if (mm->exe_file == NULL) |
48 | if (!IS_ERR(path)) { | 49 | return 0; |
49 | sim_notify_exec(path); | 50 | |
50 | retval = 1; | 51 | for (vma = current->mm->mmap; ; vma = vma->vm_next) { |
51 | } | 52 | if (vma == NULL) |
52 | free_page((unsigned long)buf); | 53 | return 0; |
54 | if (vma->vm_file == mm->exe_file) | ||
55 | break; | ||
56 | } | ||
57 | |||
58 | buf = (char *) __get_free_page(GFP_KERNEL); | ||
59 | if (buf == NULL) | ||
60 | return 0; | ||
61 | |||
62 | path = d_path(&mm->exe_file->f_path, buf, PAGE_SIZE); | ||
63 | if (IS_ERR(path)) { | ||
64 | free_page((unsigned long)buf); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | /* | ||
69 | * Notify simulator of an ET_DYN object so we know the load address. | ||
70 | * The somewhat cryptic overuse of SIM_CONTROL_DLOPEN allows us | ||
71 | * to be backward-compatible with older simulator releases. | ||
72 | */ | ||
73 | if (vma->vm_start == (ELF_ET_DYN_BASE & PAGE_MASK)) { | ||
74 | char buf[64]; | ||
75 | int i; | ||
76 | |||
77 | snprintf(buf, sizeof(buf), "0x%lx:@", vma->vm_start); | ||
78 | for (i = 0; ; ++i) { | ||
79 | char c = buf[i]; | ||
80 | __insn_mtspr(SPR_SIM_CONTROL, | ||
81 | (SIM_CONTROL_DLOPEN | ||
82 | | (c << _SIM_CONTROL_OPERATOR_BITS))); | ||
83 | if (c == '\0') | ||
84 | break; | ||
53 | } | 85 | } |
54 | } | 86 | } |
55 | return retval; | 87 | |
88 | sim_notify_exec(path); | ||
89 | free_page((unsigned long)buf); | ||
90 | return 1; | ||
56 | } | 91 | } |
57 | 92 | ||
58 | /* Notify a running simulator, if any, that we loaded an interpreter. */ | 93 | /* Notify a running simulator, if any, that we loaded an interpreter. */ |
@@ -68,37 +103,10 @@ static void sim_notify_interp(unsigned long load_addr) | |||
68 | } | 103 | } |
69 | 104 | ||
70 | 105 | ||
71 | /* Kernel address of page used to map read-only kernel data into userspace. */ | ||
72 | static void *vdso_page; | ||
73 | |||
74 | /* One-entry array used for install_special_mapping. */ | ||
75 | static struct page *vdso_pages[1]; | ||
76 | |||
77 | static int __init vdso_setup(void) | ||
78 | { | ||
79 | vdso_page = (void *)get_zeroed_page(GFP_ATOMIC); | ||
80 | memcpy(vdso_page, __rt_sigreturn, __rt_sigreturn_end - __rt_sigreturn); | ||
81 | vdso_pages[0] = virt_to_page(vdso_page); | ||
82 | return 0; | ||
83 | } | ||
84 | device_initcall(vdso_setup); | ||
85 | |||
86 | const char *arch_vma_name(struct vm_area_struct *vma) | ||
87 | { | ||
88 | if (vma->vm_private_data == vdso_pages) | ||
89 | return "[vdso]"; | ||
90 | #ifndef __tilegx__ | ||
91 | if (vma->vm_start == MEM_USER_INTRPT) | ||
92 | return "[intrpt]"; | ||
93 | #endif | ||
94 | return NULL; | ||
95 | } | ||
96 | |||
97 | int arch_setup_additional_pages(struct linux_binprm *bprm, | 106 | int arch_setup_additional_pages(struct linux_binprm *bprm, |
98 | int executable_stack) | 107 | int executable_stack) |
99 | { | 108 | { |
100 | struct mm_struct *mm = current->mm; | 109 | struct mm_struct *mm = current->mm; |
101 | unsigned long vdso_base; | ||
102 | int retval = 0; | 110 | int retval = 0; |
103 | 111 | ||
104 | down_write(&mm->mmap_sem); | 112 | down_write(&mm->mmap_sem); |
@@ -111,14 +119,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, | |||
111 | if (!notify_exec(mm)) | 119 | if (!notify_exec(mm)) |
112 | sim_notify_exec(bprm->filename); | 120 | sim_notify_exec(bprm->filename); |
113 | 121 | ||
114 | /* | 122 | retval = setup_vdso_pages(); |
115 | * MAYWRITE to allow gdb to COW and set breakpoints | ||
116 | */ | ||
117 | vdso_base = VDSO_BASE; | ||
118 | retval = install_special_mapping(mm, vdso_base, PAGE_SIZE, | ||
119 | VM_READ|VM_EXEC| | ||
120 | VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, | ||
121 | vdso_pages); | ||
122 | 123 | ||
123 | #ifndef __tilegx__ | 124 | #ifndef __tilegx__ |
124 | /* | 125 | /* |
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c index f7f99f90cbe0..111d5a9b76f1 100644 --- a/arch/tile/mm/fault.c +++ b/arch/tile/mm/fault.c | |||
@@ -34,6 +34,7 @@ | |||
34 | #include <linux/hugetlb.h> | 34 | #include <linux/hugetlb.h> |
35 | #include <linux/syscalls.h> | 35 | #include <linux/syscalls.h> |
36 | #include <linux/uaccess.h> | 36 | #include <linux/uaccess.h> |
37 | #include <linux/kdebug.h> | ||
37 | 38 | ||
38 | #include <asm/pgalloc.h> | 39 | #include <asm/pgalloc.h> |
39 | #include <asm/sections.h> | 40 | #include <asm/sections.h> |
@@ -122,10 +123,9 @@ static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) | |||
122 | pmd_k = pmd_offset(pud_k, address); | 123 | pmd_k = pmd_offset(pud_k, address); |
123 | if (!pmd_present(*pmd_k)) | 124 | if (!pmd_present(*pmd_k)) |
124 | return NULL; | 125 | return NULL; |
125 | if (!pmd_present(*pmd)) { | 126 | if (!pmd_present(*pmd)) |
126 | set_pmd(pmd, *pmd_k); | 127 | set_pmd(pmd, *pmd_k); |
127 | arch_flush_lazy_mmu_mode(); | 128 | else |
128 | } else | ||
129 | BUG_ON(pmd_ptfn(*pmd) != pmd_ptfn(*pmd_k)); | 129 | BUG_ON(pmd_ptfn(*pmd) != pmd_ptfn(*pmd_k)); |
130 | return pmd_k; | 130 | return pmd_k; |
131 | } | 131 | } |
@@ -283,7 +283,7 @@ static int handle_page_fault(struct pt_regs *regs, | |||
283 | flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | | 283 | flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE | |
284 | (write ? FAULT_FLAG_WRITE : 0)); | 284 | (write ? FAULT_FLAG_WRITE : 0)); |
285 | 285 | ||
286 | is_kernel_mode = (EX1_PL(regs->ex1) != USER_PL); | 286 | is_kernel_mode = !user_mode(regs); |
287 | 287 | ||
288 | tsk = validate_current(); | 288 | tsk = validate_current(); |
289 | 289 | ||
@@ -466,28 +466,15 @@ good_area: | |||
466 | } | 466 | } |
467 | } | 467 | } |
468 | 468 | ||
469 | #if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() | ||
470 | /* | ||
471 | * If this was an asynchronous fault, | ||
472 | * restart the appropriate engine. | ||
473 | */ | ||
474 | switch (fault_num) { | ||
475 | #if CHIP_HAS_TILE_DMA() | 469 | #if CHIP_HAS_TILE_DMA() |
470 | /* If this was a DMA TLB fault, restart the DMA engine. */ | ||
471 | switch (fault_num) { | ||
476 | case INT_DMATLB_MISS: | 472 | case INT_DMATLB_MISS: |
477 | case INT_DMATLB_MISS_DWNCL: | 473 | case INT_DMATLB_MISS_DWNCL: |
478 | case INT_DMATLB_ACCESS: | 474 | case INT_DMATLB_ACCESS: |
479 | case INT_DMATLB_ACCESS_DWNCL: | 475 | case INT_DMATLB_ACCESS_DWNCL: |
480 | __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__REQUEST_MASK); | 476 | __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__REQUEST_MASK); |
481 | break; | 477 | break; |
482 | #endif | ||
483 | #if CHIP_HAS_SN_PROC() | ||
484 | case INT_SNITLB_MISS: | ||
485 | case INT_SNITLB_MISS_DWNCL: | ||
486 | __insn_mtspr(SPR_SNCTL, | ||
487 | __insn_mfspr(SPR_SNCTL) & | ||
488 | ~SPR_SNCTL__FRZPROC_MASK); | ||
489 | break; | ||
490 | #endif | ||
491 | } | 478 | } |
492 | #endif | 479 | #endif |
493 | 480 | ||
@@ -722,8 +709,60 @@ void do_page_fault(struct pt_regs *regs, int fault_num, | |||
722 | { | 709 | { |
723 | int is_page_fault; | 710 | int is_page_fault; |
724 | 711 | ||
712 | #ifdef CONFIG_KPROBES | ||
713 | /* | ||
714 | * This is to notify the fault handler of the kprobes. The | ||
715 | * exception code is redundant as it is also carried in REGS, | ||
716 | * but we pass it anyhow. | ||
717 | */ | ||
718 | if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1, | ||
719 | regs->faultnum, SIGSEGV) == NOTIFY_STOP) | ||
720 | return; | ||
721 | #endif | ||
722 | |||
723 | #ifdef __tilegx__ | ||
724 | /* | ||
725 | * We don't need early do_page_fault_ics() support, since unlike | ||
726 | * Pro we don't need to worry about unlocking the atomic locks. | ||
727 | * There is only one current case in GX where we touch any memory | ||
728 | * under ICS other than our own kernel stack, and we handle that | ||
729 | * here. (If we crash due to trying to touch our own stack, | ||
730 | * we're in too much trouble for C code to help out anyway.) | ||
731 | */ | ||
732 | if (write & ~1) { | ||
733 | unsigned long pc = write & ~1; | ||
734 | if (pc >= (unsigned long) __start_unalign_asm_code && | ||
735 | pc < (unsigned long) __end_unalign_asm_code) { | ||
736 | struct thread_info *ti = current_thread_info(); | ||
737 | /* | ||
738 | * Our EX_CONTEXT is still what it was from the | ||
739 | * initial unalign exception, but now we've faulted | ||
740 | * on the JIT page. We would like to complete the | ||
741 | * page fault however is appropriate, and then retry | ||
742 | * the instruction that caused the unalign exception. | ||
743 | * Our state has been "corrupted" by setting the low | ||
744 | * bit in "sp", and stashing r0..r3 in the | ||
745 | * thread_info area, so we revert all of that, then | ||
746 | * continue as if this were a normal page fault. | ||
747 | */ | ||
748 | regs->sp &= ~1UL; | ||
749 | regs->regs[0] = ti->unalign_jit_tmp[0]; | ||
750 | regs->regs[1] = ti->unalign_jit_tmp[1]; | ||
751 | regs->regs[2] = ti->unalign_jit_tmp[2]; | ||
752 | regs->regs[3] = ti->unalign_jit_tmp[3]; | ||
753 | write &= 1; | ||
754 | } else { | ||
755 | pr_alert("%s/%d: ICS set at page fault at %#lx: %#lx\n", | ||
756 | current->comm, current->pid, pc, address); | ||
757 | show_regs(regs); | ||
758 | do_group_exit(SIGKILL); | ||
759 | return; | ||
760 | } | ||
761 | } | ||
762 | #else | ||
725 | /* This case should have been handled by do_page_fault_ics(). */ | 763 | /* This case should have been handled by do_page_fault_ics(). */ |
726 | BUG_ON(write & ~1); | 764 | BUG_ON(write & ~1); |
765 | #endif | ||
727 | 766 | ||
728 | #if CHIP_HAS_TILE_DMA() | 767 | #if CHIP_HAS_TILE_DMA() |
729 | /* | 768 | /* |
@@ -752,10 +791,6 @@ void do_page_fault(struct pt_regs *regs, int fault_num, | |||
752 | case INT_DMATLB_MISS: | 791 | case INT_DMATLB_MISS: |
753 | case INT_DMATLB_MISS_DWNCL: | 792 | case INT_DMATLB_MISS_DWNCL: |
754 | #endif | 793 | #endif |
755 | #if CHIP_HAS_SN_PROC() | ||
756 | case INT_SNITLB_MISS: | ||
757 | case INT_SNITLB_MISS_DWNCL: | ||
758 | #endif | ||
759 | is_page_fault = 1; | 794 | is_page_fault = 1; |
760 | break; | 795 | break; |
761 | 796 | ||
@@ -771,8 +806,8 @@ void do_page_fault(struct pt_regs *regs, int fault_num, | |||
771 | panic("Bad fault number %d in do_page_fault", fault_num); | 806 | panic("Bad fault number %d in do_page_fault", fault_num); |
772 | } | 807 | } |
773 | 808 | ||
774 | #if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() | 809 | #if CHIP_HAS_TILE_DMA() |
775 | if (EX1_PL(regs->ex1) != USER_PL) { | 810 | if (!user_mode(regs)) { |
776 | struct async_tlb *async; | 811 | struct async_tlb *async; |
777 | switch (fault_num) { | 812 | switch (fault_num) { |
778 | #if CHIP_HAS_TILE_DMA() | 813 | #if CHIP_HAS_TILE_DMA() |
@@ -783,12 +818,6 @@ void do_page_fault(struct pt_regs *regs, int fault_num, | |||
783 | async = ¤t->thread.dma_async_tlb; | 818 | async = ¤t->thread.dma_async_tlb; |
784 | break; | 819 | break; |
785 | #endif | 820 | #endif |
786 | #if CHIP_HAS_SN_PROC() | ||
787 | case INT_SNITLB_MISS: | ||
788 | case INT_SNITLB_MISS_DWNCL: | ||
789 | async = ¤t->thread.sn_async_tlb; | ||
790 | break; | ||
791 | #endif | ||
792 | default: | 821 | default: |
793 | async = NULL; | 822 | async = NULL; |
794 | } | 823 | } |
@@ -821,14 +850,22 @@ void do_page_fault(struct pt_regs *regs, int fault_num, | |||
821 | } | 850 | } |
822 | 851 | ||
823 | 852 | ||
824 | #if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() | 853 | #if CHIP_HAS_TILE_DMA() |
825 | /* | 854 | /* |
826 | * Check an async_tlb structure to see if a deferred fault is waiting, | 855 | * This routine effectively re-issues asynchronous page faults |
827 | * and if so pass it to the page-fault code. | 856 | * when we are returning to user space. |
828 | */ | 857 | */ |
829 | static void handle_async_page_fault(struct pt_regs *regs, | 858 | void do_async_page_fault(struct pt_regs *regs) |
830 | struct async_tlb *async) | ||
831 | { | 859 | { |
860 | struct async_tlb *async = ¤t->thread.dma_async_tlb; | ||
861 | |||
862 | /* | ||
863 | * Clear thread flag early. If we re-interrupt while processing | ||
864 | * code here, we will reset it and recall this routine before | ||
865 | * returning to user space. | ||
866 | */ | ||
867 | clear_thread_flag(TIF_ASYNC_TLB); | ||
868 | |||
832 | if (async->fault_num) { | 869 | if (async->fault_num) { |
833 | /* | 870 | /* |
834 | * Clear async->fault_num before calling the page-fault | 871 | * Clear async->fault_num before calling the page-fault |
@@ -842,35 +879,15 @@ static void handle_async_page_fault(struct pt_regs *regs, | |||
842 | async->address, async->is_write); | 879 | async->address, async->is_write); |
843 | } | 880 | } |
844 | } | 881 | } |
845 | 882 | #endif /* CHIP_HAS_TILE_DMA() */ | |
846 | /* | ||
847 | * This routine effectively re-issues asynchronous page faults | ||
848 | * when we are returning to user space. | ||
849 | */ | ||
850 | void do_async_page_fault(struct pt_regs *regs) | ||
851 | { | ||
852 | /* | ||
853 | * Clear thread flag early. If we re-interrupt while processing | ||
854 | * code here, we will reset it and recall this routine before | ||
855 | * returning to user space. | ||
856 | */ | ||
857 | clear_thread_flag(TIF_ASYNC_TLB); | ||
858 | |||
859 | #if CHIP_HAS_TILE_DMA() | ||
860 | handle_async_page_fault(regs, ¤t->thread.dma_async_tlb); | ||
861 | #endif | ||
862 | #if CHIP_HAS_SN_PROC() | ||
863 | handle_async_page_fault(regs, ¤t->thread.sn_async_tlb); | ||
864 | #endif | ||
865 | } | ||
866 | #endif /* CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC() */ | ||
867 | 883 | ||
868 | 884 | ||
869 | void vmalloc_sync_all(void) | 885 | void vmalloc_sync_all(void) |
870 | { | 886 | { |
871 | #ifdef __tilegx__ | 887 | #ifdef __tilegx__ |
872 | /* Currently all L1 kernel pmd's are static and shared. */ | 888 | /* Currently all L1 kernel pmd's are static and shared. */ |
873 | BUG_ON(pgd_index(VMALLOC_END) != pgd_index(VMALLOC_START)); | 889 | BUILD_BUG_ON(pgd_index(VMALLOC_END - PAGE_SIZE) != |
890 | pgd_index(VMALLOC_START)); | ||
874 | #else | 891 | #else |
875 | /* | 892 | /* |
876 | * Note that races in the updates of insync and start aren't | 893 | * Note that races in the updates of insync and start aren't |
diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c index 347d123b14be..0dc218294770 100644 --- a/arch/tile/mm/highmem.c +++ b/arch/tile/mm/highmem.c | |||
@@ -114,7 +114,6 @@ static void kmap_atomic_register(struct page *page, int type, | |||
114 | 114 | ||
115 | list_add(&->list, &_list); | 115 | list_add(&->list, &_list); |
116 | set_pte(ptep, pteval); | 116 | set_pte(ptep, pteval); |
117 | arch_flush_lazy_mmu_mode(); | ||
118 | 117 | ||
119 | spin_unlock(&_lock); | 118 | spin_unlock(&_lock); |
120 | homecache_kpte_unlock(flags); | 119 | homecache_kpte_unlock(flags); |
@@ -259,7 +258,6 @@ void __kunmap_atomic(void *kvaddr) | |||
259 | BUG_ON(vaddr >= (unsigned long)high_memory); | 258 | BUG_ON(vaddr >= (unsigned long)high_memory); |
260 | } | 259 | } |
261 | 260 | ||
262 | arch_flush_lazy_mmu_mode(); | ||
263 | pagefault_enable(); | 261 | pagefault_enable(); |
264 | } | 262 | } |
265 | EXPORT_SYMBOL(__kunmap_atomic); | 263 | EXPORT_SYMBOL(__kunmap_atomic); |
diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c index 1ae911939a18..004ba568d93f 100644 --- a/arch/tile/mm/homecache.c +++ b/arch/tile/mm/homecache.c | |||
@@ -43,12 +43,9 @@ | |||
43 | #include "migrate.h" | 43 | #include "migrate.h" |
44 | 44 | ||
45 | 45 | ||
46 | #if CHIP_HAS_COHERENT_LOCAL_CACHE() | ||
47 | |||
48 | /* | 46 | /* |
49 | * The noallocl2 option suppresses all use of the L2 cache to cache | 47 | * The noallocl2 option suppresses all use of the L2 cache to cache |
50 | * locally from a remote home. There's no point in using it if we | 48 | * locally from a remote home. |
51 | * don't have coherent local caching, though. | ||
52 | */ | 49 | */ |
53 | static int __write_once noallocl2; | 50 | static int __write_once noallocl2; |
54 | static int __init set_noallocl2(char *str) | 51 | static int __init set_noallocl2(char *str) |
@@ -58,12 +55,6 @@ static int __init set_noallocl2(char *str) | |||
58 | } | 55 | } |
59 | early_param("noallocl2", set_noallocl2); | 56 | early_param("noallocl2", set_noallocl2); |
60 | 57 | ||
61 | #else | ||
62 | |||
63 | #define noallocl2 0 | ||
64 | |||
65 | #endif | ||
66 | |||
67 | 58 | ||
68 | /* | 59 | /* |
69 | * Update the irq_stat for cpus that we are going to interrupt | 60 | * Update the irq_stat for cpus that we are going to interrupt |
@@ -172,7 +163,8 @@ void flush_remote(unsigned long cache_pfn, unsigned long cache_control, | |||
172 | 163 | ||
173 | static void homecache_finv_page_va(void* va, int home) | 164 | static void homecache_finv_page_va(void* va, int home) |
174 | { | 165 | { |
175 | if (home == smp_processor_id()) { | 166 | int cpu = get_cpu(); |
167 | if (home == cpu) { | ||
176 | finv_buffer_local(va, PAGE_SIZE); | 168 | finv_buffer_local(va, PAGE_SIZE); |
177 | } else if (home == PAGE_HOME_HASH) { | 169 | } else if (home == PAGE_HOME_HASH) { |
178 | finv_buffer_remote(va, PAGE_SIZE, 1); | 170 | finv_buffer_remote(va, PAGE_SIZE, 1); |
@@ -180,6 +172,7 @@ static void homecache_finv_page_va(void* va, int home) | |||
180 | BUG_ON(home < 0 || home >= NR_CPUS); | 172 | BUG_ON(home < 0 || home >= NR_CPUS); |
181 | finv_buffer_remote(va, PAGE_SIZE, 0); | 173 | finv_buffer_remote(va, PAGE_SIZE, 0); |
182 | } | 174 | } |
175 | put_cpu(); | ||
183 | } | 176 | } |
184 | 177 | ||
185 | void homecache_finv_map_page(struct page *page, int home) | 178 | void homecache_finv_map_page(struct page *page, int home) |
@@ -198,7 +191,7 @@ void homecache_finv_map_page(struct page *page, int home) | |||
198 | #else | 191 | #else |
199 | va = __fix_to_virt(FIX_HOMECACHE_BEGIN + smp_processor_id()); | 192 | va = __fix_to_virt(FIX_HOMECACHE_BEGIN + smp_processor_id()); |
200 | #endif | 193 | #endif |
201 | ptep = virt_to_pte(NULL, (unsigned long)va); | 194 | ptep = virt_to_kpte(va); |
202 | pte = pfn_pte(page_to_pfn(page), PAGE_KERNEL); | 195 | pte = pfn_pte(page_to_pfn(page), PAGE_KERNEL); |
203 | __set_pte(ptep, pte_set_home(pte, home)); | 196 | __set_pte(ptep, pte_set_home(pte, home)); |
204 | homecache_finv_page_va((void *)va, home); | 197 | homecache_finv_page_va((void *)va, home); |
@@ -263,10 +256,8 @@ static int pte_to_home(pte_t pte) | |||
263 | return PAGE_HOME_INCOHERENT; | 256 | return PAGE_HOME_INCOHERENT; |
264 | case HV_PTE_MODE_UNCACHED: | 257 | case HV_PTE_MODE_UNCACHED: |
265 | return PAGE_HOME_UNCACHED; | 258 | return PAGE_HOME_UNCACHED; |
266 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
267 | case HV_PTE_MODE_CACHE_HASH_L3: | 259 | case HV_PTE_MODE_CACHE_HASH_L3: |
268 | return PAGE_HOME_HASH; | 260 | return PAGE_HOME_HASH; |
269 | #endif | ||
270 | } | 261 | } |
271 | panic("Bad PTE %#llx\n", pte.val); | 262 | panic("Bad PTE %#llx\n", pte.val); |
272 | } | 263 | } |
@@ -323,20 +314,16 @@ pte_t pte_set_home(pte_t pte, int home) | |||
323 | HV_PTE_MODE_CACHE_NO_L3); | 314 | HV_PTE_MODE_CACHE_NO_L3); |
324 | } | 315 | } |
325 | } else | 316 | } else |
326 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
327 | if (hash_default) | 317 | if (hash_default) |
328 | pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_HASH_L3); | 318 | pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_HASH_L3); |
329 | else | 319 | else |
330 | #endif | ||
331 | pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3); | 320 | pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3); |
332 | pte = hv_pte_set_nc(pte); | 321 | pte = hv_pte_set_nc(pte); |
333 | break; | 322 | break; |
334 | 323 | ||
335 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
336 | case PAGE_HOME_HASH: | 324 | case PAGE_HOME_HASH: |
337 | pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_HASH_L3); | 325 | pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_HASH_L3); |
338 | break; | 326 | break; |
339 | #endif | ||
340 | 327 | ||
341 | default: | 328 | default: |
342 | BUG_ON(home < 0 || home >= NR_CPUS || | 329 | BUG_ON(home < 0 || home >= NR_CPUS || |
@@ -346,7 +333,6 @@ pte_t pte_set_home(pte_t pte, int home) | |||
346 | break; | 333 | break; |
347 | } | 334 | } |
348 | 335 | ||
349 | #if CHIP_HAS_NC_AND_NOALLOC_BITS() | ||
350 | if (noallocl2) | 336 | if (noallocl2) |
351 | pte = hv_pte_set_no_alloc_l2(pte); | 337 | pte = hv_pte_set_no_alloc_l2(pte); |
352 | 338 | ||
@@ -355,7 +341,6 @@ pte_t pte_set_home(pte_t pte, int home) | |||
355 | hv_pte_get_mode(pte) == HV_PTE_MODE_CACHE_NO_L3) { | 341 | hv_pte_get_mode(pte) == HV_PTE_MODE_CACHE_NO_L3) { |
356 | pte = hv_pte_set_mode(pte, HV_PTE_MODE_UNCACHED); | 342 | pte = hv_pte_set_mode(pte, HV_PTE_MODE_UNCACHED); |
357 | } | 343 | } |
358 | #endif | ||
359 | 344 | ||
360 | /* Checking this case here gives a better panic than from the hv. */ | 345 | /* Checking this case here gives a better panic than from the hv. */ |
361 | BUG_ON(hv_pte_get_mode(pte) == 0); | 346 | BUG_ON(hv_pte_get_mode(pte) == 0); |
@@ -371,19 +356,13 @@ EXPORT_SYMBOL(pte_set_home); | |||
371 | * so they're not suitable for anything but infrequent use. | 356 | * so they're not suitable for anything but infrequent use. |
372 | */ | 357 | */ |
373 | 358 | ||
374 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
375 | static inline int initial_page_home(void) { return PAGE_HOME_HASH; } | ||
376 | #else | ||
377 | static inline int initial_page_home(void) { return 0; } | ||
378 | #endif | ||
379 | |||
380 | int page_home(struct page *page) | 359 | int page_home(struct page *page) |
381 | { | 360 | { |
382 | if (PageHighMem(page)) { | 361 | if (PageHighMem(page)) { |
383 | return initial_page_home(); | 362 | return PAGE_HOME_HASH; |
384 | } else { | 363 | } else { |
385 | unsigned long kva = (unsigned long)page_address(page); | 364 | unsigned long kva = (unsigned long)page_address(page); |
386 | return pte_to_home(*virt_to_pte(NULL, kva)); | 365 | return pte_to_home(*virt_to_kpte(kva)); |
387 | } | 366 | } |
388 | } | 367 | } |
389 | EXPORT_SYMBOL(page_home); | 368 | EXPORT_SYMBOL(page_home); |
@@ -402,7 +381,7 @@ void homecache_change_page_home(struct page *page, int order, int home) | |||
402 | NULL, 0); | 381 | NULL, 0); |
403 | 382 | ||
404 | for (i = 0; i < pages; ++i, kva += PAGE_SIZE) { | 383 | for (i = 0; i < pages; ++i, kva += PAGE_SIZE) { |
405 | pte_t *ptep = virt_to_pte(NULL, kva); | 384 | pte_t *ptep = virt_to_kpte(kva); |
406 | pte_t pteval = *ptep; | 385 | pte_t pteval = *ptep; |
407 | BUG_ON(!pte_present(pteval) || pte_huge(pteval)); | 386 | BUG_ON(!pte_present(pteval) || pte_huge(pteval)); |
408 | __set_pte(ptep, pte_set_home(pteval, home)); | 387 | __set_pte(ptep, pte_set_home(pteval, home)); |
@@ -436,7 +415,7 @@ struct page *homecache_alloc_pages_node(int nid, gfp_t gfp_mask, | |||
436 | void __homecache_free_pages(struct page *page, unsigned int order) | 415 | void __homecache_free_pages(struct page *page, unsigned int order) |
437 | { | 416 | { |
438 | if (put_page_testzero(page)) { | 417 | if (put_page_testzero(page)) { |
439 | homecache_change_page_home(page, order, initial_page_home()); | 418 | homecache_change_page_home(page, order, PAGE_HOME_HASH); |
440 | if (order == 0) { | 419 | if (order == 0) { |
441 | free_hot_cold_page(page, 0); | 420 | free_hot_cold_page(page, 0); |
442 | } else { | 421 | } else { |
diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c index 650ccff8378c..e514899e1100 100644 --- a/arch/tile/mm/hugetlbpage.c +++ b/arch/tile/mm/hugetlbpage.c | |||
@@ -49,38 +49,6 @@ int huge_shift[HUGE_SHIFT_ENTRIES] = { | |||
49 | #endif | 49 | #endif |
50 | }; | 50 | }; |
51 | 51 | ||
52 | /* | ||
53 | * This routine is a hybrid of pte_alloc_map() and pte_alloc_kernel(). | ||
54 | * It assumes that L2 PTEs are never in HIGHMEM (we don't support that). | ||
55 | * It locks the user pagetable, and bumps up the mm->nr_ptes field, | ||
56 | * but otherwise allocate the page table using the kernel versions. | ||
57 | */ | ||
58 | static pte_t *pte_alloc_hugetlb(struct mm_struct *mm, pmd_t *pmd, | ||
59 | unsigned long address) | ||
60 | { | ||
61 | pte_t *new; | ||
62 | |||
63 | if (pmd_none(*pmd)) { | ||
64 | new = pte_alloc_one_kernel(mm, address); | ||
65 | if (!new) | ||
66 | return NULL; | ||
67 | |||
68 | smp_wmb(); /* See comment in __pte_alloc */ | ||
69 | |||
70 | spin_lock(&mm->page_table_lock); | ||
71 | if (likely(pmd_none(*pmd))) { /* Has another populated it ? */ | ||
72 | mm->nr_ptes++; | ||
73 | pmd_populate_kernel(mm, pmd, new); | ||
74 | new = NULL; | ||
75 | } else | ||
76 | VM_BUG_ON(pmd_trans_splitting(*pmd)); | ||
77 | spin_unlock(&mm->page_table_lock); | ||
78 | if (new) | ||
79 | pte_free_kernel(mm, new); | ||
80 | } | ||
81 | |||
82 | return pte_offset_kernel(pmd, address); | ||
83 | } | ||
84 | #endif | 52 | #endif |
85 | 53 | ||
86 | pte_t *huge_pte_alloc(struct mm_struct *mm, | 54 | pte_t *huge_pte_alloc(struct mm_struct *mm, |
@@ -109,7 +77,7 @@ pte_t *huge_pte_alloc(struct mm_struct *mm, | |||
109 | else { | 77 | else { |
110 | if (sz != PAGE_SIZE << huge_shift[HUGE_SHIFT_PAGE]) | 78 | if (sz != PAGE_SIZE << huge_shift[HUGE_SHIFT_PAGE]) |
111 | panic("Unexpected page size %#lx\n", sz); | 79 | panic("Unexpected page size %#lx\n", sz); |
112 | return pte_alloc_hugetlb(mm, pmd, addr); | 80 | return pte_alloc_map(mm, NULL, pmd, addr); |
113 | } | 81 | } |
114 | } | 82 | } |
115 | #else | 83 | #else |
@@ -144,14 +112,14 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr) | |||
144 | 112 | ||
145 | /* Get the top-level page table entry. */ | 113 | /* Get the top-level page table entry. */ |
146 | pgd = (pgd_t *)get_pte((pte_t *)mm->pgd, pgd_index(addr), 0); | 114 | pgd = (pgd_t *)get_pte((pte_t *)mm->pgd, pgd_index(addr), 0); |
147 | if (!pgd_present(*pgd)) | ||
148 | return NULL; | ||
149 | 115 | ||
150 | /* We don't have four levels. */ | 116 | /* We don't have four levels. */ |
151 | pud = pud_offset(pgd, addr); | 117 | pud = pud_offset(pgd, addr); |
152 | #ifndef __PAGETABLE_PUD_FOLDED | 118 | #ifndef __PAGETABLE_PUD_FOLDED |
153 | # error support fourth page table level | 119 | # error support fourth page table level |
154 | #endif | 120 | #endif |
121 | if (!pud_present(*pud)) | ||
122 | return NULL; | ||
155 | 123 | ||
156 | /* Check for an L0 huge PTE, if we have three levels. */ | 124 | /* Check for an L0 huge PTE, if we have three levels. */ |
157 | #ifndef __PAGETABLE_PMD_FOLDED | 125 | #ifndef __PAGETABLE_PMD_FOLDED |
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c index e182958c707d..4e316deb92fd 100644 --- a/arch/tile/mm/init.c +++ b/arch/tile/mm/init.c | |||
@@ -106,10 +106,8 @@ pte_t *get_prealloc_pte(unsigned long pfn) | |||
106 | */ | 106 | */ |
107 | static int initial_heap_home(void) | 107 | static int initial_heap_home(void) |
108 | { | 108 | { |
109 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
110 | if (hash_default) | 109 | if (hash_default) |
111 | return PAGE_HOME_HASH; | 110 | return PAGE_HOME_HASH; |
112 | #endif | ||
113 | return smp_processor_id(); | 111 | return smp_processor_id(); |
114 | } | 112 | } |
115 | 113 | ||
@@ -190,14 +188,11 @@ static void __init page_table_range_init(unsigned long start, | |||
190 | } | 188 | } |
191 | 189 | ||
192 | 190 | ||
193 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
194 | |||
195 | static int __initdata ktext_hash = 1; /* .text pages */ | 191 | static int __initdata ktext_hash = 1; /* .text pages */ |
196 | static int __initdata kdata_hash = 1; /* .data and .bss pages */ | 192 | static int __initdata kdata_hash = 1; /* .data and .bss pages */ |
197 | int __write_once hash_default = 1; /* kernel allocator pages */ | 193 | int __write_once hash_default = 1; /* kernel allocator pages */ |
198 | EXPORT_SYMBOL(hash_default); | 194 | EXPORT_SYMBOL(hash_default); |
199 | int __write_once kstack_hash = 1; /* if no homecaching, use h4h */ | 195 | int __write_once kstack_hash = 1; /* if no homecaching, use h4h */ |
200 | #endif /* CHIP_HAS_CBOX_HOME_MAP */ | ||
201 | 196 | ||
202 | /* | 197 | /* |
203 | * CPUs to use to for striping the pages of kernel data. If hash-for-home | 198 | * CPUs to use to for striping the pages of kernel data. If hash-for-home |
@@ -215,14 +210,12 @@ int __write_once kdata_huge; /* if no homecaching, small pages */ | |||
215 | static pgprot_t __init construct_pgprot(pgprot_t prot, int home) | 210 | static pgprot_t __init construct_pgprot(pgprot_t prot, int home) |
216 | { | 211 | { |
217 | prot = pte_set_home(prot, home); | 212 | prot = pte_set_home(prot, home); |
218 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
219 | if (home == PAGE_HOME_IMMUTABLE) { | 213 | if (home == PAGE_HOME_IMMUTABLE) { |
220 | if (ktext_hash) | 214 | if (ktext_hash) |
221 | prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_HASH_L3); | 215 | prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_HASH_L3); |
222 | else | 216 | else |
223 | prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_NO_L3); | 217 | prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_NO_L3); |
224 | } | 218 | } |
225 | #endif | ||
226 | return prot; | 219 | return prot; |
227 | } | 220 | } |
228 | 221 | ||
@@ -234,22 +227,17 @@ static pgprot_t __init init_pgprot(ulong address) | |||
234 | { | 227 | { |
235 | int cpu; | 228 | int cpu; |
236 | unsigned long page; | 229 | unsigned long page; |
237 | enum { CODE_DELTA = MEM_SV_INTRPT - PAGE_OFFSET }; | 230 | enum { CODE_DELTA = MEM_SV_START - PAGE_OFFSET }; |
238 | 231 | ||
239 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
240 | /* For kdata=huge, everything is just hash-for-home. */ | 232 | /* For kdata=huge, everything is just hash-for-home. */ |
241 | if (kdata_huge) | 233 | if (kdata_huge) |
242 | return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); | 234 | return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); |
243 | #endif | ||
244 | 235 | ||
245 | /* We map the aliased pages of permanent text inaccessible. */ | 236 | /* We map the aliased pages of permanent text inaccessible. */ |
246 | if (address < (ulong) _sinittext - CODE_DELTA) | 237 | if (address < (ulong) _sinittext - CODE_DELTA) |
247 | return PAGE_NONE; | 238 | return PAGE_NONE; |
248 | 239 | ||
249 | /* | 240 | /* We map read-only data non-coherent for performance. */ |
250 | * We map read-only data non-coherent for performance. We could | ||
251 | * use neighborhood caching on TILE64, but it's not clear it's a win. | ||
252 | */ | ||
253 | if ((address >= (ulong) __start_rodata && | 241 | if ((address >= (ulong) __start_rodata && |
254 | address < (ulong) __end_rodata) || | 242 | address < (ulong) __end_rodata) || |
255 | address == (ulong) empty_zero_page) { | 243 | address == (ulong) empty_zero_page) { |
@@ -257,12 +245,10 @@ static pgprot_t __init init_pgprot(ulong address) | |||
257 | } | 245 | } |
258 | 246 | ||
259 | #ifndef __tilegx__ | 247 | #ifndef __tilegx__ |
260 | #if !ATOMIC_LOCKS_FOUND_VIA_TABLE() | ||
261 | /* Force the atomic_locks[] array page to be hash-for-home. */ | 248 | /* Force the atomic_locks[] array page to be hash-for-home. */ |
262 | if (address == (ulong) atomic_locks) | 249 | if (address == (ulong) atomic_locks) |
263 | return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); | 250 | return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); |
264 | #endif | 251 | #endif |
265 | #endif | ||
266 | 252 | ||
267 | /* | 253 | /* |
268 | * Everything else that isn't data or bss is heap, so mark it | 254 | * Everything else that isn't data or bss is heap, so mark it |
@@ -280,19 +266,9 @@ static pgprot_t __init init_pgprot(ulong address) | |||
280 | if (address >= (ulong) _end || address < (ulong) _einitdata) | 266 | if (address >= (ulong) _end || address < (ulong) _einitdata) |
281 | return construct_pgprot(PAGE_KERNEL, initial_heap_home()); | 267 | return construct_pgprot(PAGE_KERNEL, initial_heap_home()); |
282 | 268 | ||
283 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
284 | /* Use hash-for-home if requested for data/bss. */ | 269 | /* Use hash-for-home if requested for data/bss. */ |
285 | if (kdata_hash) | 270 | if (kdata_hash) |
286 | return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); | 271 | return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); |
287 | #endif | ||
288 | |||
289 | /* | ||
290 | * Make the w1data homed like heap to start with, to avoid | ||
291 | * making it part of the page-striped data area when we're just | ||
292 | * going to convert it to read-only soon anyway. | ||
293 | */ | ||
294 | if (address >= (ulong)__w1data_begin && address < (ulong)__w1data_end) | ||
295 | return construct_pgprot(PAGE_KERNEL, initial_heap_home()); | ||
296 | 272 | ||
297 | /* | 273 | /* |
298 | * Otherwise we just hand out consecutive cpus. To avoid | 274 | * Otherwise we just hand out consecutive cpus. To avoid |
@@ -301,7 +277,7 @@ static pgprot_t __init init_pgprot(ulong address) | |||
301 | * the requested address, while walking cpu home around kdata_mask. | 277 | * the requested address, while walking cpu home around kdata_mask. |
302 | * This is typically no more than a dozen or so iterations. | 278 | * This is typically no more than a dozen or so iterations. |
303 | */ | 279 | */ |
304 | page = (((ulong)__w1data_end) + PAGE_SIZE - 1) & PAGE_MASK; | 280 | page = (((ulong)__end_rodata) + PAGE_SIZE - 1) & PAGE_MASK; |
305 | BUG_ON(address < page || address >= (ulong)_end); | 281 | BUG_ON(address < page || address >= (ulong)_end); |
306 | cpu = cpumask_first(&kdata_mask); | 282 | cpu = cpumask_first(&kdata_mask); |
307 | for (; page < address; page += PAGE_SIZE) { | 283 | for (; page < address; page += PAGE_SIZE) { |
@@ -311,11 +287,9 @@ static pgprot_t __init init_pgprot(ulong address) | |||
311 | if (page == (ulong)empty_zero_page) | 287 | if (page == (ulong)empty_zero_page) |
312 | continue; | 288 | continue; |
313 | #ifndef __tilegx__ | 289 | #ifndef __tilegx__ |
314 | #if !ATOMIC_LOCKS_FOUND_VIA_TABLE() | ||
315 | if (page == (ulong)atomic_locks) | 290 | if (page == (ulong)atomic_locks) |
316 | continue; | 291 | continue; |
317 | #endif | 292 | #endif |
318 | #endif | ||
319 | cpu = cpumask_next(cpu, &kdata_mask); | 293 | cpu = cpumask_next(cpu, &kdata_mask); |
320 | if (cpu == NR_CPUS) | 294 | if (cpu == NR_CPUS) |
321 | cpu = cpumask_first(&kdata_mask); | 295 | cpu = cpumask_first(&kdata_mask); |
@@ -358,7 +332,7 @@ static int __init setup_ktext(char *str) | |||
358 | 332 | ||
359 | ktext_arg_seen = 1; | 333 | ktext_arg_seen = 1; |
360 | 334 | ||
361 | /* Default setting on Tile64: use a huge page */ | 335 | /* Default setting: use a huge page */ |
362 | if (strcmp(str, "huge") == 0) | 336 | if (strcmp(str, "huge") == 0) |
363 | pr_info("ktext: using one huge locally cached page\n"); | 337 | pr_info("ktext: using one huge locally cached page\n"); |
364 | 338 | ||
@@ -404,10 +378,8 @@ static inline pgprot_t ktext_set_nocache(pgprot_t prot) | |||
404 | { | 378 | { |
405 | if (!ktext_nocache) | 379 | if (!ktext_nocache) |
406 | prot = hv_pte_set_nc(prot); | 380 | prot = hv_pte_set_nc(prot); |
407 | #if CHIP_HAS_NC_AND_NOALLOC_BITS() | ||
408 | else | 381 | else |
409 | prot = hv_pte_set_no_alloc_l2(prot); | 382 | prot = hv_pte_set_no_alloc_l2(prot); |
410 | #endif | ||
411 | return prot; | 383 | return prot; |
412 | } | 384 | } |
413 | 385 | ||
@@ -440,7 +412,6 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
440 | struct cpumask kstripe_mask; | 412 | struct cpumask kstripe_mask; |
441 | int rc, i; | 413 | int rc, i; |
442 | 414 | ||
443 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
444 | if (ktext_arg_seen && ktext_hash) { | 415 | if (ktext_arg_seen && ktext_hash) { |
445 | pr_warning("warning: \"ktext\" boot argument ignored" | 416 | pr_warning("warning: \"ktext\" boot argument ignored" |
446 | " if \"kcache_hash\" sets up text hash-for-home\n"); | 417 | " if \"kcache_hash\" sets up text hash-for-home\n"); |
@@ -457,7 +428,6 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
457 | " kcache_hash=all or =allbutstack\n"); | 428 | " kcache_hash=all or =allbutstack\n"); |
458 | kdata_huge = 0; | 429 | kdata_huge = 0; |
459 | } | 430 | } |
460 | #endif | ||
461 | 431 | ||
462 | /* | 432 | /* |
463 | * Set up a mask for cpus to use for kernel striping. | 433 | * Set up a mask for cpus to use for kernel striping. |
@@ -538,7 +508,7 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
538 | } | 508 | } |
539 | } | 509 | } |
540 | 510 | ||
541 | address = MEM_SV_INTRPT; | 511 | address = MEM_SV_START; |
542 | pmd = get_pmd(pgtables, address); | 512 | pmd = get_pmd(pgtables, address); |
543 | pfn = 0; /* code starts at PA 0 */ | 513 | pfn = 0; /* code starts at PA 0 */ |
544 | if (ktext_small) { | 514 | if (ktext_small) { |
@@ -585,13 +555,11 @@ static void __init kernel_physical_mapping_init(pgd_t *pgd_base) | |||
585 | } else { | 555 | } else { |
586 | pte_t pteval = pfn_pte(0, PAGE_KERNEL_EXEC); | 556 | pte_t pteval = pfn_pte(0, PAGE_KERNEL_EXEC); |
587 | pteval = pte_mkhuge(pteval); | 557 | pteval = pte_mkhuge(pteval); |
588 | #if CHIP_HAS_CBOX_HOME_MAP() | ||
589 | if (ktext_hash) { | 558 | if (ktext_hash) { |
590 | pteval = hv_pte_set_mode(pteval, | 559 | pteval = hv_pte_set_mode(pteval, |
591 | HV_PTE_MODE_CACHE_HASH_L3); | 560 | HV_PTE_MODE_CACHE_HASH_L3); |
592 | pteval = ktext_set_nocache(pteval); | 561 | pteval = ktext_set_nocache(pteval); |
593 | } else | 562 | } else |
594 | #endif /* CHIP_HAS_CBOX_HOME_MAP() */ | ||
595 | if (cpumask_weight(&ktext_mask) == 1) { | 563 | if (cpumask_weight(&ktext_mask) == 1) { |
596 | pteval = set_remote_cache_cpu(pteval, | 564 | pteval = set_remote_cache_cpu(pteval, |
597 | cpumask_first(&ktext_mask)); | 565 | cpumask_first(&ktext_mask)); |
@@ -777,10 +745,7 @@ void __init paging_init(void) | |||
777 | 745 | ||
778 | kernel_physical_mapping_init(pgd_base); | 746 | kernel_physical_mapping_init(pgd_base); |
779 | 747 | ||
780 | /* | 748 | /* Fixed mappings, only the page table structure has to be created. */ |
781 | * Fixed mappings, only the page table structure has to be | ||
782 | * created - mappings will be set by set_fixmap(): | ||
783 | */ | ||
784 | page_table_range_init(fix_to_virt(__end_of_fixed_addresses - 1), | 749 | page_table_range_init(fix_to_virt(__end_of_fixed_addresses - 1), |
785 | FIXADDR_TOP, pgd_base); | 750 | FIXADDR_TOP, pgd_base); |
786 | 751 | ||
@@ -941,26 +906,6 @@ void __init pgtable_cache_init(void) | |||
941 | panic("pgtable_cache_init(): Cannot create pgd cache"); | 906 | panic("pgtable_cache_init(): Cannot create pgd cache"); |
942 | } | 907 | } |
943 | 908 | ||
944 | #if !CHIP_HAS_COHERENT_LOCAL_CACHE() | ||
945 | /* | ||
946 | * The __w1data area holds data that is only written during initialization, | ||
947 | * and is read-only and thus freely cacheable thereafter. Fix the page | ||
948 | * table entries that cover that region accordingly. | ||
949 | */ | ||
950 | static void mark_w1data_ro(void) | ||
951 | { | ||
952 | /* Loop over page table entries */ | ||
953 | unsigned long addr = (unsigned long)__w1data_begin; | ||
954 | BUG_ON((addr & (PAGE_SIZE-1)) != 0); | ||
955 | for (; addr <= (unsigned long)__w1data_end - 1; addr += PAGE_SIZE) { | ||
956 | unsigned long pfn = kaddr_to_pfn((void *)addr); | ||
957 | pte_t *ptep = virt_to_pte(NULL, addr); | ||
958 | BUG_ON(pte_huge(*ptep)); /* not relevant for kdata_huge */ | ||
959 | set_pte_at(&init_mm, addr, ptep, pfn_pte(pfn, PAGE_KERNEL_RO)); | ||
960 | } | ||
961 | } | ||
962 | #endif | ||
963 | |||
964 | #ifdef CONFIG_DEBUG_PAGEALLOC | 909 | #ifdef CONFIG_DEBUG_PAGEALLOC |
965 | static long __write_once initfree; | 910 | static long __write_once initfree; |
966 | #else | 911 | #else |
@@ -1000,7 +945,7 @@ static void free_init_pages(char *what, unsigned long begin, unsigned long end) | |||
1000 | */ | 945 | */ |
1001 | int pfn = kaddr_to_pfn((void *)addr); | 946 | int pfn = kaddr_to_pfn((void *)addr); |
1002 | struct page *page = pfn_to_page(pfn); | 947 | struct page *page = pfn_to_page(pfn); |
1003 | pte_t *ptep = virt_to_pte(NULL, addr); | 948 | pte_t *ptep = virt_to_kpte(addr); |
1004 | if (!initfree) { | 949 | if (!initfree) { |
1005 | /* | 950 | /* |
1006 | * If debugging page accesses then do not free | 951 | * If debugging page accesses then do not free |
@@ -1024,15 +969,11 @@ static void free_init_pages(char *what, unsigned long begin, unsigned long end) | |||
1024 | 969 | ||
1025 | void free_initmem(void) | 970 | void free_initmem(void) |
1026 | { | 971 | { |
1027 | const unsigned long text_delta = MEM_SV_INTRPT - PAGE_OFFSET; | 972 | const unsigned long text_delta = MEM_SV_START - PAGE_OFFSET; |
1028 | 973 | ||
1029 | /* | 974 | /* |
1030 | * Evict the dirty initdata on the boot cpu, evict the w1data | 975 | * Evict the cache on all cores to avoid incoherence. |
1031 | * wherever it's homed, and evict all the init code everywhere. | 976 | * We are guaranteed that no one will touch the init pages any more. |
1032 | * We are guaranteed that no one will touch the init pages any | ||
1033 | * more, and although other cpus may be touching the w1data, | ||
1034 | * we only actually change the caching on tile64, which won't | ||
1035 | * be keeping local copies in the other tiles' caches anyway. | ||
1036 | */ | 977 | */ |
1037 | homecache_evict(&cpu_cacheable_map); | 978 | homecache_evict(&cpu_cacheable_map); |
1038 | 979 | ||
@@ -1043,26 +984,11 @@ void free_initmem(void) | |||
1043 | 984 | ||
1044 | /* | 985 | /* |
1045 | * Free the pages mapped from 0xc0000000 that correspond to code | 986 | * Free the pages mapped from 0xc0000000 that correspond to code |
1046 | * pages from MEM_SV_INTRPT that we won't use again after init. | 987 | * pages from MEM_SV_START that we won't use again after init. |
1047 | */ | 988 | */ |
1048 | free_init_pages("unused kernel text", | 989 | free_init_pages("unused kernel text", |
1049 | (unsigned long)_sinittext - text_delta, | 990 | (unsigned long)_sinittext - text_delta, |
1050 | (unsigned long)_einittext - text_delta); | 991 | (unsigned long)_einittext - text_delta); |
1051 | |||
1052 | #if !CHIP_HAS_COHERENT_LOCAL_CACHE() | ||
1053 | /* | ||
1054 | * Upgrade the .w1data section to globally cached. | ||
1055 | * We don't do this on tilepro, since the cache architecture | ||
1056 | * pretty much makes it irrelevant, and in any case we end | ||
1057 | * up having racing issues with other tiles that may touch | ||
1058 | * the data after we flush the cache but before we update | ||
1059 | * the PTEs and flush the TLBs, causing sharer shootdowns | ||
1060 | * later. Even though this is to clean data, it seems like | ||
1061 | * an unnecessary complication. | ||
1062 | */ | ||
1063 | mark_w1data_ro(); | ||
1064 | #endif | ||
1065 | |||
1066 | /* Do a global TLB flush so everyone sees the changes. */ | 992 | /* Do a global TLB flush so everyone sees the changes. */ |
1067 | flush_tlb_all(); | 993 | flush_tlb_all(); |
1068 | } | 994 | } |
diff --git a/arch/tile/mm/migrate_32.S b/arch/tile/mm/migrate_32.S index 5305814bf187..772085491bf9 100644 --- a/arch/tile/mm/migrate_32.S +++ b/arch/tile/mm/migrate_32.S | |||
@@ -136,7 +136,7 @@ STD_ENTRY(flush_and_install_context) | |||
136 | move r8, zero /* asids */ | 136 | move r8, zero /* asids */ |
137 | move r9, zero /* asidcount */ | 137 | move r9, zero /* asidcount */ |
138 | } | 138 | } |
139 | jal hv_flush_remote | 139 | jal _hv_flush_remote |
140 | bnz r0, .Ldone | 140 | bnz r0, .Ldone |
141 | 141 | ||
142 | /* Now install the new page table. */ | 142 | /* Now install the new page table. */ |
@@ -152,7 +152,7 @@ STD_ENTRY(flush_and_install_context) | |||
152 | move r4, r_asid | 152 | move r4, r_asid |
153 | moveli r5, HV_CTX_DIRECTIO | CTX_PAGE_FLAG | 153 | moveli r5, HV_CTX_DIRECTIO | CTX_PAGE_FLAG |
154 | } | 154 | } |
155 | jal hv_install_context | 155 | jal _hv_install_context |
156 | bnz r0, .Ldone | 156 | bnz r0, .Ldone |
157 | 157 | ||
158 | /* Finally, flush the TLB. */ | 158 | /* Finally, flush the TLB. */ |
diff --git a/arch/tile/mm/migrate_64.S b/arch/tile/mm/migrate_64.S index 1d15b10833d1..a49eee38f872 100644 --- a/arch/tile/mm/migrate_64.S +++ b/arch/tile/mm/migrate_64.S | |||
@@ -123,7 +123,7 @@ STD_ENTRY(flush_and_install_context) | |||
123 | } | 123 | } |
124 | { | 124 | { |
125 | move r8, zero /* asidcount */ | 125 | move r8, zero /* asidcount */ |
126 | jal hv_flush_remote | 126 | jal _hv_flush_remote |
127 | } | 127 | } |
128 | bnez r0, 1f | 128 | bnez r0, 1f |
129 | 129 | ||
@@ -136,7 +136,7 @@ STD_ENTRY(flush_and_install_context) | |||
136 | move r2, r_asid | 136 | move r2, r_asid |
137 | moveli r3, HV_CTX_DIRECTIO | CTX_PAGE_FLAG | 137 | moveli r3, HV_CTX_DIRECTIO | CTX_PAGE_FLAG |
138 | } | 138 | } |
139 | jal hv_install_context | 139 | jal _hv_install_context |
140 | bnez r0, 1f | 140 | bnez r0, 1f |
141 | 141 | ||
142 | /* Finally, flush the TLB. */ | 142 | /* Finally, flush the TLB. */ |
diff --git a/arch/tile/mm/mmap.c b/arch/tile/mm/mmap.c index d67d91ebf63e..851a94e6ae58 100644 --- a/arch/tile/mm/mmap.c +++ b/arch/tile/mm/mmap.c | |||
@@ -58,16 +58,36 @@ void arch_pick_mmap_layout(struct mm_struct *mm) | |||
58 | #else | 58 | #else |
59 | int is_32bit = 0; | 59 | int is_32bit = 0; |
60 | #endif | 60 | #endif |
61 | unsigned long random_factor = 0UL; | ||
62 | |||
63 | /* | ||
64 | * 8 bits of randomness in 32bit mmaps, 24 address space bits | ||
65 | * 12 bits of randomness in 64bit mmaps, 28 address space bits | ||
66 | */ | ||
67 | if (current->flags & PF_RANDOMIZE) { | ||
68 | if (is_32bit) | ||
69 | random_factor = get_random_int() % (1<<8); | ||
70 | else | ||
71 | random_factor = get_random_int() % (1<<12); | ||
72 | |||
73 | random_factor <<= PAGE_SHIFT; | ||
74 | } | ||
61 | 75 | ||
62 | /* | 76 | /* |
63 | * Use standard layout if the expected stack growth is unlimited | 77 | * Use standard layout if the expected stack growth is unlimited |
64 | * or we are running native 64 bits. | 78 | * or we are running native 64 bits. |
65 | */ | 79 | */ |
66 | if (!is_32bit || rlimit(RLIMIT_STACK) == RLIM_INFINITY) { | 80 | if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) { |
67 | mm->mmap_base = TASK_UNMAPPED_BASE; | 81 | mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; |
68 | mm->get_unmapped_area = arch_get_unmapped_area; | 82 | mm->get_unmapped_area = arch_get_unmapped_area; |
69 | } else { | 83 | } else { |
70 | mm->mmap_base = mmap_base(mm); | 84 | mm->mmap_base = mmap_base(mm); |
71 | mm->get_unmapped_area = arch_get_unmapped_area_topdown; | 85 | mm->get_unmapped_area = arch_get_unmapped_area_topdown; |
72 | } | 86 | } |
73 | } | 87 | } |
88 | |||
89 | unsigned long arch_randomize_brk(struct mm_struct *mm) | ||
90 | { | ||
91 | unsigned long range_end = mm->brk + 0x02000000; | ||
92 | return randomize_range(mm->brk, range_end, 0) ? : mm->brk; | ||
93 | } | ||
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c index dfd63ce87327..2deaddf3e01f 100644 --- a/arch/tile/mm/pgtable.c +++ b/arch/tile/mm/pgtable.c | |||
@@ -83,55 +83,6 @@ void show_mem(unsigned int filter) | |||
83 | } | 83 | } |
84 | } | 84 | } |
85 | 85 | ||
86 | /* | ||
87 | * Associate a virtual page frame with a given physical page frame | ||
88 | * and protection flags for that frame. | ||
89 | */ | ||
90 | static void set_pte_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags) | ||
91 | { | ||
92 | pgd_t *pgd; | ||
93 | pud_t *pud; | ||
94 | pmd_t *pmd; | ||
95 | pte_t *pte; | ||
96 | |||
97 | pgd = swapper_pg_dir + pgd_index(vaddr); | ||
98 | if (pgd_none(*pgd)) { | ||
99 | BUG(); | ||
100 | return; | ||
101 | } | ||
102 | pud = pud_offset(pgd, vaddr); | ||
103 | if (pud_none(*pud)) { | ||
104 | BUG(); | ||
105 | return; | ||
106 | } | ||
107 | pmd = pmd_offset(pud, vaddr); | ||
108 | if (pmd_none(*pmd)) { | ||
109 | BUG(); | ||
110 | return; | ||
111 | } | ||
112 | pte = pte_offset_kernel(pmd, vaddr); | ||
113 | /* <pfn,flags> stored as-is, to permit clearing entries */ | ||
114 | set_pte(pte, pfn_pte(pfn, flags)); | ||
115 | |||
116 | /* | ||
117 | * It's enough to flush this one mapping. | ||
118 | * This appears conservative since it is only called | ||
119 | * from __set_fixmap. | ||
120 | */ | ||
121 | local_flush_tlb_page(NULL, vaddr, PAGE_SIZE); | ||
122 | } | ||
123 | |||
124 | void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags) | ||
125 | { | ||
126 | unsigned long address = __fix_to_virt(idx); | ||
127 | |||
128 | if (idx >= __end_of_fixed_addresses) { | ||
129 | BUG(); | ||
130 | return; | ||
131 | } | ||
132 | set_pte_pfn(address, phys >> PAGE_SHIFT, flags); | ||
133 | } | ||
134 | |||
135 | /** | 86 | /** |
136 | * shatter_huge_page() - ensure a given address is mapped by a small page. | 87 | * shatter_huge_page() - ensure a given address is mapped by a small page. |
137 | * | 88 | * |
@@ -374,6 +325,17 @@ void ptep_set_wrprotect(struct mm_struct *mm, | |||
374 | 325 | ||
375 | #endif | 326 | #endif |
376 | 327 | ||
328 | /* | ||
329 | * Return a pointer to the PTE that corresponds to the given | ||
330 | * address in the given page table. A NULL page table just uses | ||
331 | * the standard kernel page table; the preferred API in this case | ||
332 | * is virt_to_kpte(). | ||
333 | * | ||
334 | * The returned pointer can point to a huge page in other levels | ||
335 | * of the page table than the bottom, if the huge page is present | ||
336 | * in the page table. For bottom-level PTEs, the returned pointer | ||
337 | * can point to a PTE that is either present or not. | ||
338 | */ | ||
377 | pte_t *virt_to_pte(struct mm_struct* mm, unsigned long addr) | 339 | pte_t *virt_to_pte(struct mm_struct* mm, unsigned long addr) |
378 | { | 340 | { |
379 | pgd_t *pgd; | 341 | pgd_t *pgd; |
@@ -387,13 +349,23 @@ pte_t *virt_to_pte(struct mm_struct* mm, unsigned long addr) | |||
387 | pud = pud_offset(pgd, addr); | 349 | pud = pud_offset(pgd, addr); |
388 | if (!pud_present(*pud)) | 350 | if (!pud_present(*pud)) |
389 | return NULL; | 351 | return NULL; |
352 | if (pud_huge_page(*pud)) | ||
353 | return (pte_t *)pud; | ||
390 | pmd = pmd_offset(pud, addr); | 354 | pmd = pmd_offset(pud, addr); |
391 | if (pmd_huge_page(*pmd)) | ||
392 | return (pte_t *)pmd; | ||
393 | if (!pmd_present(*pmd)) | 355 | if (!pmd_present(*pmd)) |
394 | return NULL; | 356 | return NULL; |
357 | if (pmd_huge_page(*pmd)) | ||
358 | return (pte_t *)pmd; | ||
395 | return pte_offset_kernel(pmd, addr); | 359 | return pte_offset_kernel(pmd, addr); |
396 | } | 360 | } |
361 | EXPORT_SYMBOL(virt_to_pte); | ||
362 | |||
363 | pte_t *virt_to_kpte(unsigned long kaddr) | ||
364 | { | ||
365 | BUG_ON(kaddr < PAGE_OFFSET); | ||
366 | return virt_to_pte(NULL, kaddr); | ||
367 | } | ||
368 | EXPORT_SYMBOL(virt_to_kpte); | ||
397 | 369 | ||
398 | pgprot_t set_remote_cache_cpu(pgprot_t prot, int cpu) | 370 | pgprot_t set_remote_cache_cpu(pgprot_t prot, int cpu) |
399 | { | 371 | { |
@@ -568,7 +540,7 @@ void __iomem *ioremap_prot(resource_size_t phys_addr, unsigned long size, | |||
568 | addr = area->addr; | 540 | addr = area->addr; |
569 | if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, | 541 | if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, |
570 | phys_addr, pgprot)) { | 542 | phys_addr, pgprot)) { |
571 | remove_vm_area((void *)(PAGE_MASK & (unsigned long) addr)); | 543 | free_vm_area(area); |
572 | return NULL; | 544 | return NULL; |
573 | } | 545 | } |
574 | return (__force void __iomem *) (offset + (char *)addr); | 546 | return (__force void __iomem *) (offset + (char *)addr); |
diff --git a/drivers/edac/tile_edac.c b/drivers/edac/tile_edac.c index a0820536b7d9..578f915ee195 100644 --- a/drivers/edac/tile_edac.c +++ b/drivers/edac/tile_edac.c | |||
@@ -257,7 +257,6 @@ static void __exit tile_edac_exit(void) | |||
257 | if (!pdev) | 257 | if (!pdev) |
258 | continue; | 258 | continue; |
259 | 259 | ||
260 | platform_set_drvdata(pdev, NULL); | ||
261 | platform_device_unregister(pdev); | 260 | platform_device_unregister(pdev); |
262 | } | 261 | } |
263 | platform_driver_unregister(&tile_edac_mc_driver); | 262 | platform_driver_unregister(&tile_edac_mc_driver); |
diff --git a/drivers/tty/hvc/hvc_tile.c b/drivers/tty/hvc/hvc_tile.c index 7a84a0595477..af8cdaa1dcb9 100644 --- a/drivers/tty/hvc/hvc_tile.c +++ b/drivers/tty/hvc/hvc_tile.c | |||
@@ -18,16 +18,46 @@ | |||
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/err.h> | 19 | #include <linux/err.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/irq.h> | ||
21 | #include <linux/moduleparam.h> | 23 | #include <linux/moduleparam.h> |
24 | #include <linux/platform_device.h> | ||
22 | #include <linux/types.h> | 25 | #include <linux/types.h> |
23 | 26 | ||
27 | #include <asm/setup.h> | ||
28 | #include <arch/sim_def.h> | ||
29 | |||
24 | #include <hv/hypervisor.h> | 30 | #include <hv/hypervisor.h> |
25 | 31 | ||
26 | #include "hvc_console.h" | 32 | #include "hvc_console.h" |
27 | 33 | ||
34 | static int use_sim_console; | ||
35 | static int __init sim_console(char *str) | ||
36 | { | ||
37 | use_sim_console = 1; | ||
38 | return 0; | ||
39 | } | ||
40 | early_param("sim_console", sim_console); | ||
41 | |||
42 | int tile_console_write(const char *buf, int count) | ||
43 | { | ||
44 | if (unlikely(use_sim_console)) { | ||
45 | int i; | ||
46 | for (i = 0; i < count; ++i) | ||
47 | __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC | | ||
48 | (buf[i] << _SIM_CONTROL_OPERATOR_BITS)); | ||
49 | __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC | | ||
50 | (SIM_PUTC_FLUSH_BINARY << | ||
51 | _SIM_CONTROL_OPERATOR_BITS)); | ||
52 | return 0; | ||
53 | } else { | ||
54 | return hv_console_write((HV_VirtAddr)buf, count); | ||
55 | } | ||
56 | } | ||
57 | |||
28 | static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count) | 58 | static int hvc_tile_put_chars(uint32_t vt, const char *buf, int count) |
29 | { | 59 | { |
30 | return hv_console_write((HV_VirtAddr)buf, count); | 60 | return tile_console_write(buf, count); |
31 | } | 61 | } |
32 | 62 | ||
33 | static int hvc_tile_get_chars(uint32_t vt, char *buf, int count) | 63 | static int hvc_tile_get_chars(uint32_t vt, char *buf, int count) |
@@ -44,25 +74,132 @@ static int hvc_tile_get_chars(uint32_t vt, char *buf, int count) | |||
44 | return i; | 74 | return i; |
45 | } | 75 | } |
46 | 76 | ||
77 | #ifdef __tilegx__ | ||
78 | /* | ||
79 | * IRQ based callbacks. | ||
80 | */ | ||
81 | static int hvc_tile_notifier_add_irq(struct hvc_struct *hp, int irq) | ||
82 | { | ||
83 | int rc; | ||
84 | int cpu = raw_smp_processor_id(); /* Choose an arbitrary cpu */ | ||
85 | HV_Coord coord = { .x = cpu_x(cpu), .y = cpu_y(cpu) }; | ||
86 | |||
87 | rc = notifier_add_irq(hp, irq); | ||
88 | if (rc) | ||
89 | return rc; | ||
90 | |||
91 | /* | ||
92 | * Request that the hypervisor start sending us interrupts. | ||
93 | * If the hypervisor returns an error, we still return 0, so that | ||
94 | * we can fall back to polling. | ||
95 | */ | ||
96 | if (hv_console_set_ipi(KERNEL_PL, irq, coord) < 0) | ||
97 | notifier_del_irq(hp, irq); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static void hvc_tile_notifier_del_irq(struct hvc_struct *hp, int irq) | ||
103 | { | ||
104 | HV_Coord coord = { 0, 0 }; | ||
105 | |||
106 | /* Tell the hypervisor to stop sending us interrupts. */ | ||
107 | hv_console_set_ipi(KERNEL_PL, -1, coord); | ||
108 | |||
109 | notifier_del_irq(hp, irq); | ||
110 | } | ||
111 | |||
112 | static void hvc_tile_notifier_hangup_irq(struct hvc_struct *hp, int irq) | ||
113 | { | ||
114 | hvc_tile_notifier_del_irq(hp, irq); | ||
115 | } | ||
116 | #endif | ||
117 | |||
47 | static const struct hv_ops hvc_tile_get_put_ops = { | 118 | static const struct hv_ops hvc_tile_get_put_ops = { |
48 | .get_chars = hvc_tile_get_chars, | 119 | .get_chars = hvc_tile_get_chars, |
49 | .put_chars = hvc_tile_put_chars, | 120 | .put_chars = hvc_tile_put_chars, |
121 | #ifdef __tilegx__ | ||
122 | .notifier_add = hvc_tile_notifier_add_irq, | ||
123 | .notifier_del = hvc_tile_notifier_del_irq, | ||
124 | .notifier_hangup = hvc_tile_notifier_hangup_irq, | ||
125 | #endif | ||
126 | }; | ||
127 | |||
128 | |||
129 | #ifdef __tilegx__ | ||
130 | static int hvc_tile_probe(struct platform_device *pdev) | ||
131 | { | ||
132 | struct hvc_struct *hp; | ||
133 | int tile_hvc_irq; | ||
134 | |||
135 | /* Create our IRQ and register it. */ | ||
136 | tile_hvc_irq = create_irq(); | ||
137 | if (tile_hvc_irq < 0) | ||
138 | return -ENXIO; | ||
139 | |||
140 | tile_irq_activate(tile_hvc_irq, TILE_IRQ_PERCPU); | ||
141 | hp = hvc_alloc(0, tile_hvc_irq, &hvc_tile_get_put_ops, 128); | ||
142 | if (IS_ERR(hp)) { | ||
143 | destroy_irq(tile_hvc_irq); | ||
144 | return PTR_ERR(hp); | ||
145 | } | ||
146 | dev_set_drvdata(&pdev->dev, hp); | ||
147 | |||
148 | return 0; | ||
149 | } | ||
150 | |||
151 | static int hvc_tile_remove(struct platform_device *pdev) | ||
152 | { | ||
153 | int rc; | ||
154 | struct hvc_struct *hp = dev_get_drvdata(&pdev->dev); | ||
155 | |||
156 | rc = hvc_remove(hp); | ||
157 | if (rc == 0) | ||
158 | destroy_irq(hp->data); | ||
159 | |||
160 | return rc; | ||
161 | } | ||
162 | |||
163 | static void hvc_tile_shutdown(struct platform_device *pdev) | ||
164 | { | ||
165 | struct hvc_struct *hp = dev_get_drvdata(&pdev->dev); | ||
166 | |||
167 | hvc_tile_notifier_del_irq(hp, hp->data); | ||
168 | } | ||
169 | |||
170 | static struct platform_device hvc_tile_pdev = { | ||
171 | .name = "hvc-tile", | ||
172 | .id = 0, | ||
173 | }; | ||
174 | |||
175 | static struct platform_driver hvc_tile_driver = { | ||
176 | .probe = hvc_tile_probe, | ||
177 | .remove = hvc_tile_remove, | ||
178 | .shutdown = hvc_tile_shutdown, | ||
179 | .driver = { | ||
180 | .name = "hvc-tile", | ||
181 | .owner = THIS_MODULE, | ||
182 | } | ||
50 | }; | 183 | }; |
184 | #endif | ||
51 | 185 | ||
52 | static int __init hvc_tile_console_init(void) | 186 | static int __init hvc_tile_console_init(void) |
53 | { | 187 | { |
54 | extern void disable_early_printk(void); | ||
55 | hvc_instantiate(0, 0, &hvc_tile_get_put_ops); | 188 | hvc_instantiate(0, 0, &hvc_tile_get_put_ops); |
56 | add_preferred_console("hvc", 0, NULL); | 189 | add_preferred_console("hvc", 0, NULL); |
57 | disable_early_printk(); | ||
58 | return 0; | 190 | return 0; |
59 | } | 191 | } |
60 | console_initcall(hvc_tile_console_init); | 192 | console_initcall(hvc_tile_console_init); |
61 | 193 | ||
62 | static int __init hvc_tile_init(void) | 194 | static int __init hvc_tile_init(void) |
63 | { | 195 | { |
64 | struct hvc_struct *s; | 196 | #ifndef __tilegx__ |
65 | s = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128); | 197 | struct hvc_struct *hp; |
66 | return IS_ERR(s) ? PTR_ERR(s) : 0; | 198 | hp = hvc_alloc(0, 0, &hvc_tile_get_put_ops, 128); |
199 | return IS_ERR(hp) ? PTR_ERR(hp) : 0; | ||
200 | #else | ||
201 | platform_device_register(&hvc_tile_pdev); | ||
202 | return platform_driver_register(&hvc_tile_driver); | ||
203 | #endif | ||
67 | } | 204 | } |
68 | device_initcall(hvc_tile_init); | 205 | device_initcall(hvc_tile_init); |
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index cc4c8682b47b..47c6e7b9e150 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig | |||
@@ -1439,6 +1439,15 @@ config SERIAL_EFM32_UART_CONSOLE | |||
1439 | depends on SERIAL_EFM32_UART=y | 1439 | depends on SERIAL_EFM32_UART=y |
1440 | select SERIAL_CORE_CONSOLE | 1440 | select SERIAL_CORE_CONSOLE |
1441 | 1441 | ||
1442 | config SERIAL_TILEGX | ||
1443 | tristate "TILE-Gx on-chip serial port support" | ||
1444 | depends on TILEGX | ||
1445 | select TILE_GXIO_UART | ||
1446 | select SERIAL_CORE | ||
1447 | ---help--- | ||
1448 | This device provides access to the on-chip UARTs on the TILE-Gx | ||
1449 | processor. | ||
1450 | |||
1442 | config SERIAL_ARC | 1451 | config SERIAL_ARC |
1443 | tristate "ARC UART driver support" | 1452 | tristate "ARC UART driver support" |
1444 | select SERIAL_CORE | 1453 | select SERIAL_CORE |
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 47b679c547e9..3068c7722087 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile | |||
@@ -66,6 +66,7 @@ obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o | |||
66 | obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o | 66 | obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o |
67 | obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o | 67 | obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o |
68 | obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o | 68 | obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o |
69 | obj-$(CONFIG_SERIAL_TILEGX) += tilegx.o | ||
69 | obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o | 70 | obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o |
70 | obj-$(CONFIG_SERIAL_QE) += ucc_uart.o | 71 | obj-$(CONFIG_SERIAL_QE) += ucc_uart.o |
71 | obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o | 72 | obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o |
diff --git a/drivers/tty/serial/tilegx.c b/drivers/tty/serial/tilegx.c new file mode 100644 index 000000000000..f92d7e6bd876 --- /dev/null +++ b/drivers/tty/serial/tilegx.c | |||
@@ -0,0 +1,708 @@ | |||
1 | /* | ||
2 | * Copyright 2013 Tilera Corporation. All Rights Reserved. | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, but | ||
9 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or | ||
11 | * NON INFRINGEMENT. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | * TILEGx UART driver. | ||
15 | */ | ||
16 | |||
17 | #include <linux/delay.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/io.h> | ||
21 | #include <linux/irq.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/serial_core.h> | ||
24 | #include <linux/tty.h> | ||
25 | #include <linux/tty_flip.h> | ||
26 | |||
27 | #include <gxio/common.h> | ||
28 | #include <gxio/iorpc_globals.h> | ||
29 | #include <gxio/iorpc_uart.h> | ||
30 | #include <gxio/kiorpc.h> | ||
31 | |||
32 | #include <hv/drv_uart_intf.h> | ||
33 | |||
34 | /* | ||
35 | * Use device name ttyS, major 4, minor 64-65. | ||
36 | * This is the usual serial port name, 8250 conventional range. | ||
37 | */ | ||
38 | #define TILEGX_UART_MAJOR TTY_MAJOR | ||
39 | #define TILEGX_UART_MINOR 64 | ||
40 | #define TILEGX_UART_NAME "ttyS" | ||
41 | #define DRIVER_NAME_STRING "TILEGx_Serial" | ||
42 | #define TILEGX_UART_REF_CLK 125000000; /* REF_CLK is always 125 MHz. */ | ||
43 | |||
44 | struct tile_uart_port { | ||
45 | /* UART port. */ | ||
46 | struct uart_port uart; | ||
47 | |||
48 | /* GXIO device context. */ | ||
49 | gxio_uart_context_t context; | ||
50 | |||
51 | /* UART access mutex. */ | ||
52 | struct mutex mutex; | ||
53 | |||
54 | /* CPU receiving interrupts. */ | ||
55 | int irq_cpu; | ||
56 | }; | ||
57 | |||
58 | static struct tile_uart_port tile_uart_ports[TILEGX_UART_NR]; | ||
59 | static struct uart_driver tilegx_uart_driver; | ||
60 | |||
61 | |||
62 | /* | ||
63 | * Read UART rx fifo, and insert the chars into tty buffer. | ||
64 | */ | ||
65 | static void receive_chars(struct tile_uart_port *tile_uart, | ||
66 | struct tty_struct *tty) | ||
67 | { | ||
68 | int i; | ||
69 | char c; | ||
70 | UART_FIFO_COUNT_t count; | ||
71 | gxio_uart_context_t *context = &tile_uart->context; | ||
72 | struct tty_port *port = tty->port; | ||
73 | |||
74 | count.word = gxio_uart_read(context, UART_FIFO_COUNT); | ||
75 | for (i = 0; i < count.rfifo_count; i++) { | ||
76 | c = (char)gxio_uart_read(context, UART_RECEIVE_DATA); | ||
77 | tty_insert_flip_char(port, c, TTY_NORMAL); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | |||
82 | /* | ||
83 | * Drain the Rx FIFO, called by interrupt handler. | ||
84 | */ | ||
85 | static void handle_receive(struct tile_uart_port *tile_uart) | ||
86 | { | ||
87 | struct tty_port *port = &tile_uart->uart.state->port; | ||
88 | struct tty_struct *tty = tty_port_tty_get(port); | ||
89 | gxio_uart_context_t *context = &tile_uart->context; | ||
90 | |||
91 | if (!tty) | ||
92 | return; | ||
93 | |||
94 | /* First read UART rx fifo. */ | ||
95 | receive_chars(tile_uart, tty); | ||
96 | |||
97 | /* Reset RFIFO_WE interrupt. */ | ||
98 | gxio_uart_write(context, UART_INTERRUPT_STATUS, | ||
99 | UART_INTERRUPT_MASK__RFIFO_WE_MASK); | ||
100 | |||
101 | /* Final read, if any chars comes between the first read and | ||
102 | * the interrupt reset. | ||
103 | */ | ||
104 | receive_chars(tile_uart, tty); | ||
105 | |||
106 | spin_unlock(&tile_uart->uart.lock); | ||
107 | tty_flip_buffer_push(port); | ||
108 | spin_lock(&tile_uart->uart.lock); | ||
109 | tty_kref_put(tty); | ||
110 | } | ||
111 | |||
112 | |||
113 | /* | ||
114 | * Push one char to UART Write FIFO. | ||
115 | * Return 0 on success, -1 if write filo is full. | ||
116 | */ | ||
117 | static int tilegx_putchar(gxio_uart_context_t *context, char c) | ||
118 | { | ||
119 | UART_FLAG_t flag; | ||
120 | flag.word = gxio_uart_read(context, UART_FLAG); | ||
121 | if (flag.wfifo_full) | ||
122 | return -1; | ||
123 | |||
124 | gxio_uart_write(context, UART_TRANSMIT_DATA, (unsigned long)c); | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | |||
129 | /* | ||
130 | * Send chars to UART Write FIFO; called by interrupt handler. | ||
131 | */ | ||
132 | static void handle_transmit(struct tile_uart_port *tile_uart) | ||
133 | { | ||
134 | unsigned char ch; | ||
135 | struct uart_port *port; | ||
136 | struct circ_buf *xmit; | ||
137 | gxio_uart_context_t *context = &tile_uart->context; | ||
138 | |||
139 | /* First reset WFIFO_RE interrupt. */ | ||
140 | gxio_uart_write(context, UART_INTERRUPT_STATUS, | ||
141 | UART_INTERRUPT_MASK__WFIFO_RE_MASK); | ||
142 | |||
143 | port = &tile_uart->uart; | ||
144 | xmit = &port->state->xmit; | ||
145 | if (port->x_char) { | ||
146 | if (tilegx_putchar(context, port->x_char)) | ||
147 | return; | ||
148 | port->x_char = 0; | ||
149 | port->icount.tx++; | ||
150 | } | ||
151 | |||
152 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) | ||
153 | return; | ||
154 | |||
155 | while (!uart_circ_empty(xmit)) { | ||
156 | ch = xmit->buf[xmit->tail]; | ||
157 | if (tilegx_putchar(context, ch)) | ||
158 | break; | ||
159 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
160 | port->icount.tx++; | ||
161 | } | ||
162 | |||
163 | /* Reset WFIFO_RE interrupt. */ | ||
164 | gxio_uart_write(context, UART_INTERRUPT_STATUS, | ||
165 | UART_INTERRUPT_MASK__WFIFO_RE_MASK); | ||
166 | |||
167 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
168 | uart_write_wakeup(port); | ||
169 | } | ||
170 | |||
171 | |||
172 | /* | ||
173 | * UART Interrupt handler. | ||
174 | */ | ||
175 | static irqreturn_t tilegx_interrupt(int irq, void *dev_id) | ||
176 | { | ||
177 | unsigned long flags; | ||
178 | UART_INTERRUPT_STATUS_t intr_stat; | ||
179 | struct tile_uart_port *tile_uart; | ||
180 | gxio_uart_context_t *context; | ||
181 | struct uart_port *port = dev_id; | ||
182 | irqreturn_t ret = IRQ_NONE; | ||
183 | |||
184 | spin_lock_irqsave(&port->lock, flags); | ||
185 | |||
186 | tile_uart = container_of(port, struct tile_uart_port, uart); | ||
187 | context = &tile_uart->context; | ||
188 | intr_stat.word = gxio_uart_read(context, UART_INTERRUPT_STATUS); | ||
189 | |||
190 | if (intr_stat.rfifo_we) { | ||
191 | handle_receive(tile_uart); | ||
192 | ret = IRQ_HANDLED; | ||
193 | } | ||
194 | if (intr_stat.wfifo_re) { | ||
195 | handle_transmit(tile_uart); | ||
196 | ret = IRQ_HANDLED; | ||
197 | } | ||
198 | |||
199 | spin_unlock_irqrestore(&port->lock, flags); | ||
200 | return ret; | ||
201 | } | ||
202 | |||
203 | |||
204 | /* | ||
205 | * Return TIOCSER_TEMT when transmitter FIFO is empty. | ||
206 | */ | ||
207 | static u_int tilegx_tx_empty(struct uart_port *port) | ||
208 | { | ||
209 | int ret; | ||
210 | UART_FLAG_t flag; | ||
211 | struct tile_uart_port *tile_uart; | ||
212 | gxio_uart_context_t *context; | ||
213 | |||
214 | tile_uart = container_of(port, struct tile_uart_port, uart); | ||
215 | if (!mutex_trylock(&tile_uart->mutex)) | ||
216 | return 0; | ||
217 | context = &tile_uart->context; | ||
218 | |||
219 | flag.word = gxio_uart_read(context, UART_FLAG); | ||
220 | ret = (flag.wfifo_empty) ? TIOCSER_TEMT : 0; | ||
221 | mutex_unlock(&tile_uart->mutex); | ||
222 | |||
223 | return ret; | ||
224 | } | ||
225 | |||
226 | |||
227 | /* | ||
228 | * Set state of the modem control output lines. | ||
229 | */ | ||
230 | static void tilegx_set_mctrl(struct uart_port *port, u_int mctrl) | ||
231 | { | ||
232 | /* N/A */ | ||
233 | } | ||
234 | |||
235 | |||
236 | /* | ||
237 | * Get state of the modem control input lines. | ||
238 | */ | ||
239 | static u_int tilegx_get_mctrl(struct uart_port *port) | ||
240 | { | ||
241 | return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR; | ||
242 | } | ||
243 | |||
244 | |||
245 | /* | ||
246 | * Stop transmitting. | ||
247 | */ | ||
248 | static void tilegx_stop_tx(struct uart_port *port) | ||
249 | { | ||
250 | /* N/A */ | ||
251 | } | ||
252 | |||
253 | |||
254 | /* | ||
255 | * Start transmitting. | ||
256 | */ | ||
257 | static void tilegx_start_tx(struct uart_port *port) | ||
258 | { | ||
259 | unsigned char ch; | ||
260 | struct circ_buf *xmit; | ||
261 | struct tile_uart_port *tile_uart; | ||
262 | gxio_uart_context_t *context; | ||
263 | |||
264 | tile_uart = container_of(port, struct tile_uart_port, uart); | ||
265 | if (!mutex_trylock(&tile_uart->mutex)) | ||
266 | return; | ||
267 | context = &tile_uart->context; | ||
268 | xmit = &port->state->xmit; | ||
269 | if (port->x_char) { | ||
270 | if (tilegx_putchar(context, port->x_char)) | ||
271 | return; | ||
272 | port->x_char = 0; | ||
273 | port->icount.tx++; | ||
274 | } | ||
275 | |||
276 | if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { | ||
277 | mutex_unlock(&tile_uart->mutex); | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | while (!uart_circ_empty(xmit)) { | ||
282 | ch = xmit->buf[xmit->tail]; | ||
283 | if (tilegx_putchar(context, ch)) | ||
284 | break; | ||
285 | xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); | ||
286 | port->icount.tx++; | ||
287 | } | ||
288 | |||
289 | if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) | ||
290 | uart_write_wakeup(port); | ||
291 | |||
292 | mutex_unlock(&tile_uart->mutex); | ||
293 | } | ||
294 | |||
295 | |||
296 | /* | ||
297 | * Stop receiving - port is in process of being closed. | ||
298 | */ | ||
299 | static void tilegx_stop_rx(struct uart_port *port) | ||
300 | { | ||
301 | int err; | ||
302 | struct tile_uart_port *tile_uart; | ||
303 | gxio_uart_context_t *context; | ||
304 | int cpu; | ||
305 | |||
306 | tile_uart = container_of(port, struct tile_uart_port, uart); | ||
307 | if (!mutex_trylock(&tile_uart->mutex)) | ||
308 | return; | ||
309 | |||
310 | context = &tile_uart->context; | ||
311 | cpu = tile_uart->irq_cpu; | ||
312 | err = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), | ||
313 | KERNEL_PL, -1); | ||
314 | mutex_unlock(&tile_uart->mutex); | ||
315 | } | ||
316 | |||
317 | |||
318 | /* | ||
319 | * Enable modem status interrupts. | ||
320 | */ | ||
321 | static void tilegx_enable_ms(struct uart_port *port) | ||
322 | { | ||
323 | /* N/A */ | ||
324 | } | ||
325 | |||
326 | /* | ||
327 | * Control the transmission of a break signal. | ||
328 | */ | ||
329 | static void tilegx_break_ctl(struct uart_port *port, int break_state) | ||
330 | { | ||
331 | /* N/A */ | ||
332 | } | ||
333 | |||
334 | |||
335 | /* | ||
336 | * Perform initialization and enable port for reception. | ||
337 | */ | ||
338 | static int tilegx_startup(struct uart_port *port) | ||
339 | { | ||
340 | struct tile_uart_port *tile_uart; | ||
341 | gxio_uart_context_t *context; | ||
342 | int ret = 0; | ||
343 | int cpu = raw_smp_processor_id(); /* pick an arbitrary cpu */ | ||
344 | |||
345 | tile_uart = container_of(port, struct tile_uart_port, uart); | ||
346 | if (mutex_lock_interruptible(&tile_uart->mutex)) | ||
347 | return -EBUSY; | ||
348 | context = &tile_uart->context; | ||
349 | |||
350 | /* Now open the hypervisor device if we haven't already. */ | ||
351 | if (context->fd < 0) { | ||
352 | UART_INTERRUPT_MASK_t intr_mask; | ||
353 | |||
354 | /* Initialize UART device. */ | ||
355 | ret = gxio_uart_init(context, port->line); | ||
356 | if (ret) { | ||
357 | ret = -ENXIO; | ||
358 | goto err; | ||
359 | } | ||
360 | |||
361 | /* Create our IRQs. */ | ||
362 | port->irq = create_irq(); | ||
363 | if (port->irq < 0) | ||
364 | goto err_uart_dest; | ||
365 | tile_irq_activate(port->irq, TILE_IRQ_PERCPU); | ||
366 | |||
367 | /* Register our IRQs. */ | ||
368 | ret = request_irq(port->irq, tilegx_interrupt, 0, | ||
369 | tilegx_uart_driver.driver_name, port); | ||
370 | if (ret) | ||
371 | goto err_dest_irq; | ||
372 | |||
373 | /* Request that the hardware start sending us interrupts. */ | ||
374 | tile_uart->irq_cpu = cpu; | ||
375 | ret = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), | ||
376 | KERNEL_PL, port->irq); | ||
377 | if (ret) | ||
378 | goto err_free_irq; | ||
379 | |||
380 | /* Enable UART Tx/Rx Interrupt. */ | ||
381 | intr_mask.word = gxio_uart_read(context, UART_INTERRUPT_MASK); | ||
382 | intr_mask.wfifo_re = 0; | ||
383 | intr_mask.rfifo_we = 0; | ||
384 | gxio_uart_write(context, UART_INTERRUPT_MASK, intr_mask.word); | ||
385 | |||
386 | /* Reset the Tx/Rx interrupt in case it's set. */ | ||
387 | gxio_uart_write(context, UART_INTERRUPT_STATUS, | ||
388 | UART_INTERRUPT_MASK__WFIFO_RE_MASK | | ||
389 | UART_INTERRUPT_MASK__RFIFO_WE_MASK); | ||
390 | } | ||
391 | |||
392 | mutex_unlock(&tile_uart->mutex); | ||
393 | return ret; | ||
394 | |||
395 | err_free_irq: | ||
396 | free_irq(port->irq, port); | ||
397 | err_dest_irq: | ||
398 | destroy_irq(port->irq); | ||
399 | err_uart_dest: | ||
400 | gxio_uart_destroy(context); | ||
401 | ret = -ENXIO; | ||
402 | err: | ||
403 | mutex_unlock(&tile_uart->mutex); | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | |||
408 | /* | ||
409 | * Release kernel resources if it is the last close, disable the port, | ||
410 | * free IRQ and close the port. | ||
411 | */ | ||
412 | static void tilegx_shutdown(struct uart_port *port) | ||
413 | { | ||
414 | int err; | ||
415 | UART_INTERRUPT_MASK_t intr_mask; | ||
416 | struct tile_uart_port *tile_uart; | ||
417 | gxio_uart_context_t *context; | ||
418 | int cpu; | ||
419 | |||
420 | tile_uart = container_of(port, struct tile_uart_port, uart); | ||
421 | if (mutex_lock_interruptible(&tile_uart->mutex)) | ||
422 | return; | ||
423 | context = &tile_uart->context; | ||
424 | |||
425 | /* Disable UART Tx/Rx Interrupt. */ | ||
426 | intr_mask.word = gxio_uart_read(context, UART_INTERRUPT_MASK); | ||
427 | intr_mask.wfifo_re = 1; | ||
428 | intr_mask.rfifo_we = 1; | ||
429 | gxio_uart_write(context, UART_INTERRUPT_MASK, intr_mask.word); | ||
430 | |||
431 | /* Request that the hardware stop sending us interrupts. */ | ||
432 | cpu = tile_uart->irq_cpu; | ||
433 | err = gxio_uart_cfg_interrupt(context, cpu_x(cpu), cpu_y(cpu), | ||
434 | KERNEL_PL, -1); | ||
435 | |||
436 | if (port->irq > 0) { | ||
437 | free_irq(port->irq, port); | ||
438 | destroy_irq(port->irq); | ||
439 | port->irq = 0; | ||
440 | } | ||
441 | |||
442 | gxio_uart_destroy(context); | ||
443 | |||
444 | mutex_unlock(&tile_uart->mutex); | ||
445 | } | ||
446 | |||
447 | |||
448 | /* | ||
449 | * Flush the buffer. | ||
450 | */ | ||
451 | static void tilegx_flush_buffer(struct uart_port *port) | ||
452 | { | ||
453 | /* N/A */ | ||
454 | } | ||
455 | |||
456 | |||
457 | /* | ||
458 | * Change the port parameters. | ||
459 | */ | ||
460 | static void tilegx_set_termios(struct uart_port *port, | ||
461 | struct ktermios *termios, struct ktermios *old) | ||
462 | { | ||
463 | int err; | ||
464 | UART_DIVISOR_t divisor; | ||
465 | UART_TYPE_t type; | ||
466 | unsigned int baud; | ||
467 | struct tile_uart_port *tile_uart; | ||
468 | gxio_uart_context_t *context; | ||
469 | |||
470 | tile_uart = container_of(port, struct tile_uart_port, uart); | ||
471 | if (!mutex_trylock(&tile_uart->mutex)) | ||
472 | return; | ||
473 | context = &tile_uart->context; | ||
474 | |||
475 | /* Open the hypervisor device if we haven't already. */ | ||
476 | if (context->fd < 0) { | ||
477 | err = gxio_uart_init(context, port->line); | ||
478 | if (err) { | ||
479 | mutex_unlock(&tile_uart->mutex); | ||
480 | return; | ||
481 | } | ||
482 | } | ||
483 | |||
484 | divisor.word = gxio_uart_read(context, UART_DIVISOR); | ||
485 | type.word = gxio_uart_read(context, UART_TYPE); | ||
486 | |||
487 | /* Divisor. */ | ||
488 | baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16); | ||
489 | divisor.divisor = uart_get_divisor(port, baud); | ||
490 | |||
491 | /* Byte size. */ | ||
492 | if ((termios->c_cflag & CSIZE) == CS7) | ||
493 | type.dbits = UART_TYPE__DBITS_VAL_SEVEN_DBITS; | ||
494 | else | ||
495 | type.dbits = UART_TYPE__DBITS_VAL_EIGHT_DBITS; | ||
496 | |||
497 | /* Parity. */ | ||
498 | if (termios->c_cflag & PARENB) { | ||
499 | /* Mark or Space parity. */ | ||
500 | if (termios->c_cflag & CMSPAR) | ||
501 | if (termios->c_cflag & PARODD) | ||
502 | type.ptype = UART_TYPE__PTYPE_VAL_MARK; | ||
503 | else | ||
504 | type.ptype = UART_TYPE__PTYPE_VAL_SPACE; | ||
505 | else if (termios->c_cflag & PARODD) | ||
506 | type.ptype = UART_TYPE__PTYPE_VAL_ODD; | ||
507 | else | ||
508 | type.ptype = UART_TYPE__PTYPE_VAL_EVEN; | ||
509 | } else | ||
510 | type.ptype = UART_TYPE__PTYPE_VAL_NONE; | ||
511 | |||
512 | /* Stop bits. */ | ||
513 | if (termios->c_cflag & CSTOPB) | ||
514 | type.sbits = UART_TYPE__SBITS_VAL_TWO_SBITS; | ||
515 | else | ||
516 | type.sbits = UART_TYPE__SBITS_VAL_ONE_SBITS; | ||
517 | |||
518 | /* Set the uart paramters. */ | ||
519 | gxio_uart_write(context, UART_DIVISOR, divisor.word); | ||
520 | gxio_uart_write(context, UART_TYPE, type.word); | ||
521 | |||
522 | mutex_unlock(&tile_uart->mutex); | ||
523 | } | ||
524 | |||
525 | |||
526 | /* | ||
527 | * Return string describing the specified port. | ||
528 | */ | ||
529 | static const char *tilegx_type(struct uart_port *port) | ||
530 | { | ||
531 | return port->type == PORT_TILEGX ? DRIVER_NAME_STRING : NULL; | ||
532 | } | ||
533 | |||
534 | |||
535 | /* | ||
536 | * Release the resources being used by 'port'. | ||
537 | */ | ||
538 | static void tilegx_release_port(struct uart_port *port) | ||
539 | { | ||
540 | /* Nothing to release. */ | ||
541 | } | ||
542 | |||
543 | |||
544 | /* | ||
545 | * Request the resources being used by 'port'. | ||
546 | */ | ||
547 | static int tilegx_request_port(struct uart_port *port) | ||
548 | { | ||
549 | /* Always present. */ | ||
550 | return 0; | ||
551 | } | ||
552 | |||
553 | |||
554 | /* | ||
555 | * Configure/autoconfigure the port. | ||
556 | */ | ||
557 | static void tilegx_config_port(struct uart_port *port, int flags) | ||
558 | { | ||
559 | if (flags & UART_CONFIG_TYPE) | ||
560 | port->type = PORT_TILEGX; | ||
561 | } | ||
562 | |||
563 | |||
564 | /* | ||
565 | * Verify the new serial_struct (for TIOCSSERIAL). | ||
566 | */ | ||
567 | static int tilegx_verify_port(struct uart_port *port, | ||
568 | struct serial_struct *ser) | ||
569 | { | ||
570 | if ((ser->type != PORT_UNKNOWN) && (ser->type != PORT_TILEGX)) | ||
571 | return -EINVAL; | ||
572 | |||
573 | return 0; | ||
574 | } | ||
575 | |||
576 | #ifdef CONFIG_CONSOLE_POLL | ||
577 | |||
578 | /* | ||
579 | * Console polling routines for writing and reading from the uart while | ||
580 | * in an interrupt or debug context. | ||
581 | */ | ||
582 | |||
583 | static int tilegx_poll_get_char(struct uart_port *port) | ||
584 | { | ||
585 | UART_FIFO_COUNT_t count; | ||
586 | gxio_uart_context_t *context; | ||
587 | struct tile_uart_port *tile_uart; | ||
588 | |||
589 | tile_uart = container_of(port, struct tile_uart_port, uart); | ||
590 | context = &tile_uart->context; | ||
591 | count.word = gxio_uart_read(context, UART_FIFO_COUNT); | ||
592 | if (count.rfifo_count == 0) | ||
593 | return NO_POLL_CHAR; | ||
594 | return (char)gxio_uart_read(context, UART_RECEIVE_DATA); | ||
595 | } | ||
596 | |||
597 | static void tilegx_poll_put_char(struct uart_port *port, unsigned char c) | ||
598 | { | ||
599 | gxio_uart_context_t *context; | ||
600 | struct tile_uart_port *tile_uart; | ||
601 | |||
602 | tile_uart = container_of(port, struct tile_uart_port, uart); | ||
603 | context = &tile_uart->context; | ||
604 | gxio_uart_write(context, UART_TRANSMIT_DATA, (unsigned long)c); | ||
605 | } | ||
606 | |||
607 | #endif /* CONFIG_CONSOLE_POLL */ | ||
608 | |||
609 | |||
610 | static const struct uart_ops tilegx_ops = { | ||
611 | .tx_empty = tilegx_tx_empty, | ||
612 | .set_mctrl = tilegx_set_mctrl, | ||
613 | .get_mctrl = tilegx_get_mctrl, | ||
614 | .stop_tx = tilegx_stop_tx, | ||
615 | .start_tx = tilegx_start_tx, | ||
616 | .stop_rx = tilegx_stop_rx, | ||
617 | .enable_ms = tilegx_enable_ms, | ||
618 | .break_ctl = tilegx_break_ctl, | ||
619 | .startup = tilegx_startup, | ||
620 | .shutdown = tilegx_shutdown, | ||
621 | .flush_buffer = tilegx_flush_buffer, | ||
622 | .set_termios = tilegx_set_termios, | ||
623 | .type = tilegx_type, | ||
624 | .release_port = tilegx_release_port, | ||
625 | .request_port = tilegx_request_port, | ||
626 | .config_port = tilegx_config_port, | ||
627 | .verify_port = tilegx_verify_port, | ||
628 | #ifdef CONFIG_CONSOLE_POLL | ||
629 | .poll_get_char = tilegx_poll_get_char, | ||
630 | .poll_put_char = tilegx_poll_put_char, | ||
631 | #endif | ||
632 | }; | ||
633 | |||
634 | |||
635 | static void tilegx_init_ports(void) | ||
636 | { | ||
637 | int i; | ||
638 | struct uart_port *port; | ||
639 | |||
640 | for (i = 0; i < TILEGX_UART_NR; i++) { | ||
641 | port = &tile_uart_ports[i].uart; | ||
642 | port->ops = &tilegx_ops; | ||
643 | port->line = i; | ||
644 | port->type = PORT_TILEGX; | ||
645 | port->uartclk = TILEGX_UART_REF_CLK; | ||
646 | port->flags = UPF_BOOT_AUTOCONF; | ||
647 | |||
648 | tile_uart_ports[i].context.fd = -1; | ||
649 | mutex_init(&tile_uart_ports[i].mutex); | ||
650 | } | ||
651 | } | ||
652 | |||
653 | |||
654 | static struct uart_driver tilegx_uart_driver = { | ||
655 | .owner = THIS_MODULE, | ||
656 | .driver_name = DRIVER_NAME_STRING, | ||
657 | .dev_name = TILEGX_UART_NAME, | ||
658 | .major = TILEGX_UART_MAJOR, | ||
659 | .minor = TILEGX_UART_MINOR, | ||
660 | .nr = TILEGX_UART_NR, | ||
661 | }; | ||
662 | |||
663 | |||
664 | static int __init tilegx_init(void) | ||
665 | { | ||
666 | int i; | ||
667 | int ret; | ||
668 | struct tty_driver *tty_drv; | ||
669 | |||
670 | ret = uart_register_driver(&tilegx_uart_driver); | ||
671 | if (ret) | ||
672 | return ret; | ||
673 | tty_drv = tilegx_uart_driver.tty_driver; | ||
674 | tty_drv->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL; | ||
675 | tty_drv->init_termios.c_ispeed = 115200; | ||
676 | tty_drv->init_termios.c_ospeed = 115200; | ||
677 | |||
678 | tilegx_init_ports(); | ||
679 | |||
680 | for (i = 0; i < TILEGX_UART_NR; i++) { | ||
681 | struct uart_port *port = &tile_uart_ports[i].uart; | ||
682 | ret = uart_add_one_port(&tilegx_uart_driver, port); | ||
683 | } | ||
684 | |||
685 | return 0; | ||
686 | } | ||
687 | |||
688 | |||
689 | static void __exit tilegx_exit(void) | ||
690 | { | ||
691 | int i; | ||
692 | struct uart_port *port; | ||
693 | |||
694 | for (i = 0; i < TILEGX_UART_NR; i++) { | ||
695 | port = &tile_uart_ports[i].uart; | ||
696 | uart_remove_one_port(&tilegx_uart_driver, port); | ||
697 | } | ||
698 | |||
699 | uart_unregister_driver(&tilegx_uart_driver); | ||
700 | } | ||
701 | |||
702 | |||
703 | module_init(tilegx_init); | ||
704 | module_exit(tilegx_exit); | ||
705 | |||
706 | MODULE_AUTHOR("Tilera Corporation"); | ||
707 | MODULE_DESCRIPTION("TILEGx serial port driver"); | ||
708 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index e40ebe124ced..b47dba2c1e6f 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h | |||
@@ -235,4 +235,7 @@ | |||
235 | /* ST ASC type numbers */ | 235 | /* ST ASC type numbers */ |
236 | #define PORT_ASC 105 | 236 | #define PORT_ASC 105 |
237 | 237 | ||
238 | /* Tilera TILE-Gx UART */ | ||
239 | #define PORT_TILEGX 106 | ||
240 | |||
238 | #endif /* _UAPILINUX_SERIAL_CORE_H */ | 241 | #endif /* _UAPILINUX_SERIAL_CORE_H */ |
diff --git a/samples/kprobes/kprobe_example.c b/samples/kprobes/kprobe_example.c index ebf5e0c368ea..366db1a9fb65 100644 --- a/samples/kprobes/kprobe_example.c +++ b/samples/kprobes/kprobe_example.c | |||
@@ -37,6 +37,11 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs) | |||
37 | " status = 0x%lx\n", | 37 | " status = 0x%lx\n", |
38 | p->addr, regs->cp0_epc, regs->cp0_status); | 38 | p->addr, regs->cp0_epc, regs->cp0_status); |
39 | #endif | 39 | #endif |
40 | #ifdef CONFIG_TILEGX | ||
41 | printk(KERN_INFO "pre_handler: p->addr = 0x%p, pc = 0x%lx," | ||
42 | " ex1 = 0x%lx\n", | ||
43 | p->addr, regs->pc, regs->ex1); | ||
44 | #endif | ||
40 | 45 | ||
41 | /* A dump_stack() here will give a stack backtrace */ | 46 | /* A dump_stack() here will give a stack backtrace */ |
42 | return 0; | 47 | return 0; |
@@ -58,6 +63,10 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs, | |||
58 | printk(KERN_INFO "post_handler: p->addr = 0x%p, status = 0x%lx\n", | 63 | printk(KERN_INFO "post_handler: p->addr = 0x%p, status = 0x%lx\n", |
59 | p->addr, regs->cp0_status); | 64 | p->addr, regs->cp0_status); |
60 | #endif | 65 | #endif |
66 | #ifdef CONFIG_TILEGX | ||
67 | printk(KERN_INFO "post_handler: p->addr = 0x%p, ex1 = 0x%lx\n", | ||
68 | p->addr, regs->ex1); | ||
69 | #endif | ||
61 | } | 70 | } |
62 | 71 | ||
63 | /* | 72 | /* |
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index 858966ab019c..a674fd5507c1 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl | |||
@@ -364,6 +364,10 @@ if ($arch eq "x86_64") { | |||
364 | } elsif ($arch eq "blackfin") { | 364 | } elsif ($arch eq "blackfin") { |
365 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; | 365 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; |
366 | $mcount_adjust = -4; | 366 | $mcount_adjust = -4; |
367 | } elsif ($arch eq "tilegx") { | ||
368 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s__mcount\$"; | ||
369 | $type = ".quad"; | ||
370 | $alignment = 8; | ||
367 | } else { | 371 | } else { |
368 | die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; | 372 | die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; |
369 | } | 373 | } |