From 07f4e62f1c704f583740e6dd59c223819feb03ec Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Feb 2018 08:37:33 -0800 Subject: selftests: fib_tests: simplify ip commands in a namespace 'ip netns exec testns ip' is more efficiently handled using 'ip -netns'; runs the ip command after switching the namespace and avoids an exec. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 210 +++++++++++++++---------------- 1 file changed, 105 insertions(+), 105 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index a9154eefb2e2..672f263f8f53 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -34,23 +34,23 @@ fib_unreg_unicast_test() netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_err $? - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy0 check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_fail $? ip netns del testns @@ -68,40 +68,40 @@ fib_unreg_multipath_test() netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip link add dummy1 type dummy - ip netns exec testns ip link set dev dummy1 up + ip -netns testns link add dummy1 type dummy + ip -netns testns link set dev dummy1 up - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip address add 192.0.2.1/24 dev dummy1 - ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy1 + ip -netns testns address add 192.0.2.1/24 dev dummy1 + ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 - ip netns exec testns ip route add 203.0.113.0/24 \ + ip -netns testns route add 203.0.113.0/24 \ nexthop via 198.51.100.2 dev dummy0 \ nexthop via 192.0.2.2 dev dummy1 - ip netns exec testns ip -6 route add 2001:db8:3::/64 \ + ip -netns testns -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 - ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null + ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null check_err $? - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy0 check_err $? - ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null + ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null # In IPv6 we do not flush the entire multipath route. check_err $? - ip netns exec testns ip link del dev dummy1 + ip -netns testns link del dev dummy1 ip netns del testns @@ -126,26 +126,26 @@ fib_down_unicast_test() netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_err $? - ip netns exec testns ip link set dev dummy0 down + ip -netns testns link set dev dummy0 down check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_fail $? - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy0 ip netns del testns @@ -161,31 +161,31 @@ fib_down_multipath_test_do() local down_dev=$1 local up_dev=$2 - ip netns exec testns ip route get fibmatch 203.0.113.1 \ + ip -netns testns route get fibmatch 203.0.113.1 \ oif $down_dev &> /dev/null check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 \ + ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ oif $down_dev &> /dev/null check_fail $? - ip netns exec testns ip route get fibmatch 203.0.113.1 \ + ip -netns testns route get fibmatch 203.0.113.1 \ oif $up_dev &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 \ + ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ oif $up_dev &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 203.0.113.1 | \ + ip -netns testns route get fibmatch 203.0.113.1 | \ grep $down_dev | grep -q "dead linkdown" check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 | \ + ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ grep $down_dev | grep -q "dead linkdown" check_err $? - ip netns exec testns ip route get fibmatch 203.0.113.1 | \ + ip -netns testns route get fibmatch 203.0.113.1 | \ grep $up_dev | grep -q "dead linkdown" check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 | \ + ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ grep $up_dev | grep -q "dead linkdown" check_fail $? } @@ -196,52 +196,52 @@ fib_down_multipath_test() netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip link add dummy1 type dummy - ip netns exec testns ip link set dev dummy1 up + ip -netns testns link add dummy1 type dummy + ip -netns testns link set dev dummy1 up - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip address add 192.0.2.1/24 dev dummy1 - ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy1 + ip -netns testns address add 192.0.2.1/24 dev dummy1 + ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 - ip netns exec testns ip route add 203.0.113.0/24 \ + ip -netns testns route add 203.0.113.0/24 \ nexthop via 198.51.100.2 dev dummy0 \ nexthop via 192.0.2.2 dev dummy1 - ip netns exec testns ip -6 route add 2001:db8:3::/64 \ + ip -netns testns -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 - ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null + ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null check_err $? - ip netns exec testns ip link set dev dummy0 down + ip -netns testns link set dev dummy0 down check_err $? fib_down_multipath_test_do "dummy0" "dummy1" - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link set dev dummy0 up check_err $? - ip netns exec testns ip link set dev dummy1 down + ip -netns testns link set dev dummy1 down check_err $? fib_down_multipath_test_do "dummy1" "dummy0" - ip netns exec testns ip link set dev dummy0 down + ip -netns testns link set dev dummy0 down check_err $? - ip netns exec testns ip route get fibmatch 203.0.113.1 &> /dev/null + ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:3::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null check_fail $? - ip netns exec testns ip link del dev dummy1 - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy1 + ip -netns testns link del dev dummy0 ip netns del testns @@ -267,56 +267,56 @@ fib_carrier_local_test() # Local routes should not be affected when carrier changes. netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip link set dev dummy0 carrier on + ip -netns testns link set dev dummy0 carrier on - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 198.51.100.1 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.1 | \ + ip -netns testns route get fibmatch 198.51.100.1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 | \ + ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip link set dev dummy0 carrier off + ip -netns testns link set dev dummy0 carrier off - ip netns exec testns ip route get fibmatch 198.51.100.1 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.1 | \ + ip -netns testns route get fibmatch 198.51.100.1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::1 | \ + ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip address add 192.0.2.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy0 + ip -netns testns address add 192.0.2.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 192.0.2.1 &> /dev/null + ip -netns testns route get fibmatch 192.0.2.1 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:2::1 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:2::1 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 192.0.2.1 | \ + ip -netns testns route get fibmatch 192.0.2.1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:2::1 | \ + ip -netns testns -6 route get fibmatch 2001:db8:2::1 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy0 ip netns del testns @@ -333,56 +333,56 @@ fib_carrier_unicast_test() netns_create "testns" - ip netns exec testns ip link add dummy0 type dummy - ip netns exec testns ip link set dev dummy0 up + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up - ip netns exec testns ip link set dev dummy0 carrier on + ip -netns testns link set dev dummy0 carrier on - ip netns exec testns ip address add 198.51.100.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:1::1/64 dev dummy0 + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.2 | \ + ip -netns testns route get fibmatch 198.51.100.2 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 | \ + ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" check_fail $? - ip netns exec testns ip link set dev dummy0 carrier off + ip -netns testns link set dev dummy0 carrier off - ip netns exec testns ip route get fibmatch 198.51.100.2 &> /dev/null + ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 198.51.100.2 | \ + ip -netns testns route get fibmatch 198.51.100.2 | \ grep -q "linkdown" check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:1::2 | \ + ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" check_err $? - ip netns exec testns ip address add 192.0.2.1/24 dev dummy0 - ip netns exec testns ip -6 address add 2001:db8:2::1/64 dev dummy0 + ip -netns testns address add 192.0.2.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 - ip netns exec testns ip route get fibmatch 192.0.2.2 &> /dev/null + ip -netns testns route get fibmatch 192.0.2.2 &> /dev/null check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:2::2 &> /dev/null + ip -netns testns -6 route get fibmatch 2001:db8:2::2 &> /dev/null check_err $? - ip netns exec testns ip route get fibmatch 192.0.2.2 | \ + ip -netns testns route get fibmatch 192.0.2.2 | \ grep -q "linkdown" check_err $? - ip netns exec testns ip -6 route get fibmatch 2001:db8:2::2 | \ + ip -netns testns -6 route get fibmatch 2001:db8:2::2 | \ grep -q "linkdown" check_err $? - ip netns exec testns ip link del dev dummy0 + ip -netns testns link del dev dummy0 ip netns del testns -- cgit v1.3-14-g43fede From 1056691b26809e838da67bc2a61761017d20cfda Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Feb 2018 08:37:34 -0800 Subject: selftests: fib_tests: Make test results more verbose fib_tests.sh is failing in a VM: $ fib_tests.sh Running netdev unregister tests PASS: unicast route test PASS: multipath route test Running netdev down tests PASS: unicast route test PASS: multipath route test Running netdev carrier change tests PASS: local route carrier test FAIL: unicast route carrier test The last test corresponds to fib_carrier_unicast_test which 12 places that could be failing. Be more verbose in the output so a failure is easier to track down and separate test setup failures with set -e and set +e pairs. With the verbose logging it is easier to see which checks are failing: $fib_tests.sh Single path route carrier test .... Carrier down IPv4 fibmatch [ OK ] IPv6 fibmatch [ OK ] IPv4 linkdown flag set [FAIL] IPv6 linkdown flag set [FAIL] Second address added with carrier down IPv4 fibmatch [ OK ] IPv6 fibmatch [ OK ] IPv4 linkdown flag set [FAIL] IPv6 linkdown flag set [ OK ] Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 248 +++++++++++++++++-------------- 1 file changed, 135 insertions(+), 113 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index 672f263f8f53..d4e0b5cb4355 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -6,17 +6,25 @@ ret=0 -check_err() -{ - if [ $ret -eq 0 ]; then - ret=$1 - fi -} +PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} -check_fail() +log_test() { - if [ $1 -eq 0 ]; then + local rc=$1 + local expected=$2 + local msg="$3" + + if [ ${rc} -eq ${expected} ]; then + printf " %-60s [ OK ]\n" "${msg}" + else ret=1 + printf " %-60s [FAIL]\n" "${msg}" + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi fi } @@ -30,42 +38,44 @@ netns_create() fib_unreg_unicast_test() { - ret=0 + echo + echo "Single path route test" + set -e netns_create "testns" ip -netns testns link add dummy0 type dummy ip -netns testns link set dev dummy0 up - ip -netns testns address add 198.51.100.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + set +e + echo " Start point" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" + set -e ip -netns testns link del dev dummy0 - check_err $? + set +e + echo " Nexthop device deleted" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_fail $? + log_test $? 2 "IPv4 fibmatch - no route" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_fail $? + log_test $? 2 "IPv6 fibmatch - no route" ip netns del testns - - if [ $ret -ne 0 ]; then - echo "FAIL: unicast route test" - return 1 - fi - echo "PASS: unicast route test" } fib_unreg_multipath_test() { - ret=0 + echo + echo "Multipath route test" + + set -e netns_create "testns" ip -netns testns link add dummy0 type dummy @@ -86,44 +96,49 @@ fib_unreg_multipath_test() ip -netns testns -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 + set +e + echo " Start point" ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" + set -e ip -netns testns link del dev dummy0 - check_err $? + set +e + echo " One nexthop device deleted" ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null - check_fail $? + log_test $? 2 "IPv4 - multipath route removed on delete" + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null # In IPv6 we do not flush the entire multipath route. - check_err $? + log_test $? 0 "IPv6 - multipath down to single path" + set -e ip -netns testns link del dev dummy1 + set +e - ip netns del testns + echo " Second nexthop device deleted" + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + log_test $? 2 "IPv6 - no route" - if [ $ret -ne 0 ]; then - echo "FAIL: multipath route test" - return 1 - fi - echo "PASS: multipath route test" + ip netns del testns } fib_unreg_test() { - echo "Running netdev unregister tests" - fib_unreg_unicast_test fib_unreg_multipath_test } fib_down_unicast_test() { - ret=0 + echo + echo "Single path, admin down" + set -e netns_create "testns" ip -netns testns link add dummy0 type dummy @@ -131,29 +146,27 @@ fib_down_unicast_test() ip -netns testns address add 198.51.100.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + set +e + echo " Start point" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" + set -e ip -netns testns link set dev dummy0 down - check_err $? + set +e + echo " Route deleted on down" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_fail $? + log_test $? 2 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_fail $? + log_test $? 2 "IPv6 fibmatch" ip -netns testns link del dev dummy0 ip netns del testns - - if [ $ret -ne 0 ]; then - echo "FAIL: unicast route test" - return 1 - fi - echo "PASS: unicast route test" } fib_down_multipath_test_do() @@ -163,37 +176,39 @@ fib_down_multipath_test_do() ip -netns testns route get fibmatch 203.0.113.1 \ oif $down_dev &> /dev/null - check_fail $? + log_test $? 2 "IPv4 fibmatch on down device" ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ oif $down_dev &> /dev/null - check_fail $? + log_test $? 2 "IPv6 fibmatch on down device" ip -netns testns route get fibmatch 203.0.113.1 \ oif $up_dev &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch on up device" ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ oif $up_dev &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch on up device" ip -netns testns route get fibmatch 203.0.113.1 | \ grep $down_dev | grep -q "dead linkdown" - check_err $? + log_test $? 0 "IPv4 flags on down device" ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ grep $down_dev | grep -q "dead linkdown" - check_err $? + log_test $? 0 "IPv6 flags on down device" ip -netns testns route get fibmatch 203.0.113.1 | \ grep $up_dev | grep -q "dead linkdown" - check_fail $? + log_test $? 1 "IPv4 flags on up device" ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ grep $up_dev | grep -q "dead linkdown" - check_fail $? + log_test $? 1 "IPv6 flags on up device" } fib_down_multipath_test() { - ret=0 + echo + echo "Admin down multipath" + set -e netns_create "testns" ip -netns testns link add dummy0 type dummy @@ -214,57 +229,58 @@ fib_down_multipath_test() ip -netns testns -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 + set +e + echo " Verify start point" ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" + ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" + set -e ip -netns testns link set dev dummy0 down - check_err $? + set +e + echo " One device down, one up" fib_down_multipath_test_do "dummy0" "dummy1" + set -e ip -netns testns link set dev dummy0 up - check_err $? ip -netns testns link set dev dummy1 down - check_err $? + set +e + echo " Other device down and up" fib_down_multipath_test_do "dummy1" "dummy0" + set -e ip -netns testns link set dev dummy0 down - check_err $? + set +e + echo " Both devices down" ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null - check_fail $? + log_test $? 2 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null - check_fail $? + log_test $? 2 "IPv6 fibmatch" ip -netns testns link del dev dummy1 ip -netns testns link del dev dummy0 - ip netns del testns - - if [ $ret -ne 0 ]; then - echo "FAIL: multipath route test" - return 1 - fi - echo "PASS: multipath route test" } fib_down_test() { - echo "Running netdev down tests" - fib_down_unicast_test fib_down_multipath_test } +# Local routes should not be affected when carrier changes. fib_carrier_local_test() { - ret=0 + echo + echo "Local carrier tests - single path" - # Local routes should not be affected when carrier changes. + set -e netns_create "testns" ip -netns testns link add dummy0 type dummy @@ -274,65 +290,71 @@ fib_carrier_local_test() ip -netns testns address add 198.51.100.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + set +e + echo " Start point" ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 198.51.100.1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv4 - no linkdown flag" ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv6 - no linkdown flag" + set -e ip -netns testns link set dev dummy0 carrier off + set +e + echo " Carrier off on nexthop" ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 198.51.100.1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv4 - linkdown flag set" ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv6 - linkdown flag set" + set -e ip -netns testns address add 192.0.2.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 + set +e + echo " Route to local address with carrier down" ip -netns testns route get fibmatch 192.0.2.1 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:2::1 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 192.0.2.1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv4 linkdown flag set" ip -netns testns -6 route get fibmatch 2001:db8:2::1 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv6 linkdown flag set" ip -netns testns link del dev dummy0 ip netns del testns - - if [ $ret -ne 0 ]; then - echo "FAIL: local route carrier test" - return 1 - fi - echo "PASS: local route carrier test" } fib_carrier_unicast_test() { ret=0 + echo + echo "Single path route carrier test" + netns_create "testns" + set -e ip -netns testns link add dummy0 type dummy ip -netns testns link set dev dummy0 up @@ -340,63 +362,63 @@ fib_carrier_unicast_test() ip -netns testns address add 198.51.100.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + set +e + echo " Start point" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 198.51.100.2 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv4 no linkdown flag" ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" - check_fail $? + log_test $? 1 "IPv6 no linkdown flag" + set -e ip -netns testns link set dev dummy0 carrier off + set +e + echo " Carrier down" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 198.51.100.2 | \ grep -q "linkdown" - check_err $? + log_test $? 0 "IPv4 linkdown flag set" ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" - check_err $? + log_test $? 0 "IPv6 linkdown flag set" + set -e ip -netns testns address add 192.0.2.1/24 dev dummy0 ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 + set +e + echo " Second address added with carrier down" ip -netns testns route get fibmatch 192.0.2.2 &> /dev/null - check_err $? + log_test $? 0 "IPv4 fibmatch" ip -netns testns -6 route get fibmatch 2001:db8:2::2 &> /dev/null - check_err $? + log_test $? 0 "IPv6 fibmatch" ip -netns testns route get fibmatch 192.0.2.2 | \ grep -q "linkdown" - check_err $? + log_test $? 0 "IPv4 linkdown flag set" ip -netns testns -6 route get fibmatch 2001:db8:2::2 | \ grep -q "linkdown" - check_err $? + log_test $? 0 "IPv6 linkdown flag set" ip -netns testns link del dev dummy0 ip netns del testns - - if [ $ret -ne 0 ]; then - echo "FAIL: unicast route carrier test" - return 1 - fi - echo "PASS: unicast route carrier test" } fib_carrier_test() { - echo "Running netdev carrier change tests" - fib_carrier_local_test fib_carrier_unicast_test } -- cgit v1.3-14-g43fede From ee395a5e722c8c7e85641c3017de8f64209ff04f Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Feb 2018 08:37:35 -0800 Subject: selftests: fib_tests: Move admin of dummy0 to helpers Move setup and teardown of testns and dummy0 to helpers. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 100 +++++++++++-------------------- 1 file changed, 34 insertions(+), 66 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index d4e0b5cb4355..e113cfd659fc 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -28,12 +28,24 @@ log_test() fi } -netns_create() +setup() { - local testns=$1 + set -e + ip netns add testns + ip -netns testns link set dev lo up + + ip -netns testns link add dummy0 type dummy + ip -netns testns link set dev dummy0 up + ip -netns testns address add 198.51.100.1/24 dev dummy0 + ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + set +e + +} - ip netns add $testns - ip netns exec $testns ip link set dev lo up +cleanup() +{ + ip -netns testns link del dev dummy0 &> /dev/null + ip netns del testns } fib_unreg_unicast_test() @@ -41,14 +53,7 @@ fib_unreg_unicast_test() echo echo "Single path route test" - set -e - netns_create "testns" - - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - set +e + setup echo " Start point" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null @@ -66,7 +71,7 @@ fib_unreg_unicast_test() ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 2 "IPv6 fibmatch - no route" - ip netns del testns + cleanup } fib_unreg_multipath_test() @@ -75,18 +80,11 @@ fib_unreg_multipath_test() echo echo "Multipath route test" - set -e - netns_create "testns" - - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up + setup + set -e ip -netns testns link add dummy1 type dummy ip -netns testns link set dev dummy1 up - - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip -netns testns address add 192.0.2.1/24 dev dummy1 ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 @@ -124,7 +122,7 @@ fib_unreg_multipath_test() ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null log_test $? 2 "IPv6 - no route" - ip netns del testns + cleanup } fib_unreg_test() @@ -138,15 +136,7 @@ fib_down_unicast_test() echo echo "Single path, admin down" - set -e - netns_create "testns" - - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up - - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - set +e + setup echo " Start point" ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null @@ -164,9 +154,7 @@ fib_down_unicast_test() ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 2 "IPv6 fibmatch" - ip -netns testns link del dev dummy0 - - ip netns del testns + cleanup } fib_down_multipath_test_do() @@ -208,18 +196,12 @@ fib_down_multipath_test() echo echo "Admin down multipath" - set -e - netns_create "testns" - - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up + setup + set -e ip -netns testns link add dummy1 type dummy ip -netns testns link set dev dummy1 up - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 - ip -netns testns address add 192.0.2.1/24 dev dummy1 ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 @@ -264,8 +246,7 @@ fib_down_multipath_test() log_test $? 2 "IPv6 fibmatch" ip -netns testns link del dev dummy1 - ip -netns testns link del dev dummy0 - ip netns del testns + cleanup } fib_down_test() @@ -280,16 +261,10 @@ fib_carrier_local_test() echo echo "Local carrier tests - single path" - set -e - netns_create "testns" - - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up + setup + set -e ip -netns testns link set dev dummy0 carrier on - - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 set +e echo " Start point" @@ -340,9 +315,7 @@ fib_carrier_local_test() grep -q "linkdown" log_test $? 1 "IPv6 linkdown flag set" - ip -netns testns link del dev dummy0 - - ip netns del testns + cleanup } fib_carrier_unicast_test() @@ -352,16 +325,10 @@ fib_carrier_unicast_test() echo echo "Single path route carrier test" - netns_create "testns" + setup set -e - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up - ip -netns testns link set dev dummy0 carrier on - - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 set +e echo " Start point" @@ -412,9 +379,7 @@ fib_carrier_unicast_test() grep -q "linkdown" log_test $? 0 "IPv6 linkdown flag set" - ip -netns testns link del dev dummy0 - - ip netns del testns + cleanup } fib_carrier_test() @@ -446,6 +411,9 @@ if [ $? -ne 0 ]; then exit 0 fi +# start clean +cleanup &> /dev/null + fib_test exit $ret -- cgit v1.3-14-g43fede From e2ba732a1681d907a6dffbaf9802aebcac233099 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Feb 2018 08:37:36 -0800 Subject: selftests: fib_tests: sleep after changing carrier sleep for a second after setting carrier down to allow linkwatch to propagate the change to the routing stack via netdev_state_change. As it stands there is a race setting carrier down on the dummy device and then checking the linkdown flag in the routes. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index e113cfd659fc..b617985ecdc1 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -282,6 +282,7 @@ fib_carrier_local_test() set -e ip -netns testns link set dev dummy0 carrier off + sleep 1 set +e echo " Carrier off on nexthop" -- cgit v1.3-14-g43fede From 153e1b84f477f716bc3f81e6cfae1a3d941fc7ec Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Feb 2018 08:44:06 -0800 Subject: selftests: Add FIB onlink tests Add test cases verifying FIB onlink commands work as expected in various conditions - IPv4, IPv6, main table, and VRF. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib-onlink-tests.sh | 375 ++++++++++++++++++++++++ 1 file changed, 375 insertions(+) create mode 100755 tools/testing/selftests/net/fib-onlink-tests.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib-onlink-tests.sh b/tools/testing/selftests/net/fib-onlink-tests.sh new file mode 100755 index 000000000000..06b1d7cc12cc --- /dev/null +++ b/tools/testing/selftests/net/fib-onlink-tests.sh @@ -0,0 +1,375 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# IPv4 and IPv6 onlink tests + +PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} + +# Network interfaces +# - odd in current namespace; even in peer ns +declare -A NETIFS +# default VRF +NETIFS[p1]=veth1 +NETIFS[p2]=veth2 +NETIFS[p3]=veth3 +NETIFS[p4]=veth4 +# VRF +NETIFS[p5]=veth5 +NETIFS[p6]=veth6 +NETIFS[p7]=veth7 +NETIFS[p8]=veth8 + +# /24 network +declare -A V4ADDRS +V4ADDRS[p1]=169.254.1.1 +V4ADDRS[p2]=169.254.1.2 +V4ADDRS[p3]=169.254.3.1 +V4ADDRS[p4]=169.254.3.2 +V4ADDRS[p5]=169.254.5.1 +V4ADDRS[p6]=169.254.5.2 +V4ADDRS[p7]=169.254.7.1 +V4ADDRS[p8]=169.254.7.2 + +# /64 network +declare -A V6ADDRS +V6ADDRS[p1]=2001:db8:101::1 +V6ADDRS[p2]=2001:db8:101::2 +V6ADDRS[p3]=2001:db8:301::1 +V6ADDRS[p4]=2001:db8:301::2 +V6ADDRS[p5]=2001:db8:501::1 +V6ADDRS[p6]=2001:db8:501::2 +V6ADDRS[p7]=2001:db8:701::1 +V6ADDRS[p8]=2001:db8:701::2 + +# Test networks: +# [1] = default table +# [2] = VRF +# +# /32 host routes +declare -A TEST_NET4 +TEST_NET4[1]=169.254.101 +TEST_NET4[2]=169.254.102 +# /128 host routes +declare -A TEST_NET6 +TEST_NET6[1]=2001:db8:101 +TEST_NET6[2]=2001:db8:102 + +# connected gateway +CONGW[1]=169.254.1.254 +CONGW[2]=169.254.5.254 + +# recursive gateway +RECGW4[1]=169.254.11.254 +RECGW4[2]=169.254.12.254 +RECGW6[1]=2001:db8:11::64 +RECGW6[2]=2001:db8:12::64 + +# for v4 mapped to v6 +declare -A TEST_NET4IN6IN6 +TEST_NET4IN6[1]=10.1.1.254 +TEST_NET4IN6[2]=10.2.1.254 + +# mcast address +MCAST6=ff02::1 + + +PEER_NS=bart +PEER_CMD="ip netns exec ${PEER_NS}" +VRF=lisa +VRF_TABLE=1101 +PBR_TABLE=101 + +################################################################################ +# utilities + +log_test() +{ + local rc=$1 + local expected=$2 + local msg="$3" + + if [ ${rc} -eq ${expected} ]; then + nsuccess=$((nsuccess+1)) + printf "\n TEST: %-50s [ OK ]\n" "${msg}" + else + nfail=$((nfail+1)) + printf "\n TEST: %-50s [FAIL]\n" "${msg}" + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo + echo "hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + fi +} + +log_section() +{ + echo + echo "######################################################################" + echo "TEST SECTION: $*" + echo "######################################################################" +} + +log_subsection() +{ + echo + echo "#########################################" + echo "TEST SUBSECTION: $*" +} + +run_cmd() +{ + echo + echo "COMMAND: $*" + eval $* +} + +get_linklocal() +{ + local dev=$1 + local pfx + local addr + + addr=$(${pfx} ip -6 -br addr show dev ${dev} | \ + awk '{ + for (i = 3; i <= NF; ++i) { + if ($i ~ /^fe80/) + print $i + } + }' + ) + addr=${addr/\/*} + + [ -z "$addr" ] && return 1 + + echo $addr + + return 0 +} + +################################################################################ +# + +setup() +{ + echo + echo "########################################" + echo "Configuring interfaces" + + set -e + + # create namespace + ip netns add ${PEER_NS} + ip -netns ${PEER_NS} li set lo up + + # add vrf table + ip li add ${VRF} type vrf table ${VRF_TABLE} + ip li set ${VRF} up + ip ro add table ${VRF_TABLE} unreachable default + ip -6 ro add table ${VRF_TABLE} unreachable default + + # create test interfaces + ip li add ${NETIFS[p1]} type veth peer name ${NETIFS[p2]} + ip li add ${NETIFS[p3]} type veth peer name ${NETIFS[p4]} + ip li add ${NETIFS[p5]} type veth peer name ${NETIFS[p6]} + ip li add ${NETIFS[p7]} type veth peer name ${NETIFS[p8]} + + # enslave vrf interfaces + for n in 5 7; do + ip li set ${NETIFS[p${n}]} vrf ${VRF} + done + + # add addresses + for n in 1 3 5 7; do + ip li set ${NETIFS[p${n}]} up + ip addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} + ip addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} + done + + # move peer interfaces to namespace and add addresses + for n in 2 4 6 8; do + ip li set ${NETIFS[p${n}]} netns ${PEER_NS} up + ip -netns ${PEER_NS} addr add ${V4ADDRS[p${n}]}/24 dev ${NETIFS[p${n}]} + ip -netns ${PEER_NS} addr add ${V6ADDRS[p${n}]}/64 dev ${NETIFS[p${n}]} + done + + set +e + + # let DAD complete - assume default of 1 probe + sleep 1 +} + +cleanup() +{ + # make sure we start from a clean slate + ip netns del ${PEER_NS} 2>/dev/null + for n in 1 3 5 7; do + ip link del ${NETIFS[p${n}]} 2>/dev/null + done + ip link del ${VRF} 2>/dev/null + ip ro flush table ${VRF_TABLE} + ip -6 ro flush table ${VRF_TABLE} +} + +################################################################################ +# IPv4 tests +# + +run_ip() +{ + local table="$1" + local prefix="$2" + local gw="$3" + local dev="$4" + local exp_rc="$5" + local desc="$6" + + # dev arg may be empty + [ -n "${dev}" ] && dev="dev ${dev}" + + run_cmd ip ro add table "${table}" "${prefix}"/32 via "${gw}" "${dev}" onlink + log_test $? ${exp_rc} "${desc}" +} + +valid_onlink_ipv4() +{ + # - unicast connected, unicast recursive + # + log_subsection "default VRF - main table" + + run_ip 254 ${TEST_NET4[1]}.1 ${CONGW[1]} ${NETIFS[p1]} 0 "unicast connected" + run_ip 254 ${TEST_NET4[1]}.2 ${RECGW4[1]} ${NETIFS[p1]} 0 "unicast recursive" + + log_subsection "VRF ${VRF}" + + run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[2]} ${NETIFS[p5]} 0 "unicast connected" + run_ip ${VRF_TABLE} ${TEST_NET4[2]}.2 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" + + log_subsection "VRF device, PBR table" + + run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[2]} ${NETIFS[p5]} 0 "unicast connected" + run_ip ${PBR_TABLE} ${TEST_NET4[2]}.4 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" +} + +invalid_onlink_ipv4() +{ + run_ip 254 ${TEST_NET4[1]}.11 ${V4ADDRS[p1]} ${NETIFS[p1]} 2 \ + "Invalid gw - local unicast address" + + run_ip ${VRF_TABLE} ${TEST_NET4[2]}.11 ${V4ADDRS[p5]} ${NETIFS[p5]} 2 \ + "Invalid gw - local unicast address, VRF" + + run_ip 254 ${TEST_NET4[1]}.101 ${V4ADDRS[p1]} "" 2 "No nexthop device given" + + run_ip 254 ${TEST_NET4[1]}.102 ${V4ADDRS[p3]} ${NETIFS[p1]} 2 \ + "Gateway resolves to wrong nexthop device" + + run_ip ${VRF_TABLE} ${TEST_NET4[2]}.103 ${V4ADDRS[p7]} ${NETIFS[p5]} 2 \ + "Gateway resolves to wrong nexthop device - VRF" +} + +################################################################################ +# IPv6 tests +# + +run_ip6() +{ + local table="$1" + local prefix="$2" + local gw="$3" + local dev="$4" + local exp_rc="$5" + local desc="$6" + + # dev arg may be empty + [ -n "${dev}" ] && dev="dev ${dev}" + + run_cmd ip -6 ro add table "${table}" "${prefix}"/128 via "${gw}" "${dev}" onlink + log_test $? ${exp_rc} "${desc}" +} + +valid_onlink_ipv6() +{ + # - unicast connected, unicast recursive, v4-mapped + # + log_subsection "default VRF - main table" + + run_ip6 254 ${TEST_NET6[1]}::1 ${V6ADDRS[p1]/::*}::64 ${NETIFS[p1]} 0 "unicast connected" + run_ip6 254 ${TEST_NET6[1]}::2 ${RECGW6[1]} ${NETIFS[p1]} 0 "unicast recursive" + run_ip6 254 ${TEST_NET6[1]}::3 ::ffff:${TEST_NET4IN6[1]} ${NETIFS[p1]} 0 "v4-mapped" + + log_subsection "VRF ${VRF}" + + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::1 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected" + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::2 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive" + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::3 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped" + + log_subsection "VRF device, PBR table" + + run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::4 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected" + run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::5 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive" + run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::6 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped" +} + +invalid_onlink_ipv6() +{ + local lladdr + + lladdr=$(get_linklocal ${NETIFS[p1]}) || return 1 + + run_ip6 254 ${TEST_NET6[1]}::11 ${V6ADDRS[p1]} ${NETIFS[p1]} 2 \ + "Invalid gw - local unicast address" + run_ip6 254 ${TEST_NET6[1]}::12 ${lladdr} ${NETIFS[p1]} 2 \ + "Invalid gw - local linklocal address" + run_ip6 254 ${TEST_NET6[1]}::12 ${MCAST6} ${NETIFS[p1]} 2 \ + "Invalid gw - multicast address" + + lladdr=$(get_linklocal ${NETIFS[p5]}) || return 1 + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::11 ${V6ADDRS[p5]} ${NETIFS[p5]} 2 \ + "Invalid gw - local unicast address, VRF" + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${lladdr} ${NETIFS[p5]} 2 \ + "Invalid gw - local linklocal address, VRF" + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::12 ${MCAST6} ${NETIFS[p5]} 2 \ + "Invalid gw - multicast address, VRF" + + run_ip6 254 ${TEST_NET6[1]}::101 ${V6ADDRS[p1]} "" 2 \ + "No nexthop device given" + + # default VRF validation is done against LOCAL table + # run_ip6 254 ${TEST_NET6[1]}::102 ${V6ADDRS[p3]/::[0-9]/::64} ${NETIFS[p1]} 2 \ + # "Gateway resolves to wrong nexthop device" + + run_ip6 ${VRF_TABLE} ${TEST_NET6[2]}::103 ${V6ADDRS[p7]/::[0-9]/::64} ${NETIFS[p5]} 2 \ + "Gateway resolves to wrong nexthop device - VRF" +} + +run_onlink_tests() +{ + log_section "IPv4 onlink" + log_subsection "Valid onlink commands" + valid_onlink_ipv4 + log_subsection "Invalid onlink commands" + invalid_onlink_ipv4 + + log_section "IPv6 onlink" + log_subsection "Valid onlink commands" + valid_onlink_ipv6 + invalid_onlink_ipv6 +} + +################################################################################ +# main + +nsuccess=0 +nfail=0 + +cleanup +setup +run_onlink_tests +cleanup + +if [ "$TESTS" != "none" ]; then + printf "\nTests passed: %3d\n" ${nsuccess} + printf "Tests failed: %3d\n" ${nfail} +fi -- cgit v1.3-14-g43fede From 41757dcb0c3d8446c549e55163c9fd9561fcf599 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Tue, 13 Feb 2018 14:19:15 +0100 Subject: selftests/bpf: fix Makefile for cgroup_helpers.c The current selftests Makefile construct result in cgroup_helpers.c gets compiled together with all the TEST_GEN_PROGS. And it also result in invoking the libbpf Makefile two times (tools/lib/bpf). These issues were introduced in commit 9d1f15941967 ("bpf: move cgroup_helpers from samples/bpf/ to tools/testing/selftesting/bpf/"). The only test program that requires the cgroup helpers is 'test_dev_cgroup'. Thus, create a make target $(OUTPUT)/test_dev_cgroup that extend[1] the 'prerequisite' for the 'stem' %-style pattern in ../lib.mk, for this particular test program. Reviewers notice the make-rules in tools/testing/selftests/lib.mk differ from the normal kernel kbuild rules, and it is practical to use 'make -p' to follow how these 'Implicit/static pattern stem' gets expanded. [1] https://www.gnu.org/software/make/manual/html_node/Static-Usage.html Fixes: 9d1f15941967 ("bpf: move cgroup_helpers from samples/bpf/ to tools/testing/selftesting/bpf/") Signed-off-by: Jesper Dangaard Brouer Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 5c43c187f27c..8567a858b789 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -35,12 +35,14 @@ TEST_GEN_PROGS_EXTENDED = test_libbpf_open include ../lib.mk -BPFOBJ := $(OUTPUT)/libbpf.a cgroup_helpers.c +BPFOBJ := $(OUTPUT)/libbpf.a $(TEST_GEN_PROGS): $(BPFOBJ) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a +$(OUTPUT)/test_dev_cgroup: cgroup_helpers.c + .PHONY: force # force a rebuild of BPFOBJ when its dependencies are updated -- cgit v1.3-14-g43fede From 615a9474985799c8b48645b8e95a9b9f0691f56a Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Tue, 13 Feb 2018 10:35:05 -0800 Subject: tools/bpf: adjust rlimit RLIMIT_MEMLOCK for test_tcpbpf_user The default rlimit RLIMIT_MEMLOCK is 64KB. In certain cases, e.g. in a test machine mimicking our production system, this test may fail due to unable to charge the required memory for map creation: # ./test_tcpbpf_user libbpf: failed to create map (name: 'global_map'): Operation not permitted libbpf: failed to load object 'test_tcpbpf_kern.o' FAILED: load_bpf_file failed for: test_tcpbpf_kern.o Changing the default rlimit RLIMIT_MEMLOCK to unlimited makes the test always pass. Signed-off-by: Yonghong Song Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_tcpbpf_user.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c index 95a370f3d378..5d73db416460 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_user.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include #include #include @@ -42,6 +44,7 @@ static int bpf_find_map(const char *test, struct bpf_object *obj, int main(int argc, char **argv) { + struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; const char *file = "test_tcpbpf_kern.o"; struct tcpbpf_globals g = {0}; int cg_fd, prog_fd, map_fd; @@ -54,6 +57,9 @@ int main(int argc, char **argv) int pid; int rv; + if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0) + perror("Unable to lift memlock rlimit"); + if (argc > 1 && strcmp(argv[1], "-d") == 0) debug_flag = true; -- cgit v1.3-14-g43fede From 95f87a9706d0a55ff02a652bc8f1b3f7d51bf5eb Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 14 Feb 2018 13:50:34 -0800 Subject: selftests/bpf: Print unexpected output on fail This makes it easier to debug off-hand when the error message isn't exactly as expected. Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index c0f16e93f9bd..6cf9bd6f08b7 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -11291,7 +11291,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv, goto fail_log; } if (!strstr(bpf_vlog, expected_err) && !reject_from_alignment) { - printf("FAIL\nUnexpected error message!\n"); + printf("FAIL\nUnexpected error message!\n\tEXP: %s\n\tRES: %s\n", + expected_err, bpf_vlog); goto fail_log; } } -- cgit v1.3-14-g43fede From d0a0e4956f6c20754ef67db6dfb9746e85ecdcb5 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 14 Feb 2018 13:50:35 -0800 Subject: selftests/bpf: Count tests skipped by unpriv When priviliged tests are skipped due to user rights, count the number of skipped tests so it's more obvious that the test did not check everything. Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 6cf9bd6f08b7..7ab02526c403 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -11378,7 +11378,7 @@ out: static int do_test(bool unpriv, unsigned int from, unsigned int to) { - int i, passes = 0, errors = 0; + int i, passes = 0, errors = 0, skips = 0; for (i = from; i < to; i++) { struct bpf_test *test = &tests[i]; @@ -11395,13 +11395,17 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) set_admin(true); } - if (!unpriv) { + if (unpriv) { + printf("#%d/p %s SKIP\n", i, test->descr); + skips++; + } else { printf("#%d/p %s ", i, test->descr); do_test_single(test, false, &passes, &errors); } } - printf("Summary: %d PASSED, %d FAILED\n", passes, errors); + printf("Summary: %d PASSED, %d SKIPPED, %d FAILED\n", passes, + skips, errors); return errors ? EXIT_FAILURE : EXIT_SUCCESS; } -- cgit v1.3-14-g43fede From 0a67487403683852e05fea97208ad7b0ed820115 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 14 Feb 2018 13:50:36 -0800 Subject: selftests/bpf: Only run tests if !bpf_disabled The "kernel.unprivileged_bpf_disabled" sysctl, if enabled, causes all unprivileged tests to fail because it permanently disables unprivileged BPF access for the currently running kernel. Skip the relevant tests if the user attempts to run the testsuite with this sysctl enabled. Signed-off-by: Joe Stringer Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 7ab02526c403..2971ba2829ac 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -57,6 +57,9 @@ #define F_NEEDS_EFFICIENT_UNALIGNED_ACCESS (1 << 0) #define F_LOAD_WITH_STRICT_ALIGNMENT (1 << 1) +#define UNPRIV_SYSCTL "kernel/unprivileged_bpf_disabled" +static bool unpriv_disabled = false; + struct bpf_test { const char *descr; struct bpf_insn insns[MAX_INSNS]; @@ -11376,6 +11379,17 @@ out: return ret; } +static void get_unpriv_disabled() +{ + char buf[2]; + FILE *fd; + + fd = fopen("/proc/sys/"UNPRIV_SYSCTL, "r"); + if (fgets(buf, 2, fd) == buf && atoi(buf)) + unpriv_disabled = true; + fclose(fd); +} + static int do_test(bool unpriv, unsigned int from, unsigned int to) { int i, passes = 0, errors = 0, skips = 0; @@ -11386,7 +11400,10 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) /* Program types that are not supported by non-root we * skip right away. */ - if (!test->prog_type) { + if (!test->prog_type && unpriv_disabled) { + printf("#%d/u %s SKIP\n", i, test->descr); + skips++; + } else if (!test->prog_type) { if (!unpriv) set_admin(false); printf("#%d/u %s ", i, test->descr); @@ -11433,6 +11450,13 @@ int main(int argc, char **argv) } } + get_unpriv_disabled(); + if (unpriv && unpriv_disabled) { + printf("Cannot run as unprivileged user with sysctl %s.\n", + UNPRIV_SYSCTL); + return EXIT_FAILURE; + } + setrlimit(RLIMIT_MEMLOCK, unpriv ? &rlim : &rinf); return do_test(unpriv, from, to); } -- cgit v1.3-14-g43fede From f87c7f646c6f704b29504d63c4ab965584c4aacb Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:19 -0500 Subject: tools: tc-testing: Command line parms Separate the functionality of the command line parameters into "selection" parameters, "action" parameters and other parameters. "Selection" parameters are for choosing which tests on which to act. "Action" parameters are for choosing what to do with the selected tests. "Other" parameters are for global effect (like "help" or "verbose"). With this commit, we add the ability to name a directory as another selection mechanism. We can accumulate a number of tests by directory, file, category, or even by test id, instead of being constrained to run all tests in one collection or just one test. Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- .../creating-testcases/AddingTestCases.txt | 35 +++- tools/testing/selftests/tc-testing/tdc.py | 209 +++++++++++++-------- tools/testing/selftests/tc-testing/tdc_helper.py | 15 +- 3 files changed, 164 insertions(+), 95 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt b/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt index 00438331ba47..17b267dedbd9 100644 --- a/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt +++ b/tools/testing/selftests/tc-testing/creating-testcases/AddingTestCases.txt @@ -12,14 +12,18 @@ template.json for the required JSON format for test cases. Include the 'id' field, but do not assign a value. Running tdc with the -i option will generate a unique ID for that test case. -tdc will recursively search the 'tc' subdirectory for .json files. Any -test case files you create in these directories will automatically be included. -If you wish to store your custom test cases elsewhere, be sure to run tdc -with the -f argument and the path to your file. +tdc will recursively search the 'tc-tests' subdirectory (or the +directories named with the -D option) for .json files. Any test case +files you create in these directories will automatically be included. +If you wish to store your custom test cases elsewhere, be sure to run +tdc with the -f argument and the path to your file, or the -D argument +and the path to your directory(ies). -Be aware of required escape characters in the JSON data - particularly when -defining the match pattern. Refer to the tctests.json file for examples when -in doubt. +Be aware of required escape characters in the JSON data - particularly +when defining the match pattern. Refer to the supplied json test files +for examples when in doubt. The match pattern is written in json, and +will be used by python. So the match pattern will be a python regular +expression, but should be written using json syntax. TEST CASE STRUCTURE @@ -69,7 +73,8 @@ SETUP/TEARDOWN ERRORS If an error is detected during the setup/teardown process, execution of the tests will immediately stop with an error message and the namespace in which the tests are run will be destroyed. This is to prevent inaccurate results -in the test cases. +in the test cases. tdc will output a series of TAP results for the skipped +tests. Repeated failures of the setup/teardown may indicate a problem with the test case, or possibly even a bug in one of the commands that are not being tested. @@ -79,3 +84,17 @@ so that it doesn't halt the script for an error that doesn't matter. Turn the individual command into a list, with the command being first, followed by all acceptable exit codes for the command. +Example: + +A pair of setup commands. The first can have exit code 0, 1 or 255, the +second must have exit code 0. + + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + "$TC actions add action reclassify index 65536" + ], diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index fc373fdf2bdc..ef3a8881e458 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -209,20 +209,41 @@ def set_args(parser): """ Set the command line arguments for tdc. """ - parser.add_argument('-p', '--path', type=str, - help='The full path to the tc executable to use') - parser.add_argument('-c', '--category', type=str, nargs='?', const='+c', - help='Run tests only from the specified category, or if no category is specified, list known categories.') - parser.add_argument('-f', '--file', type=str, - help='Run tests from the specified file') - parser.add_argument('-l', '--list', type=str, nargs='?', const="++", metavar='CATEGORY', - help='List all test cases, or those only within the specified category') - parser.add_argument('-s', '--show', type=str, nargs=1, metavar='ID', dest='showID', - help='Display the test case with specified id') - parser.add_argument('-e', '--execute', type=str, nargs=1, metavar='ID', - help='Execute the single test case with specified ID') - parser.add_argument('-i', '--id', action='store_true', dest='gen_id', - help='Generate ID numbers for new test cases') + parser.add_argument( + '-p', '--path', type=str, + help='The full path to the tc executable to use') + sg = parser.add_argument_group( + 'selection', 'select which test cases: ' + + 'files plus directories; filtered by categories plus testids') + ag = parser.add_argument_group( + 'action', 'select action to perform on selected test cases') + + sg.add_argument( + '-D', '--directory', nargs='+', metavar='DIR', + help='Collect tests from the specified directory(ies) ' + + '(default [tc-tests])') + sg.add_argument( + '-f', '--file', nargs='+', metavar='FILE', + help='Run tests from the specified file(s)') + sg.add_argument( + '-c', '--category', nargs='*', metavar='CATG', default=['+c'], + help='Run tests only from the specified category/ies, ' + + 'or if no category/ies is/are specified, list known categories.') + sg.add_argument( + '-e', '--execute', nargs='+', metavar='ID', + help='Execute the specified test cases with specified IDs') + ag.add_argument( + '-l', '--list', action='store_true', + help='List all test cases, or those only within the specified category') + ag.add_argument( + '-s', '--show', action='store_true', dest='showID', + help='Display the selected test cases') + ag.add_argument( + '-i', '--id', action='store_true', dest='gen_id', + help='Generate ID numbers for new test cases') + parser.add_argument( + '-v', '--verbose', action='count', default=0, + help='Show the commands that are being run') parser.add_argument('-d', '--device', help='Execute the test case in flower category') return parser @@ -257,7 +278,16 @@ def check_case_id(alltests): Check for duplicate test case IDs. """ idl = get_id_list(alltests) + # print('check_case_id: idl is {}'.format(idl)) + # answer = list() + # for x in idl: + # print('Looking at {}'.format(x)) + # print('what the heck is idl.count(x)??? {}'.format(idl.count(x))) + # if idl.count(x) > 1: + # answer.append(x) + # print(' ... append it {}'.format(x)) return [x for x in idl if idl.count(x) > 1] + return answer def does_id_exist(alltests, newid): @@ -300,28 +330,96 @@ def generate_case_ids(alltests): json.dump(testlist, outfile, indent=4) outfile.close() +def filter_tests_by_id(args, testlist): + ''' + Remove tests from testlist that are not in the named id list. + If id list is empty, return empty list. + ''' + newlist = list() + if testlist and args.execute: + target_ids = args.execute + + if isinstance(target_ids, list) and (len(target_ids) > 0): + newlist = list(filter(lambda x: x['id'] in target_ids, testlist)) + return newlist + +def filter_tests_by_category(args, testlist): + ''' + Remove tests from testlist that are not in a named category. + ''' + answer = list() + if args.category and testlist: + test_ids = list() + for catg in set(args.category): + if catg == '+c': + continue + print('considering category {}'.format(catg)) + for tc in testlist: + if catg in tc['category'] and tc['id'] not in test_ids: + answer.append(tc) + test_ids.append(tc['id']) + + return answer def get_test_cases(args): """ If a test case file is specified, retrieve tests from that file. Otherwise, glob for all json files in subdirectories and load from each one. + Also, if requested, filter by category, and add tests matching + certain ids. """ import fnmatch - if args.file != None: - if not os.path.isfile(args.file): - print("The specified test case file " + args.file + " does not exist.") - exit(1) - flist = [args.file] - else: - flist = [] - for root, dirnames, filenames in os.walk('tc-tests'): + + flist = [] + testdirs = ['tc-tests'] + + if args.file: + # at least one file was specified - remove the default directory + testdirs = [] + + for ff in args.file: + if not os.path.isfile(ff): + print("IGNORING file " + ff + " \n\tBECAUSE does not exist.") + else: + flist.append(os.path.abspath(ff)) + + if args.directory: + testdirs = args.directory + + for testdir in testdirs: + for root, dirnames, filenames in os.walk(testdir): for filename in fnmatch.filter(filenames, '*.json'): - flist.append(os.path.join(root, filename)) - alltests = list() + candidate = os.path.abspath(os.path.join(root, filename)) + if candidate not in testdirs: + flist.append(candidate) + + alltestcases = list() for casefile in flist: - alltests = alltests + (load_from_file(casefile)) - return alltests + alltestcases = alltestcases + (load_from_file(casefile)) + + allcatlist = get_test_categories(alltestcases) + allidlist = get_id_list(alltestcases) + + testcases_by_cats = get_categorized_testlist(alltestcases, allcatlist) + idtestcases = filter_tests_by_id(args, alltestcases) + cattestcases = filter_tests_by_category(args, alltestcases) + + cat_ids = [x['id'] for x in cattestcases] + if args.execute: + if args.category: + alltestcases = cattestcases + [x for x in idtestcases if x['id'] not in cat_ids] + else: + alltestcases = idtestcases + else: + if cat_ids: + alltestcases = cattestcases + else: + # just accept the existing value of alltestcases, + # which has been filtered by file/directory + pass + + return allcatlist, allidlist, testcases_by_cats, alltestcases def set_operation_mode(args): @@ -330,10 +428,9 @@ def set_operation_mode(args): what the script should do for this run, and call the appropriate function. """ - alltests = get_test_cases(args) + ucat, idlist, testcases, alltests = get_test_cases(args) if args.gen_id: - idlist = get_id_list(alltests) if (has_blank_ids(idlist)): alltests = generate_case_ids(alltests) else: @@ -347,42 +444,20 @@ def set_operation_mode(args): print("Please correct them before continuing.") exit(1) - ucat = get_test_categories(alltests) - if args.showID: - show_test_case_by_id(alltests, args.showID[0]) + for atest in alltests: + print_test_case(atest) exit(0) - if args.execute: - target_id = args.execute[0] - else: - target_id = "" - - if args.category: - if (args.category == '+c'): - print("Available categories:") - print_sll(ucat) - exit(0) - else: - target_category = args.category - else: - target_category = "" - - - testcases = get_categorized_testlist(alltests, ucat) + if isinstance(args.category, list) and (len(args.category) == 0): + print("Available categories:") + print_sll(ucat) + exit(0) if args.list: - if (args.list == "++"): + if args.list: list_test_cases(alltests) exit(0) - elif(len(args.list) > 0): - if (args.list not in ucat): - print("Unknown category " + args.list) - print("Available categories:") - print_sll(ucat) - exit(1) - list_test_cases(testcases[args.list]) - exit(0) if (os.geteuid() != 0): print("This script must be run with root privileges.\n") @@ -390,24 +465,8 @@ def set_operation_mode(args): ns_create() - if (len(target_category) == 0): - if (len(target_id) > 0): - alltests = list(filter(lambda x: target_id in x['id'], alltests)) - if (len(alltests) == 0): - print("Cannot find a test case with ID matching " + target_id) - exit(1) - catresults = test_runner(alltests, args) - print("All test results: " + "\n\n" + catresults) - elif (len(target_category) > 0): - if (target_category == "flower") and args.device == None: - print("Please specify a NIC device (-d) to run category flower") - exit(1) - if (target_category not in ucat): - print("Specified category is not present in this file.") - exit(1) - else: - catresults = test_runner(testcases[target_category], args) - print("Category " + target_category + "\n\n" + catresults) + catresults = test_runner(alltests, args) + print('All test results: \n\n{}'.format(catresults)) ns_destroy() diff --git a/tools/testing/selftests/tc-testing/tdc_helper.py b/tools/testing/selftests/tc-testing/tdc_helper.py index db381120a566..9f35c96c88a0 100644 --- a/tools/testing/selftests/tc-testing/tdc_helper.py +++ b/tools/testing/selftests/tc-testing/tdc_helper.py @@ -57,20 +57,11 @@ def print_sll(items): def print_test_case(tcase): """ Pretty-printing of a given test case. """ + print('\n==============\nTest {}\t{}\n'.format(tcase['id'], tcase['name'])) for k in tcase.keys(): if (isinstance(tcase[k], list)): print(k + ":") print_list(tcase[k]) else: - print(k + ": " + tcase[k]) - - -def show_test_case_by_id(testlist, caseID): - """ Find the specified test case to pretty-print. """ - if not any(d.get('id', None) == caseID for d in testlist): - print("That ID does not exist.") - exit(1) - else: - print_test_case(next((d for d in testlist if d['id'] == caseID))) - - + if not ((k == 'id') or (k == 'name')): + print(k + ": " + str(tcase[k])) -- cgit v1.3-14-g43fede From 6fac733d9d07c4fcc349a44add75c6435cc3f18c Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:20 -0500 Subject: tools: tc-testing: Refactor test-runner Split the test_runner function into the loop part (test_runner) and the contents (run_one_test) for maintainability. It makes it a little easier to catch exceptions in an individual test, and keep going (and flush a bunch of tap results for the skipped tests). Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 81 ++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 29 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index ef3a8881e458..a2624eda34db 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -85,9 +85,42 @@ def prepare_env(cmdlist): print("\nError message:") print(foutput) print("\nAborting test run.") - ns_destroy() - exit(1) + # ns_destroy() + raise Exception('prepare_env did not complete successfully') + +def run_one_test(index, tidx): + result = True + tresult = "" + tap = "" + print("Test " + tidx["id"] + ": " + tidx["name"]) + prepare_env(tidx["setup"]) + (p, procout) = exec_cmd(tidx["cmdUnderTest"]) + exit_code = p.returncode + + if (exit_code != int(tidx["expExitCode"])): + result = False + print("exit:", exit_code, int(tidx["expExitCode"])) + print(procout) + else: + match_pattern = re.compile(str(tidx["matchPattern"]), + re.DOTALL | re.MULTILINE) + (p, procout) = exec_cmd(tidx["verifyCmd"]) + match_index = re.findall(match_pattern, procout) + if len(match_index) != int(tidx["matchCount"]): + result = False + + if not result: + tresult += "not " + tresult += "ok {} - {} # {}\n".format(str(index), tidx['id'], tidx["name"]) + tap += tresult + if result == False: + tap += procout + + prepare_env(tidx["teardown"]) + index += 1 + + return tap def test_runner(filtered_tests, args): """ @@ -104,37 +137,27 @@ def test_runner(filtered_tests, args): tap = str(index) + ".." + str(tcount) + "\n" for tidx in testlist: - result = True - tresult = "" if "flower" in tidx["category"] and args.device == None: continue - print("Test " + tidx["id"] + ": " + tidx["name"]) - prepare_env(tidx["setup"]) - (p, procout) = exec_cmd(tidx["cmdUnderTest"]) - exit_code = p.returncode - - if (exit_code != int(tidx["expExitCode"])): - result = False - print("exit:", exit_code, int(tidx["expExitCode"])) - print(procout) - else: - match_pattern = re.compile(str(tidx["matchPattern"]), re.DOTALL) - (p, procout) = exec_cmd(tidx["verifyCmd"]) - match_index = re.findall(match_pattern, procout) - if len(match_index) != int(tidx["matchCount"]): - result = False - - if result == True: - tresult += "ok " - else: - tresult += "not ok " - tap += tresult + str(index) + " " + tidx["id"] + " " + tidx["name"] + "\n" + try: + badtest = tidx # in case it goes bad + tap += run_one_test(index, tidx) + except Exception as ee: + print('Exception {} (caught in test_runner, running test {} {} {})'. + format(ee, index, tidx['id'], tidx['name'])) + break + index += 1 - if result == False: - tap += procout + count = index + tap += 'about to flush the tap output if tests need to be skipped\n' + if tcount + 1 != index: + for tidx in testlist[index - 1:]: + msg = 'skipped - previous setup or teardown failed' + tap += 'ok {} - {} # {} {} {} \n'.format( + count, tidx['id'], msg, index, badtest.get('id', '--Unknown--')) + count += 1 - prepare_env(tidx["teardown"]) - index += 1 + tap += 'done flushing skipped test tap output\n' return tap -- cgit v1.3-14-g43fede From 93707cbabcc8baf2b2b5f4a99c1f08ee83eb7abd Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:21 -0500 Subject: tools: tc-testing: Introduce plugin architecture This should be a general test architecture, and yet allow specific tests to be done. Introduce a plugin architecture. An individual test has 4 stages, setup/execute/verify/teardown. Each plugin gets a chance to run a function at each stage, plus one call before all the tests are called ("pre" suite) and one after all the tests are called ("post" suite). In addition, just before each command is executed, the plugin gets a chance to modify the command using the "adjust_command" hook. This makes the test suite quite flexible. Future patches will take some functionality out of the tdc.py script and place it in plugins. To use the plugins, place the implementation in the plugins directory and run tdc.py. It will notice the plugins and use them. Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/TdcPlugin.py | 74 +++++++ .../tc-testing/creating-plugins/AddingPlugins.txt | 104 ++++++++++ .../selftests/tc-testing/plugin-lib/README-PLUGINS | 27 +++ .../selftests/tc-testing/plugins/__init__.py | 0 tools/testing/selftests/tc-testing/tdc.py | 221 +++++++++++++++------ 5 files changed, 368 insertions(+), 58 deletions(-) create mode 100644 tools/testing/selftests/tc-testing/TdcPlugin.py create mode 100644 tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS create mode 100644 tools/testing/selftests/tc-testing/plugins/__init__.py (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/TdcPlugin.py b/tools/testing/selftests/tc-testing/TdcPlugin.py new file mode 100644 index 000000000000..3ee9a6dacb52 --- /dev/null +++ b/tools/testing/selftests/tc-testing/TdcPlugin.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python3 + +class TdcPlugin: + def __init__(self): + super().__init__() + print(' -- {}.__init__'.format(self.sub_class)) + + def pre_suite(self, testcount, testidlist): + '''run commands before test_runner goes into a test loop''' + self.testcount = testcount + self.testidlist = testidlist + if self.args.verbose > 1: + print(' -- {}.pre_suite'.format(self.sub_class)) + + def post_suite(self, index): + '''run commands after test_runner completes the test loop + index is the last ordinal number of test that was attempted''' + if self.args.verbose > 1: + print(' -- {}.post_suite'.format(self.sub_class)) + + def pre_case(self, test_ordinal, testid): + '''run commands before test_runner does one test''' + if self.args.verbose > 1: + print(' -- {}.pre_case'.format(self.sub_class)) + self.args.testid = testid + self.args.test_ordinal = test_ordinal + + def post_case(self): + '''run commands after test_runner does one test''' + if self.args.verbose > 1: + print(' -- {}.post_case'.format(self.sub_class)) + + def pre_execute(self): + '''run command before test-runner does the execute step''' + if self.args.verbose > 1: + print(' -- {}.pre_execute'.format(self.sub_class)) + + def post_execute(self): + '''run command after test-runner does the execute step''' + if self.args.verbose > 1: + print(' -- {}.post_execute'.format(self.sub_class)) + + def adjust_command(self, stage, command): + '''adjust the command''' + if self.args.verbose > 1: + print(' -- {}.adjust_command {}'.format(self.sub_class, stage)) + + # if stage == 'pre': + # pass + # elif stage == 'setup': + # pass + # elif stage == 'execute': + # pass + # elif stage == 'verify': + # pass + # elif stage == 'teardown': + # pass + # elif stage == 'post': + # pass + # else: + # pass + + return command + + def add_args(self, parser): + '''Get the plugin args from the command line''' + self.argparser = parser + return self.argparser + + def check_args(self, args, remaining): + '''Check that the args are set correctly''' + self.args = args + if self.args.verbose > 1: + print(' -- {}.check_args'.format(self.sub_class)) diff --git a/tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt b/tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt new file mode 100644 index 000000000000..c18f88d09360 --- /dev/null +++ b/tools/testing/selftests/tc-testing/creating-plugins/AddingPlugins.txt @@ -0,0 +1,104 @@ +tdc - Adding plugins for tdc + +Author: Brenda J. Butler - bjb@mojatatu.com + +ADDING PLUGINS +-------------- + +A new plugin should be written in python as a class that inherits from TdcPlugin. +There are some examples in plugin-lib. + +The plugin can be used to add functionality to the test framework, +such as: + +- adding commands to be run before and/or after the test suite +- adding commands to be run before and/or after the test cases +- adding commands to be run before and/or after the execute phase of the test cases +- ability to alter the command to be run in any phase: + pre (the pre-suite stage) + prepare + execute + verify + teardown + post (the post-suite stage) +- ability to add to the command line args, and use them at run time + + +The functions in the class should follow the following interfaces: + + def __init__(self) + def pre_suite(self, testcount, testidlist) # see "PRE_SUITE" below + def post_suite(self, ordinal) # see "SKIPPING" below + def pre_case(self, test_ordinal, testid) # see "PRE_CASE" below + def post_case(self) + def pre_execute(self) + def post_execute(self) + def adjust_command(self, stage, command) # see "ADJUST" below + def add_args(self, parser) # see "ADD_ARGS" below + def check_args(self, args, remaining) # see "CHECK_ARGS" below + + +PRE_SUITE + +This method takes a testcount (number of tests to be run) and +testidlist (array of test ids for tests that will be run). This is +useful for various things, including when an exception occurs and the +rest of the tests must be skipped. The info is stored in the object, +and the post_suite method can refer to it when dumping the "skipped" +TAP output. The tdc.py script will do that for the test suite as +defined in the test case, but if the plugin is being used to run extra +tests on each test (eg, check for memory leaks on associated +co-processes) then that other tap output can be generated in the +post-suite method using this info passed in to the pre_suite method. + + +SKIPPING + +The post_suite method will receive the ordinal number of the last +test to be attempted. It can use this info when outputting +the TAP output for the extra test cases. + + +PRE_CASE + +The pre_case method will receive the ordinal number of the test +and the test id. Useful for outputing the extra test results. + + +ADJUST + +The adjust_command method receives a string representing +the execution stage and a string which is the actual command to be +executed. The plugin can adjust the command, based on the stage of +execution. + +The stages are represented by the following strings: + + 'pre' + 'setup' + 'command' + 'verify' + 'teardown' + 'post' + +The adjust_command method must return the adjusted command so tdc +can use it. + + +ADD_ARGS + +The add_args method receives the argparser object and can add +arguments to it. Care should be taken that the new arguments do not +conflict with any from tdc.py or from other plugins that will be used +concurrently. + +The add_args method should return the argparser object. + + +CHECK_ARGS + +The check_args method is so that the plugin can do validation on +the args, if needed. If there is a problem, and Exception should +be raised, with a string that explains the problem. + +eg: raise Exception('plugin xxx, arg -y is wrong, fix it') diff --git a/tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS b/tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS new file mode 100644 index 000000000000..aa8a2669702b --- /dev/null +++ b/tools/testing/selftests/tc-testing/plugin-lib/README-PLUGINS @@ -0,0 +1,27 @@ +tdc.py will look for plugins in a directory plugins off the cwd. +Make a set of numbered symbolic links from there to the actual plugins. +Eg: + +tdc.py +plugin-lib/ +plugins/ + __init__.py + 10-rootPlugin.py -> ../plugin-lib/rootPlugin.py + 20-valgrindPlugin.py -> ../plugin-lib/valgrindPlugin.py + 30-nsPlugin.py -> ../plugin-lib/nsPlugin.py + + +tdc.py will find them and use them. + + +rootPlugin + Check if the uid is root. If not, bail out. + +valgrindPlugin + Run the command under test with valgrind, and produce an extra set of TAP results for the memory tests. + This plugin will write files to the cwd, called vgnd-xxx.log. These will contain + the valgrind output for test xxx. Any file matching the glob 'vgnd-*.log' will be + deleted at the end of the run. + +nsPlugin + Run all the commands in a network namespace. diff --git a/tools/testing/selftests/tc-testing/plugins/__init__.py b/tools/testing/selftests/tc-testing/plugins/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index a2624eda34db..3e6f9f2e1691 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -11,17 +11,91 @@ import re import os import sys import argparse +import importlib import json import subprocess +import time from collections import OrderedDict from string import Template from tdc_config import * from tdc_helper import * +import TdcPlugin USE_NS = True +class PluginMgr: + def __init__(self, argparser): + super().__init__() + self.plugins = {} + self.plugin_instances = [] + self.args = [] + self.argparser = argparser + + # TODO, put plugins in order + plugindir = os.getenv('TDC_PLUGIN_DIR', './plugins') + for dirpath, dirnames, filenames in os.walk(plugindir): + for fn in filenames: + if (fn.endswith('.py') and + not fn == '__init__.py' and + not fn.startswith('#') and + not fn.startswith('.#')): + mn = fn[0:-3] + foo = importlib.import_module('plugins.' + mn) + self.plugins[mn] = foo + self.plugin_instances.append(foo.SubPlugin()) + + def call_pre_suite(self, testcount, testidlist): + for pgn_inst in self.plugin_instances: + pgn_inst.pre_suite(testcount, testidlist) + + def call_post_suite(self, index): + for pgn_inst in reversed(self.plugin_instances): + pgn_inst.post_suite(index) + + def call_pre_case(self, test_ordinal, testid): + for pgn_inst in self.plugin_instances: + try: + pgn_inst.pre_case(test_ordinal, testid) + except Exception as ee: + print('exception {} in call to pre_case for {} plugin'. + format(ee, pgn_inst.__class__)) + print('test_ordinal is {}'.format(test_ordinal)) + print('testid is {}'.format(testid)) + raise + + def call_post_case(self): + for pgn_inst in reversed(self.plugin_instances): + pgn_inst.post_case() + + def call_pre_execute(self): + for pgn_inst in self.plugin_instances: + pgn_inst.pre_execute() + + def call_post_execute(self): + for pgn_inst in reversed(self.plugin_instances): + pgn_inst.post_execute() + + def call_add_args(self, parser): + for pgn_inst in self.plugin_instances: + parser = pgn_inst.add_args(parser) + return parser + + def call_check_args(self, args, remaining): + for pgn_inst in self.plugin_instances: + pgn_inst.check_args(args, remaining) + + def call_adjust_command(self, stage, command): + for pgn_inst in self.plugin_instances: + command = pgn_inst.adjust_command(stage, command) + return command + + @staticmethod + def _make_argparser(args): + self.argparser = argparse.ArgumentParser( + description='Linux TC unit tests') + def replace_keywords(cmd): """ @@ -33,21 +107,27 @@ def replace_keywords(cmd): return subcmd -def exec_cmd(command, nsonly=True): +def exec_cmd(args, pm, stage, command, nsonly=True): """ Perform any required modifications on an executable command, then run it in a subprocess and return the results. """ + if len(command.strip()) == 0: + return None, None if (USE_NS and nsonly): command = 'ip netns exec $NS ' + command if '$' in command: command = replace_keywords(command) + command = pm.call_adjust_command(stage, command) + if args.verbose > 0: + print('command "{}"'.format(command)) proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + stderr=subprocess.PIPE, + env=ENVIR) (rawout, serr) = proc.communicate() if proc.returncode != 0 and len(serr) > 0: @@ -60,69 +140,85 @@ def exec_cmd(command, nsonly=True): return proc, foutput -def prepare_env(cmdlist): +def prepare_env(args, pm, stage, prefix, cmdlist): """ - Execute the setup/teardown commands for a test case. Optionally - terminate test execution if the command fails. + Execute the setup/teardown commands for a test case. + Optionally terminate test execution if the command fails. """ + if args.verbose > 0: + print('{}'.format(prefix)) for cmdinfo in cmdlist: - if (type(cmdinfo) == list): + if isinstance(cmdinfo, list): exit_codes = cmdinfo[1:] cmd = cmdinfo[0] else: exit_codes = [0] cmd = cmdinfo - if (len(cmd) == 0): + if not cmd: continue - (proc, foutput) = exec_cmd(cmd) + (proc, foutput) = exec_cmd(args, pm, stage, cmd) - if proc.returncode not in exit_codes: - print - print("Could not execute:") - print(cmd) - print("\nError message:") - print(foutput) - print("\nAborting test run.") - # ns_destroy() - raise Exception('prepare_env did not complete successfully') + if proc and (proc.returncode not in exit_codes): + print('', file=sys.stderr) + print("{} *** Could not execute: \"{}\"".format(prefix, cmd), + file=sys.stderr) + print("\n{} *** Error message: \"{}\"".format(prefix, foutput), + file=sys.stderr) + print("\n{} *** Aborting test run.".format(prefix), file=sys.stderr) + print("\n\n{} *** stdout ***".format(proc.stdout), file=sys.stderr) + print("\n\n{} *** stderr ***".format(proc.stderr), file=sys.stderr) + raise Exception('"{}" did not complete successfully'.format(prefix)) -def run_one_test(index, tidx): +def run_one_test(pm, args, index, tidx): result = True tresult = "" tap = "" + if args.verbose > 0: + print("\t====================\n=====> ", end="") print("Test " + tidx["id"] + ": " + tidx["name"]) - prepare_env(tidx["setup"]) - (p, procout) = exec_cmd(tidx["cmdUnderTest"]) + + pm.call_pre_case(index, tidx['id']) + prepare_env(args, pm, 'setup', "-----> prepare stage", tidx["setup"]) + + if (args.verbose > 0): + print('-----> execute stage') + pm.call_pre_execute() + (p, procout) = exec_cmd(args, pm, 'execute', tidx["cmdUnderTest"]) exit_code = p.returncode + pm.call_post_execute() if (exit_code != int(tidx["expExitCode"])): result = False print("exit:", exit_code, int(tidx["expExitCode"])) print(procout) else: - match_pattern = re.compile(str(tidx["matchPattern"]), - re.DOTALL | re.MULTILINE) - (p, procout) = exec_cmd(tidx["verifyCmd"]) + if args.verbose > 0: + print('-----> verify stage') + match_pattern = re.compile( + str(tidx["matchPattern"]), re.DOTALL | re.MULTILINE) + (p, procout) = exec_cmd(args, pm, 'verify', tidx["verifyCmd"]) match_index = re.findall(match_pattern, procout) if len(match_index) != int(tidx["matchCount"]): result = False if not result: - tresult += "not " - tresult += "ok {} - {} # {}\n".format(str(index), tidx['id'], tidx["name"]) + tresult += 'not ' + tresult += 'ok {} - {} # {}\n'.format(str(index), tidx['id'], tidx['name']) tap += tresult if result == False: tap += procout - prepare_env(tidx["teardown"]) + prepare_env(args, pm, 'teardown', '-----> teardown stage', tidx['teardown']) + pm.call_post_case() + index += 1 return tap -def test_runner(filtered_tests, args): +def test_runner(pm, args, filtered_tests): """ Driver function for the unit tests. @@ -135,63 +231,71 @@ def test_runner(filtered_tests, args): tcount = len(testlist) index = 1 tap = str(index) + ".." + str(tcount) + "\n" + badtest = None + pm.call_pre_suite(tcount, [tidx['id'] for tidx in testlist]) + + if args.verbose > 1: + print('Run tests here') for tidx in testlist: if "flower" in tidx["category"] and args.device == None: continue try: badtest = tidx # in case it goes bad - tap += run_one_test(index, tidx) + tap += run_one_test(pm, args, index, tidx) except Exception as ee: print('Exception {} (caught in test_runner, running test {} {} {})'. format(ee, index, tidx['id'], tidx['name'])) break index += 1 + # if we failed in setup or teardown, + # fill in the remaining tests with not ok count = index tap += 'about to flush the tap output if tests need to be skipped\n' if tcount + 1 != index: for tidx in testlist[index - 1:]: msg = 'skipped - previous setup or teardown failed' - tap += 'ok {} - {} # {} {} {} \n'.format( + tap += 'ok {} - {} # {} {} {}\n'.format( count, tidx['id'], msg, index, badtest.get('id', '--Unknown--')) count += 1 tap += 'done flushing skipped test tap output\n' + pm.call_post_suite(index) return tap -def ns_create(): +def ns_create(args, pm): """ Create the network namespace in which the tests will be run and set up the required network devices for it. """ if (USE_NS): cmd = 'ip netns add $NS' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip link add $DEV0 type veth peer name $DEV1' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip link set $DEV1 netns $NS' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip link set $DEV0 up' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip -n $NS link set $DEV1 up' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip link set $DEV2 netns $NS' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) cmd = 'ip -n $NS link set $DEV2 up' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'pre', cmd, False) -def ns_destroy(): +def ns_destroy(args, pm): """ Destroy the network namespace for testing (and any associated network devices as well) """ if (USE_NS): cmd = 'ip netns delete $NS' - exec_cmd(cmd, False) + exec_cmd(args, pm, 'post', cmd, False) def has_blank_ids(idlist): @@ -272,10 +376,10 @@ def set_args(parser): return parser -def check_default_settings(args): +def check_default_settings(args, remaining, pm): """ - Process any arguments overriding the default settings, and ensure the - settings are correct. + Process any arguments overriding the default settings, + and ensure the settings are correct. """ # Allow for overriding specific settings global NAMES @@ -288,6 +392,8 @@ def check_default_settings(args): print("The specified tc path " + NAMES['TC'] + " does not exist.") exit(1) + pm.call_check_args(args, remaining) + def get_id_list(alltests): """ @@ -301,16 +407,7 @@ def check_case_id(alltests): Check for duplicate test case IDs. """ idl = get_id_list(alltests) - # print('check_case_id: idl is {}'.format(idl)) - # answer = list() - # for x in idl: - # print('Looking at {}'.format(x)) - # print('what the heck is idl.count(x)??? {}'.format(idl.count(x))) - # if idl.count(x) > 1: - # answer.append(x) - # print(' ... append it {}'.format(x)) return [x for x in idl if idl.count(x) > 1] - return answer def does_id_exist(alltests, newid): @@ -403,7 +500,7 @@ def get_test_cases(args): for ff in args.file: if not os.path.isfile(ff): - print("IGNORING file " + ff + " \n\tBECAUSE does not exist.") + print("IGNORING file " + ff + "\n\tBECAUSE does not exist.") else: flist.append(os.path.abspath(ff)) @@ -445,7 +542,7 @@ def get_test_cases(args): return allcatlist, allidlist, testcases_by_cats, alltestcases -def set_operation_mode(args): +def set_operation_mode(pm, args): """ Load the test case data and process remaining arguments to determine what the script should do for this run, and call the appropriate @@ -486,12 +583,15 @@ def set_operation_mode(args): print("This script must be run with root privileges.\n") exit(1) - ns_create() + ns_create(args, pm) - catresults = test_runner(alltests, args) + if len(alltests): + catresults = test_runner(pm, args, alltests) + else: + catresults = 'No tests found\n' print('All test results: \n\n{}'.format(catresults)) - ns_destroy() + ns_destroy(args, pm) def main(): @@ -501,10 +601,15 @@ def main(): """ parser = args_parse() parser = set_args(parser) + pm = PluginMgr(parser) + parser = pm.call_add_args(parser) (args, remaining) = parser.parse_known_args() - check_default_settings(args) + args.NAMES = NAMES + check_default_settings(args, remaining, pm) + if args.verbose > 2: + print('args is {}'.format(args)) - set_operation_mode(args) + set_operation_mode(pm, args) exit(0) -- cgit v1.3-14-g43fede From f6926e85eee9be08d05170af3a2266b8d7f9cdef Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:22 -0500 Subject: tools: tc-testing: rootPlugin Move the functionality that checks for root permissions into a plugin. Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- .../selftests/tc-testing/plugin-lib/rootPlugin.py | 19 +++++++++++++++++++ tools/testing/selftests/tc-testing/tdc.py | 4 ---- 2 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py new file mode 100644 index 000000000000..e36775bd4d12 --- /dev/null +++ b/tools/testing/selftests/tc-testing/plugin-lib/rootPlugin.py @@ -0,0 +1,19 @@ +import os +import sys +from TdcPlugin import TdcPlugin + +from tdc_config import * + + +class SubPlugin(TdcPlugin): + def __init__(self): + self.sub_class = 'root/SubPlugin' + super().__init__() + + def pre_suite(self, testcount, testidlist): + # run commands before test_runner goes into a test loop + super().pre_suite(testcount, testidlist) + + if os.geteuid(): + print('This script must be run with root privileges', file=sys.stderr) + exit(1) diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 3e6f9f2e1691..a718d2b57739 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -579,10 +579,6 @@ def set_operation_mode(pm, args): list_test_cases(alltests) exit(0) - if (os.geteuid() != 0): - print("This script must be run with root privileges.\n") - exit(1) - ns_create(args, pm) if len(alltests): -- cgit v1.3-14-g43fede From a13fedbe56fef141aff7d584eba2a08daaf613cc Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:23 -0500 Subject: tools: tc-testing: nsPlugin Move the functionality of creating a namespace before the test suite and destroying it afterwards to a plugin. Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- .../selftests/tc-testing/plugin-lib/nsPlugin.py | 141 +++++++++++++++++++++ tools/testing/selftests/tc-testing/tdc.py | 45 +------ 2 files changed, 142 insertions(+), 44 deletions(-) create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py new file mode 100644 index 000000000000..a194b1af2b30 --- /dev/null +++ b/tools/testing/selftests/tc-testing/plugin-lib/nsPlugin.py @@ -0,0 +1,141 @@ +import os +import signal +from string import Template +import subprocess +import time +from TdcPlugin import TdcPlugin + +from tdc_config import * + +class SubPlugin(TdcPlugin): + def __init__(self): + self.sub_class = 'ns/SubPlugin' + super().__init__() + + def pre_suite(self, testcount, testidlist): + '''run commands before test_runner goes into a test loop''' + super().pre_suite(testcount, testidlist) + + if self.args.namespace: + self._ns_create() + + def post_suite(self, index): + '''run commands after test_runner goes into a test loop''' + super().post_suite(index) + if self.args.verbose: + print('{}.post_suite'.format(self.sub_class)) + + if self.args.namespace: + self._ns_destroy() + + def add_args(self, parser): + super().add_args(parser) + self.argparser_group = self.argparser.add_argument_group( + 'netns', + 'options for nsPlugin(run commands in net namespace)') + self.argparser_group.add_argument( + '-n', '--namespace', action='store_true', + help='Run commands in namespace') + return self.argparser + + def adjust_command(self, stage, command): + super().adjust_command(stage, command) + cmdform = 'list' + cmdlist = list() + + if not self.args.namespace: + return command + + if self.args.verbose: + print('{}.adjust_command'.format(self.sub_class)) + + if not isinstance(command, list): + cmdform = 'str' + cmdlist = command.split() + else: + cmdlist = command + if stage == 'setup' or stage == 'execute' or stage == 'verify' or stage == 'teardown': + if self.args.verbose: + print('adjust_command: stage is {}; inserting netns stuff in command [{}] list [{}]'.format(stage, command, cmdlist)) + cmdlist.insert(0, self.args.NAMES['NS']) + cmdlist.insert(0, 'exec') + cmdlist.insert(0, 'netns') + cmdlist.insert(0, 'ip') + else: + pass + + if cmdform == 'str': + command = ' '.join(cmdlist) + else: + command = cmdlist + + if self.args.verbose: + print('adjust_command: return command [{}]'.format(command)) + return command + + def _ns_create(self): + ''' + Create the network namespace in which the tests will be run and set up + the required network devices for it. + ''' + if self.args.namespace: + cmd = 'ip netns add {}'.format(self.args.NAMES['NS']) + self._exec_cmd('pre', cmd) + cmd = 'ip link add $DEV0 type veth peer name $DEV1' + self._exec_cmd('pre', cmd) + cmd = 'ip link set $DEV1 netns {}'.format(self.args.NAMES['NS']) + self._exec_cmd('pre', cmd) + cmd = 'ip link set $DEV0 up' + self._exec_cmd('pre', cmd) + cmd = 'ip -n {} link set $DEV1 up'.format(self.args.NAMES['NS']) + self._exec_cmd('pre', cmd) + if self.args.device: + cmd = 'ip link set $DEV2 netns {}'.format(self.args.NAMES['NS']) + self._exec_cmd('pre', cmd) + cmd = 'ip -n {} link set $DEV2 up'.format(self.args.NAMES['NS']) + self._exec_cmd('pre', cmd) + + def _ns_destroy(self): + ''' + Destroy the network namespace for testing (and any associated network + devices as well) + ''' + if self.args.namespace: + cmd = 'ip netns delete {}'.format(self.args.NAMES['NS']) + self._exec_cmd('post', cmd) + + def _exec_cmd(self, stage, command): + ''' + Perform any required modifications on an executable command, then run + it in a subprocess and return the results. + ''' + if '$' in command: + command = self._replace_keywords(command) + + self.adjust_command(stage, command) + if self.args.verbose: + print('_exec_cmd: command "{}"'.format(command)) + proc = subprocess.Popen(command, + shell=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=ENVIR) + (rawout, serr) = proc.communicate() + + if proc.returncode != 0 and len(serr) > 0: + foutput = serr.decode("utf-8") + else: + foutput = rawout.decode("utf-8") + + proc.stdout.close() + proc.stderr.close() + return proc, foutput + + def _replace_keywords(self, cmd): + """ + For a given executable command, substitute any known + variables contained within NAMES with the correct values + """ + tcmd = Template(cmd) + subcmd = tcmd.safe_substitute(self.args.NAMES) + return subcmd diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index a718d2b57739..b3754b9aa302 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -23,8 +23,6 @@ from tdc_helper import * import TdcPlugin -USE_NS = True - class PluginMgr: def __init__(self, argparser): super().__init__() @@ -107,16 +105,13 @@ def replace_keywords(cmd): return subcmd -def exec_cmd(args, pm, stage, command, nsonly=True): +def exec_cmd(args, pm, stage, command): """ Perform any required modifications on an executable command, then run it in a subprocess and return the results. """ if len(command.strip()) == 0: return None, None - if (USE_NS and nsonly): - command = 'ip netns exec $NS ' + command - if '$' in command: command = replace_keywords(command) @@ -265,39 +260,6 @@ def test_runner(pm, args, filtered_tests): return tap - -def ns_create(args, pm): - """ - Create the network namespace in which the tests will be run and set up - the required network devices for it. - """ - if (USE_NS): - cmd = 'ip netns add $NS' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip link add $DEV0 type veth peer name $DEV1' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip link set $DEV1 netns $NS' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip link set $DEV0 up' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip -n $NS link set $DEV1 up' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip link set $DEV2 netns $NS' - exec_cmd(args, pm, 'pre', cmd, False) - cmd = 'ip -n $NS link set $DEV2 up' - exec_cmd(args, pm, 'pre', cmd, False) - - -def ns_destroy(args, pm): - """ - Destroy the network namespace for testing (and any associated network - devices as well) - """ - if (USE_NS): - cmd = 'ip netns delete $NS' - exec_cmd(args, pm, 'post', cmd, False) - - def has_blank_ids(idlist): """ Search the list for empty ID fields and return true/false accordingly. @@ -579,17 +541,12 @@ def set_operation_mode(pm, args): list_test_cases(alltests) exit(0) - ns_create(args, pm) - if len(alltests): catresults = test_runner(pm, args, alltests) else: catresults = 'No tests found\n' print('All test results: \n\n{}'.format(catresults)) - ns_destroy(args, pm) - - def main(): """ Start of execution; set up argument parser and get the arguments, -- cgit v1.3-14-g43fede From c25e4736867f73901de4fdb62c122ae2c6d91159 Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:24 -0500 Subject: tools: tc-testing: valgrindPlugin Run the command under test under valgrind. Produce an extra set of tap output for the memory check on each test. Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- .../tc-testing/plugin-lib/valgrindPlugin.py | 142 +++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py b/tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py new file mode 100644 index 000000000000..477a7bd7d7fb --- /dev/null +++ b/tools/testing/selftests/tc-testing/plugin-lib/valgrindPlugin.py @@ -0,0 +1,142 @@ +''' +run the command under test, under valgrind and collect memory leak info +as a separate test. +''' + + +import os +import re +import signal +from string import Template +import subprocess +import time +from TdcPlugin import TdcPlugin + +from tdc_config import * + +def vp_extract_num_from_string(num_as_string_maybe_with_commas): + return int(num_as_string_maybe_with_commas.replace(',','')) + +class SubPlugin(TdcPlugin): + def __init__(self): + self.sub_class = 'valgrind/SubPlugin' + self.tap = '' + super().__init__() + + def pre_suite(self, testcount, testidlist): + '''run commands before test_runner goes into a test loop''' + super().pre_suite(testcount, testidlist) + if self.args.verbose > 1: + print('{}.pre_suite'.format(self.sub_class)) + if self.args.valgrind: + self._add_to_tap('1..{}\n'.format(self.testcount)) + + def post_suite(self, index): + '''run commands after test_runner goes into a test loop''' + super().post_suite(index) + self._add_to_tap('\n|---\n') + if self.args.verbose > 1: + print('{}.post_suite'.format(self.sub_class)) + print('{}'.format(self.tap)) + if self.args.verbose < 4: + subprocess.check_output('rm -f vgnd-*.log', shell=True) + + def add_args(self, parser): + super().add_args(parser) + self.argparser_group = self.argparser.add_argument_group( + 'valgrind', + 'options for valgrindPlugin (run command under test under Valgrind)') + + self.argparser_group.add_argument( + '-V', '--valgrind', action='store_true', + help='Run commands under valgrind') + + return self.argparser + + def adjust_command(self, stage, command): + super().adjust_command(stage, command) + cmdform = 'list' + cmdlist = list() + + if not self.args.valgrind: + return command + + if self.args.verbose > 1: + print('{}.adjust_command'.format(self.sub_class)) + + if not isinstance(command, list): + cmdform = 'str' + cmdlist = command.split() + else: + cmdlist = command + + if stage == 'execute': + if self.args.verbose > 1: + print('adjust_command: stage is {}; inserting valgrind stuff in command [{}] list [{}]'. + format(stage, command, cmdlist)) + cmdlist.insert(0, '--track-origins=yes') + cmdlist.insert(0, '--show-leak-kinds=definite,indirect') + cmdlist.insert(0, '--leak-check=full') + cmdlist.insert(0, '--log-file=vgnd-{}.log'.format(self.args.testid)) + cmdlist.insert(0, '-v') # ask for summary of non-leak errors + cmdlist.insert(0, ENVIR['VALGRIND_BIN']) + else: + pass + + if cmdform == 'str': + command = ' '.join(cmdlist) + else: + command = cmdlist + + if self.args.verbose > 1: + print('adjust_command: return command [{}]'.format(command)) + return command + + def post_execute(self): + if not self.args.valgrind: + return + + self.definitely_lost_re = re.compile( + r'definitely lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\sblocks', re.MULTILINE | re.DOTALL) + self.indirectly_lost_re = re.compile( + r'indirectly lost:\s+([,0-9]+)\s+bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL) + self.possibly_lost_re = re.compile( + r'possibly lost:\s+([,0-9]+)bytes in\s+([,0-9]+)\s+blocks', re.MULTILINE | re.DOTALL) + self.non_leak_error_re = re.compile( + r'ERROR SUMMARY:\s+([,0-9]+) errors from\s+([,0-9]+)\s+contexts', re.MULTILINE | re.DOTALL) + + def_num = 0 + ind_num = 0 + pos_num = 0 + nle_num = 0 + + # what about concurrent test runs? Maybe force them to be in different directories? + with open('vgnd-{}.log'.format(self.args.testid)) as vfd: + content = vfd.read() + def_mo = self.definitely_lost_re.search(content) + ind_mo = self.indirectly_lost_re.search(content) + pos_mo = self.possibly_lost_re.search(content) + nle_mo = self.non_leak_error_re.search(content) + + if def_mo: + def_num = int(def_mo.group(2)) + if ind_mo: + ind_num = int(ind_mo.group(2)) + if pos_mo: + pos_num = int(pos_mo.group(2)) + if nle_mo: + nle_num = int(nle_mo.group(1)) + + mem_results = '' + if (def_num > 0) or (ind_num > 0) or (pos_num > 0) or (nle_num > 0): + mem_results += 'not ' + + mem_results += 'ok {} - {}-mem # {}\n'.format( + self.args.test_ordinal, self.args.testid, 'memory leak check') + self._add_to_tap(mem_results) + if mem_results.startswith('not '): + print('{}'.format(content)) + self._add_to_tap(content) + + def _add_to_tap(self, more_tap_output): + self.tap += more_tap_output -- cgit v1.3-14-g43fede From 95ce14c3fff87ee43366c8cf84790f2e72167633 Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 14 Feb 2018 14:09:25 -0500 Subject: tools: tc-testing: Update README and TODO Signed-off-by: Brenda J. Butler Acked-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/README | 173 +++++++++++++++++++++++++--- tools/testing/selftests/tc-testing/TODO.txt | 25 +++- 2 files changed, 179 insertions(+), 19 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/README b/tools/testing/selftests/tc-testing/README index 970ff294fec8..3a0336782d2d 100644 --- a/tools/testing/selftests/tc-testing/README +++ b/tools/testing/selftests/tc-testing/README @@ -14,11 +14,11 @@ REQUIREMENTS * The kernel must have network namespace support -* The kernel must have veth support available, as a veth pair is created +* The kernel must have veth support available, as a veth pair is created prior to running the tests. -* All tc-related features must be built in or available as modules. - To check what is required in current setup run: +* All tc-related features being tested must be built in or available as + modules. To check what is required in current setup run: ./tdc.py -c Note: @@ -44,10 +44,13 @@ using the -p option when running tdc: RUNNING TDC ----------- -To use tdc, root privileges are required. tdc will not run otherwise. +To use tdc, root privileges are required. This is because the +commands being tested must be run as root. The code that enforces +execution by root uid has been moved into a plugin (see PLUGIN +ARCHITECTURE, below). -All tests are executed inside a network namespace to prevent conflicts -within the host. +If nsPlugin is linked, all tests are executed inside a network +namespace to prevent conflicts within the host. Running tdc without any arguments will run all tests. Refer to the section on command line arguments for more information, or run: @@ -59,6 +62,33 @@ output captured from the failing test will be printed immediately following the failed test in the TAP output. +OVERVIEW OF TDC EXECUTION +------------------------- + +One run of tests is considered a "test suite" (this will be refined in the +future). A test suite has one or more test cases in it. + +A test case has four stages: + + - setup + - execute + - verify + - teardown + +The setup and teardown stages can run zero or more commands. The setup +stage does some setup if the test needs it. The teardown stage undoes +the setup and returns the system to a "neutral" state so any other test +can be run next. These two stages require any commands run to return +success, but do not otherwise verify the results. + +The execute and verify stages each run one command. The execute stage +tests the return code against one or more acceptable values. The +verify stage checks the return code for success, and also compares +the stdout with a regular expression. + +Each of the commands in any stage will run in a shell instance. + + USER-DEFINED CONSTANTS ---------------------- @@ -70,23 +100,132 @@ executed as part of the test. More will be added as test cases require. Example: $TC qdisc add dev $DEV1 ingress +The NAMES values are used to substitute into the commands in the test cases. + COMMAND LINE ARGUMENTS ---------------------- Run tdc.py -h to see the full list of available arguments. --p PATH Specify the tc executable located at PATH to be used on this - test run --c Show the available test case categories in this test file --c CATEGORY Run only tests that belong to CATEGORY --f FILE Read test cases from the JSON file named FILE --l [CATEGORY] List all test cases in the JSON file. If CATEGORY is - specified, list test cases matching that category. --s ID Show the test case matching ID --e ID Execute the test case identified by ID --i Generate unique ID numbers for test cases with no existing - ID number +usage: tdc.py [-h] [-p PATH] [-D DIR [DIR ...]] [-f FILE [FILE ...]] + [-c [CATG [CATG ...]]] [-e ID [ID ...]] [-l] [-s] [-i] [-v] + [-d DEVICE] [-n NS] [-V] + +Linux TC unit tests + +optional arguments: + -h, --help show this help message and exit + -p PATH, --path PATH The full path to the tc executable to use + -v, --verbose Show the commands that are being run + -d DEVICE, --device DEVICE + Execute the test case in flower category + +selection: + select which test cases: files plus directories; filtered by categories + plus testids + + -D DIR [DIR ...], --directory DIR [DIR ...] + Collect tests from the specified directory(ies) + (default [tc-tests]) + -f FILE [FILE ...], --file FILE [FILE ...] + Run tests from the specified file(s) + -c [CATG [CATG ...]], --category [CATG [CATG ...]] + Run tests only from the specified category/ies, or if + no category/ies is/are specified, list known + categories. + -e ID [ID ...], --execute ID [ID ...] + Execute the specified test cases with specified IDs + +action: + select action to perform on selected test cases + + -l, --list List all test cases, or those only within the + specified category + -s, --show Display the selected test cases + -i, --id Generate ID numbers for new test cases + +netns: + options for nsPlugin(run commands in net namespace) + + -n NS, --namespace NS + Run commands in namespace NS + +valgrind: + options for valgrindPlugin (run command under test under Valgrind) + + -V, --valgrind Run commands under valgrind + + +PLUGIN ARCHITECTURE +------------------- + +There is now a plugin architecture, and some of the functionality that +was in the tdc.py script has been moved into the plugins. + +The plugins are in the directory plugin-lib. The are executed from +directory plugins. Put symbolic links from plugins to plugin-lib, +and name them according to the order you want them to run. + +Example: + +bjb@bee:~/work/tc-testing$ ls -l plugins +total 4 +lrwxrwxrwx 1 bjb bjb 27 Oct 4 16:12 10-rootPlugin.py -> ../plugin-lib/rootPlugin.py +lrwxrwxrwx 1 bjb bjb 25 Oct 12 17:55 20-nsPlugin.py -> ../plugin-lib/nsPlugin.py +-rwxr-xr-x 1 bjb bjb 0 Sep 29 15:56 __init__.py + +The plugins are a subclass of TdcPlugin, defined in TdcPlugin.py and +must be called "SubPlugin" so tdc can find them. They are +distinguished from each other in the python program by their module +name. + +This base class supplies "hooks" to run extra functions. These hooks are as follows: + +pre- and post-suite +pre- and post-case +pre- and post-execute stage +adjust-command (runs in all stages and receives the stage name) + +The pre-suite hook receives the number of tests and an array of test ids. +This allows you to dump out the list of skipped tests in the event of a +failure during setup or teardown stage. + +The pre-case hook receives the ordinal number and test id of the current test. + +The adjust-command hook receives the stage id (see list below) and the +full command to be executed. This allows for last-minute adjustment +of the command. + +The stages are identified by the following strings: + + - pre (pre-suite) + - setup + - command + - verify + - teardown + - post (post-suite) + + +To write a plugin, you need to inherit from TdcPlugin in +TdcPlugin.py. To use the plugin, you have to put the +implementation file in plugin-lib, and add a symbolic link to it from +plugins. It will be detected at run time and invoked at the +appropriate times. There are a few examples in the plugin-lib +directory: + + - rootPlugin.py: + implements the enforcement of running as root + - nsPlugin.py: + sets up a network namespace and runs all commands in that namespace + - valgrindPlugin.py + runs each command in the execute stage under valgrind, + and checks for leaks. + This plugin will output an extra test for each test in the test file, + one is the existing output as to whether the test passed or failed, + and the other is a test whether the command leaked memory or not. + (This one is a preliminary version, it may not work quite right yet, + but the overall template is there and it should only need tweaks.) ACKNOWLEDGEMENTS diff --git a/tools/testing/selftests/tc-testing/TODO.txt b/tools/testing/selftests/tc-testing/TODO.txt index 6a266d811a78..c40698557e2f 100644 --- a/tools/testing/selftests/tc-testing/TODO.txt +++ b/tools/testing/selftests/tc-testing/TODO.txt @@ -5,6 +5,27 @@ tc Testing Suite To-Do list: - Add support for multiple versions of tc to run successively -- Improve error messages when tdc aborts its run +- Improve error messages when tdc aborts its run. Partially done - still + need to better handle problems in pre- and post-suite. -- Allow tdc to write its results to file +- Use python logger module for debug/verbose output + +- Allow tdc to write its results to file. + Maybe use python logger module for this too. + +- A better implementation of the "hooks". Currently, every plugin + will attempt to run a function at every hook point. Could be + changed so that plugin __init__ methods will register functions to + be run in the various predefined times. Then if a plugin does not + require action at a specific point, no penalty will be paid for + trying to run a function that will do nothing. + +- Proper exception handling - make an exception class and use it + +- a TestCase class, for easier testcase handling, searching, comparison + +- a TestSuite class + and a way to configure a test suite, + to automate running multiple "test suites" with different requirements + +- super simple test case example using ls, touch, etc -- cgit v1.3-14-g43fede From ddd0010392d9cbcb95b53d11b7cafc67b373ab56 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Thu, 15 Feb 2018 09:19:26 +0900 Subject: selftests/net: fixes psock_fanout eBPF test case eBPF test fails due to verifier failure because log_buf is too small. Fixed by increasing log_buf size Signed-off-by: Prashant Bhole Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/psock_fanout.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c index 989f917068d1..d4346b16b2c1 100644 --- a/tools/testing/selftests/net/psock_fanout.c +++ b/tools/testing/selftests/net/psock_fanout.c @@ -128,6 +128,8 @@ static void sock_fanout_getopts(int fd, uint16_t *typeflags, uint16_t *group_id) static void sock_fanout_set_ebpf(int fd) { + static char log_buf[65536]; + const int len_off = __builtin_offsetof(struct __sk_buff, len); struct bpf_insn prog[] = { { BPF_ALU64 | BPF_MOV | BPF_X, 6, 1, 0, 0 }, @@ -140,7 +142,6 @@ static void sock_fanout_set_ebpf(int fd) { BPF_ALU | BPF_MOV | BPF_K, 0, 0, 0, 0 }, { BPF_JMP | BPF_EXIT, 0, 0, 0, 0 } }; - char log_buf[512]; union bpf_attr attr; int pfd; -- cgit v1.3-14-g43fede From a7c8655b073d89303911c89d0fd9fc4be7631fbe Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 30 Nov 2017 15:36:35 -0800 Subject: sched/isolation: Eliminate NO_HZ_FULL_ALL Commit 6f1982fedd59 ("sched/isolation: Handle the nohz_full= parameter") broke CONFIG_NO_HZ_FULL_ALL=y kernels. This breakage is due to the code under CONFIG_NO_HZ_FULL_ALL failing to invoke the shiny new housekeeping functions. This means that rcutorture scenario TREE04 now emits RCU CPU stall warnings due to the RCU grace-period kthreads not being awakened at a time of their choosing, or perhaps even not at all: [ 27.731422] rcu_bh kthread starved for 21001 jiffies! g18446744073709551369 c18446744073709551368 f0x0 RCU_GP_WAIT_FQS(3) ->state=0x402 ->cpu=3 [ 27.731423] rcu_bh I14936 9 2 0x80080000 [ 27.731435] Call Trace: [ 27.731440] __schedule+0x31a/0x6d0 [ 27.731442] schedule+0x31/0x80 [ 27.731446] schedule_timeout+0x15a/0x320 [ 27.731453] ? call_timer_fn+0x130/0x130 [ 27.731457] rcu_gp_kthread+0x66c/0xea0 [ 27.731458] ? rcu_gp_kthread+0x66c/0xea0 Because no one has complained about CONFIG_NO_HZ_FULL_ALL=y being broken, I hypothesize that no one is in fact using it, other than rcutorture. This commit therefore eliminates CONFIG_NO_HZ_FULL_ALL and updates rcutorture's config files to instead use the nohz_full= kernel parameter to put the desired CPUs into nohz_full mode. Fixes: 6f1982fedd59 ("sched/isolation: Handle the nohz_full= parameter") Reported-by: kernel test robot Signed-off-by: Paul E. McKenney Cc: Frederic Weisbecker Cc: Thomas Gleixner Cc: Chris Metcalf Cc: Christoph Lameter Cc: Linus Torvalds Cc: Luiz Capitulino Cc: Mike Galbraith Cc: Peter Zijlstra Cc: Rik van Riel Cc: Wanpeng Li Cc: Ingo Molnar Cc: John Stultz Cc: Jonathan Corbet --- Documentation/timers/NO_HZ.txt | 7 ------- kernel/time/Kconfig | 10 ---------- kernel/time/tick-sched.c | 22 ++-------------------- .../selftests/rcutorture/configs/rcu/TASKS03 | 1 - .../selftests/rcutorture/configs/rcu/TASKS03.boot | 2 +- .../selftests/rcutorture/configs/rcu/TREE04 | 1 - .../selftests/rcutorture/configs/rcu/TREE04.boot | 2 +- .../selftests/rcutorture/configs/rcu/TREE07 | 1 - 8 files changed, 4 insertions(+), 42 deletions(-) (limited to 'tools/testing') diff --git a/Documentation/timers/NO_HZ.txt b/Documentation/timers/NO_HZ.txt index 2dcaf9adb7a7..9591092da5e0 100644 --- a/Documentation/timers/NO_HZ.txt +++ b/Documentation/timers/NO_HZ.txt @@ -131,13 +131,6 @@ error message, and the boot CPU will be removed from the mask. Note that this means that your system must have at least two CPUs in order for CONFIG_NO_HZ_FULL=y to do anything for you. -Alternatively, the CONFIG_NO_HZ_FULL_ALL=y Kconfig parameter specifies -that all CPUs other than the boot CPU are adaptive-ticks CPUs. This -Kconfig parameter will be overridden by the "nohz_full=" boot parameter, -so that if both the CONFIG_NO_HZ_FULL_ALL=y Kconfig parameter and -the "nohz_full=1" boot parameter is specified, the boot parameter will -prevail so that only CPU 1 will be an adaptive-ticks CPU. - Finally, adaptive-ticks CPUs must have their RCU callbacks offloaded. This is covered in the "RCU IMPLICATIONS" section below. diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig index f6b5f19223d6..78eabc41eaa6 100644 --- a/kernel/time/Kconfig +++ b/kernel/time/Kconfig @@ -113,16 +113,6 @@ config NO_HZ_FULL endchoice -config NO_HZ_FULL_ALL - bool "Full dynticks system on all CPUs by default (except CPU 0)" - depends on NO_HZ_FULL - help - If the user doesn't pass the nohz_full boot option to - define the range of full dynticks CPUs, consider that all - CPUs in the system are full dynticks by default. - Note the boot CPU will still be kept outside the range to - handle the timekeeping duty. - config NO_HZ bool "Old Idle dynticks config" depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 29a5733eff83..ccd3782da0bf 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -405,30 +405,12 @@ static int tick_nohz_cpu_down(unsigned int cpu) return 0; } -static int tick_nohz_init_all(void) -{ - int err = -1; - -#ifdef CONFIG_NO_HZ_FULL_ALL - if (!alloc_cpumask_var(&tick_nohz_full_mask, GFP_KERNEL)) { - WARN(1, "NO_HZ: Can't allocate full dynticks cpumask\n"); - return err; - } - err = 0; - cpumask_setall(tick_nohz_full_mask); - tick_nohz_full_running = true; -#endif - return err; -} - void __init tick_nohz_init(void) { int cpu, ret; - if (!tick_nohz_full_running) { - if (tick_nohz_init_all() < 0) - return; - } + if (!tick_nohz_full_running) + return; /* * Full dynticks uses irq work to drive the tick rescheduling on safe diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 index c70c51d5ded1..28568b72a31b 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03 @@ -9,5 +9,4 @@ CONFIG_PREEMPT=y CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=n CONFIG_NO_HZ_FULL=y -CONFIG_NO_HZ_FULL_ALL=y #CHECK#CONFIG_RCU_EXPERT=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot index cd2a188eeb6d..838297c58318 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TASKS03.boot @@ -1 +1 @@ -rcutorture.torture_type=tasks +rcutorture.torture_type=tasks nohz_full=1 diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 index 27d22695d64c..24c9f6012e35 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 @@ -7,7 +7,6 @@ CONFIG_PREEMPT=n CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=n CONFIG_NO_HZ_FULL=y -CONFIG_NO_HZ_FULL_ALL=y CONFIG_RCU_FAST_NO_HZ=y CONFIG_RCU_TRACE=y CONFIG_HOTPLUG_CPU=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot index e34c33430447..e6071bb96c7d 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot @@ -1 +1 @@ -rcutorture.torture_type=rcu_bh rcutree.rcu_fanout_leaf=4 +rcutorture.torture_type=rcu_bh rcutree.rcu_fanout_leaf=4 nohz_full=1-7 diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 index 0f4759f4232e..d7afb271a586 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 @@ -7,7 +7,6 @@ CONFIG_PREEMPT=n CONFIG_HZ_PERIODIC=n CONFIG_NO_HZ_IDLE=n CONFIG_NO_HZ_FULL=y -CONFIG_NO_HZ_FULL_ALL=n CONFIG_RCU_FAST_NO_HZ=n CONFIG_RCU_TRACE=y CONFIG_HOTPLUG_CPU=y -- cgit v1.3-14-g43fede From b16ac920403e5623150e428e7f5429e8eb607308 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Thu, 15 Feb 2018 10:49:37 -0800 Subject: selftests/net: add support for PF_RDS sockets Add support for basic PF_RDS client-server testing in msg_zerocopy Signed-off-by: Sowmini Varadhan Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/msg_zerocopy.c | 65 +++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c index e11fe84de0fd..7a5b35362f84 100644 --- a/tools/testing/selftests/net/msg_zerocopy.c +++ b/tools/testing/selftests/net/msg_zerocopy.c @@ -14,6 +14,9 @@ * - SOCK_DGRAM * - SOCK_RAW * + * PF_RDS + * - SOCK_SEQPACKET + * * Start this program on two connected hosts, one in send mode and * the other with option '-r' to put it in receiver mode. * @@ -53,6 +56,7 @@ #include #include #include +#include #ifndef SO_EE_ORIGIN_ZEROCOPY #define SO_EE_ORIGIN_ZEROCOPY 5 @@ -300,10 +304,15 @@ static int do_setup_tx(int domain, int type, int protocol) if (cfg_zerocopy) do_setsockopt(fd, SOL_SOCKET, SO_ZEROCOPY, 1); - if (domain != PF_PACKET) + if (domain != PF_PACKET && domain != PF_RDS) if (connect(fd, (void *) &cfg_dst_addr, cfg_alen)) error(1, errno, "connect"); + if (domain == PF_RDS) { + if (bind(fd, (void *) &cfg_src_addr, cfg_alen)) + error(1, errno, "bind"); + } + return fd; } @@ -444,6 +453,13 @@ static void do_tx(int domain, int type, int protocol) msg.msg_iovlen++; } + if (domain == PF_RDS) { + msg.msg_name = &cfg_dst_addr; + msg.msg_namelen = (cfg_dst_addr.ss_family == AF_INET ? + sizeof(struct sockaddr_in) : + sizeof(struct sockaddr_in6)); + } + iov[2].iov_base = payload; iov[2].iov_len = cfg_payload_len; msg.msg_iovlen++; @@ -555,6 +571,40 @@ static void do_flush_datagram(int fd, int type) bytes += cfg_payload_len; } + +static void do_recvmsg(int fd) +{ + int ret, off = 0; + char *buf; + struct iovec iov; + struct msghdr msg; + struct sockaddr_storage din; + + buf = calloc(cfg_payload_len, sizeof(char)); + iov.iov_base = buf; + iov.iov_len = cfg_payload_len; + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = &din; + msg.msg_namelen = sizeof(din); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + + ret = recvmsg(fd, &msg, MSG_TRUNC); + + if (ret == -1) + error(1, errno, "recv"); + if (ret != cfg_payload_len) + error(1, 0, "recv: ret=%u != %u", ret, cfg_payload_len); + + if (memcmp(buf + off, payload, ret)) + error(1, 0, "recv: data mismatch"); + + free(buf); + packets++; + bytes += cfg_payload_len; +} + static void do_rx(int domain, int type, int protocol) { uint64_t tstop; @@ -566,6 +616,8 @@ static void do_rx(int domain, int type, int protocol) do { if (type == SOCK_STREAM) do_flush_tcp(fd); + else if (domain == PF_RDS) + do_recvmsg(fd); else do_flush_datagram(fd, type); @@ -610,6 +662,7 @@ static void parse_opts(int argc, char **argv) 40 /* max tcp options */; int c; char *daddr = NULL, *saddr = NULL; + char *cfg_test; cfg_payload_len = max_payload_len; @@ -667,6 +720,14 @@ static void parse_opts(int argc, char **argv) break; } } + + cfg_test = argv[argc - 1]; + if (strcmp(cfg_test, "rds") == 0) { + if (!daddr) + error(1, 0, "-D required for PF_RDS\n"); + if (!cfg_rx && !saddr) + error(1, 0, "-S required for PF_RDS\n"); + } setup_sockaddr(cfg_family, daddr, &cfg_dst_addr); setup_sockaddr(cfg_family, saddr, &cfg_src_addr); @@ -699,6 +760,8 @@ int main(int argc, char **argv) do_test(cfg_family, SOCK_STREAM, 0); else if (!strcmp(cfg_test, "udp")) do_test(cfg_family, SOCK_DGRAM, 0); + else if (!strcmp(cfg_test, "rds")) + do_test(PF_RDS, SOCK_SEQPACKET, 0); else error(1, 0, "unknown cfg_test %s", cfg_test); -- cgit v1.3-14-g43fede From dfb8434b0a94651dac7adf373900561d8f6499e4 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Thu, 15 Feb 2018 10:49:38 -0800 Subject: selftests/net: add zerocopy support for PF_RDS test case Send a cookie with sendmsg() on PF_RDS sockets, and process the returned batched cookies in do_recv_completion() Signed-off-by: Sowmini Varadhan Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/msg_zerocopy.c | 68 ++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c index 7a5b35362f84..5cc2a53bb71c 100644 --- a/tools/testing/selftests/net/msg_zerocopy.c +++ b/tools/testing/selftests/net/msg_zerocopy.c @@ -168,17 +168,39 @@ static int do_accept(int fd) return fd; } -static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy) +static void add_zcopy_cookie(struct msghdr *msg, uint32_t cookie) +{ + struct cmsghdr *cm; + + if (!msg->msg_control) + error(1, errno, "NULL cookie"); + cm = (void *)msg->msg_control; + cm->cmsg_len = CMSG_LEN(sizeof(cookie)); + cm->cmsg_level = SOL_RDS; + cm->cmsg_type = RDS_CMSG_ZCOPY_COOKIE; + memcpy(CMSG_DATA(cm), &cookie, sizeof(cookie)); +} + +static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy, int domain) { int ret, len, i, flags; + static uint32_t cookie; + char ckbuf[CMSG_SPACE(sizeof(cookie))]; len = 0; for (i = 0; i < msg->msg_iovlen; i++) len += msg->msg_iov[i].iov_len; flags = MSG_DONTWAIT; - if (do_zerocopy) + if (do_zerocopy) { flags |= MSG_ZEROCOPY; + if (domain == PF_RDS) { + memset(&msg->msg_control, 0, sizeof(msg->msg_control)); + msg->msg_controllen = CMSG_SPACE(sizeof(cookie)); + msg->msg_control = (struct cmsghdr *)ckbuf; + add_zcopy_cookie(msg, ++cookie); + } + } ret = sendmsg(fd, msg, flags); if (ret == -1 && errno == EAGAIN) @@ -194,6 +216,10 @@ static bool do_sendmsg(int fd, struct msghdr *msg, bool do_zerocopy) if (do_zerocopy && ret) expected_completions++; } + if (do_zerocopy && domain == PF_RDS) { + msg->msg_control = NULL; + msg->msg_controllen = 0; + } return true; } @@ -220,7 +246,9 @@ static void do_sendmsg_corked(int fd, struct msghdr *msg) msg->msg_iov[0].iov_len = payload_len + extra_len; extra_len = 0; - do_sendmsg(fd, msg, do_zerocopy); + do_sendmsg(fd, msg, do_zerocopy, + (cfg_dst_addr.ss_family == AF_INET ? + PF_INET : PF_INET6)); } do_setsockopt(fd, IPPROTO_UDP, UDP_CORK, 0); @@ -316,6 +344,26 @@ static int do_setup_tx(int domain, int type, int protocol) return fd; } +static int do_process_zerocopy_cookies(struct sock_extended_err *serr, + uint32_t *ckbuf, size_t nbytes) +{ + int ncookies, i; + + if (serr->ee_errno != 0) + error(1, 0, "serr: wrong error code: %u", serr->ee_errno); + ncookies = serr->ee_data; + if (ncookies > SO_EE_ORIGIN_MAX_ZCOOKIES) + error(1, 0, "Returned %d cookies, max expected %d\n", + ncookies, SO_EE_ORIGIN_MAX_ZCOOKIES); + if (nbytes != ncookies * sizeof(uint32_t)) + error(1, 0, "Expected %d cookies, got %ld\n", + ncookies, nbytes/sizeof(uint32_t)); + for (i = 0; i < ncookies; i++) + if (cfg_verbose >= 2) + fprintf(stderr, "%d\n", ckbuf[i]); + return ncookies; +} + static bool do_recv_completion(int fd) { struct sock_extended_err *serr; @@ -324,10 +372,17 @@ static bool do_recv_completion(int fd) uint32_t hi, lo, range; int ret, zerocopy; char control[100]; + uint32_t ckbuf[SO_EE_ORIGIN_MAX_ZCOOKIES]; + struct iovec iov; msg.msg_control = control; msg.msg_controllen = sizeof(control); + iov.iov_base = ckbuf; + iov.iov_len = (SO_EE_ORIGIN_MAX_ZCOOKIES * sizeof(ckbuf[0])); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + ret = recvmsg(fd, &msg, MSG_ERRQUEUE); if (ret == -1 && errno == EAGAIN) return false; @@ -346,6 +401,11 @@ static bool do_recv_completion(int fd) cm->cmsg_level, cm->cmsg_type); serr = (void *) CMSG_DATA(cm); + + if (serr->ee_origin == SO_EE_ORIGIN_ZCOOKIE) { + completions += do_process_zerocopy_cookies(serr, ckbuf, ret); + return true; + } if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) error(1, 0, "serr: wrong origin: %u", serr->ee_origin); if (serr->ee_errno != 0) @@ -470,7 +530,7 @@ static void do_tx(int domain, int type, int protocol) if (cfg_cork) do_sendmsg_corked(fd, &msg); else - do_sendmsg(fd, &msg, cfg_zerocopy); + do_sendmsg(fd, &msg, cfg_zerocopy, domain); while (!do_poll(fd, POLLOUT)) { if (cfg_zerocopy) -- cgit v1.3-14-g43fede From f4f2cf8bd8e3f6a802b6123bbde795d948560342 Mon Sep 17 00:00:00 2001 From: Lihao Liang Date: Thu, 7 Dec 2017 18:52:22 +0800 Subject: doc: Fix typo in rcutorture documentation Signed-off-by: Lihao Liang Signed-off-by: Paul E. McKenney --- tools/testing/selftests/rcutorture/doc/rcu-test-image.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt b/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt index 66efb59a1bd1..449cf579d6f9 100644 --- a/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt +++ b/tools/testing/selftests/rcutorture/doc/rcu-test-image.txt @@ -1,4 +1,4 @@ -This document describes one way to created the rcu-test-image file +This document describes one way to create the rcu-test-image file that contains the filesystem used by the guest-OS kernel. There are probably much better ways of doing this, and this filesystem could no doubt be smaller. It is probably also possible to simply download -- cgit v1.3-14-g43fede From db92ca3ab8c9aba213cfb3b6aabc95a9afa5d833 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Mon, 11 Dec 2017 08:20:25 -0800 Subject: rcutorture: Update kvm.sh header comment The kvm.sh header comment is a bit of a relic, so this commit brings it up to date. Reported-by: Lihao Liang Signed-off-by: Paul E. McKenney --- tools/testing/selftests/rcutorture/bin/kvm.sh | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 7d1f607f0f76..1fa05132774d 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -1,10 +1,8 @@ #!/bin/bash # -# Run a series of 14 tests under KVM. These are not particularly -# well-selected or well-tuned, but are the current set. -# -# Edit the definitions below to set the locations of the various directories, -# as well as the test duration. +# Run a series of tests under KVM. By default, this series is specified +# by the relevant CFLIST file, but can be overridden by the --configs +# command-line argument. # # Usage: kvm.sh [ options ] # -- cgit v1.3-14-g43fede From 67ad71ddbcae09d891f44d4cd08a9354bc8399b0 Mon Sep 17 00:00:00 2001 From: Lihao Liang Date: Fri, 12 Jan 2018 18:11:32 +0800 Subject: rcutorture: Add basic ARM64 support to run scripts This commit adds support of the qemu command qemu-system-aarch64 to rcutorture. Signed-off-by: Lihao Liang Signed-off-by: Paul E. McKenney --- tools/testing/selftests/rcutorture/bin/functions.sh | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/rcutorture/bin/functions.sh b/tools/testing/selftests/rcutorture/bin/functions.sh index 07a13779eece..65f6655026f0 100644 --- a/tools/testing/selftests/rcutorture/bin/functions.sh +++ b/tools/testing/selftests/rcutorture/bin/functions.sh @@ -136,6 +136,9 @@ identify_boot_image () { qemu-system-x86_64|qemu-system-i386) echo arch/x86/boot/bzImage ;; + qemu-system-aarch64) + echo arch/arm64/boot/Image + ;; *) echo vmlinux ;; @@ -158,6 +161,9 @@ identify_qemu () { elif echo $u | grep -q "Intel 80386" then echo qemu-system-i386 + elif echo $u | grep -q aarch64 + then + echo qemu-system-aarch64 elif uname -a | grep -q ppc64 then echo qemu-system-ppc64 @@ -176,16 +182,20 @@ identify_qemu () { # Output arguments for the qemu "-append" string based on CPU type # and the TORTURE_QEMU_INTERACTIVE environment variable. identify_qemu_append () { + local console=ttyS0 case "$1" in qemu-system-x86_64|qemu-system-i386) echo noapic selinux=0 initcall_debug debug ;; + qemu-system-aarch64) + console=ttyAMA0 + ;; esac if test -n "$TORTURE_QEMU_INTERACTIVE" then echo root=/dev/sda else - echo console=ttyS0 + echo console=$console fi } @@ -197,6 +207,9 @@ identify_qemu_args () { case "$1" in qemu-system-x86_64|qemu-system-i386) ;; + qemu-system-aarch64) + echo -machine virt,gic-version=host -cpu host + ;; qemu-system-ppc64) echo -enable-kvm -M pseries -nodefaults echo -device spapr-vscsi @@ -254,7 +267,7 @@ specify_qemu_cpus () { echo $2 else case "$1" in - qemu-system-x86_64|qemu-system-i386) + qemu-system-x86_64|qemu-system-i386|qemu-system-aarch64) echo $2 -smp $3 ;; qemu-system-ppc64) -- cgit v1.3-14-g43fede From 642146b1ad9bf73b5d1384610d1314d833a560dc Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Fri, 12 Jan 2018 14:19:05 -0800 Subject: torture: Specify qemu memory size with --memory argument The 512 megabyte memory size has served quite well, but more memory is required when using large trace buffers on large systems. This commit therefore adds a --memory argument to the kvm.sh script, which allows the memory size to be specified on the command line, for example, "--memory 768", --memory 800M", or "--memory 2G". Reported-by: Sebastian Siewior Signed-off-by: Paul E. McKenney --- tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh | 4 ++-- tools/testing/selftests/rcutorture/bin/kvm.sh | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 1b78a12740e5..5f8fbb0d7c17 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -177,8 +177,8 @@ then exit 0 fi echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log -echo $QEMU $qemu_args -m 512 -kernel $KERNEL -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd -( $QEMU $qemu_args -m 512 -kernel $KERNEL -append "$qemu_append $boot_args"& echo $! > $resdir/qemu_pid; wait `cat $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) & +echo $QEMU $qemu_args -m $TORTURE_QEMU_MEM -kernel $KERNEL -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd +( $QEMU $qemu_args -m $TORTURE_QEMU_MEM -kernel $KERNEL -append "$qemu_append $boot_args"& echo $! > $resdir/qemu_pid; wait `cat $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) & commandcompleted=0 sleep 10 # Give qemu's pid a chance to reach the file if test -s "$resdir/qemu_pid" diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 1fa05132774d..f3c3d33150a0 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -42,6 +42,7 @@ TORTURE_BOOT_IMAGE="" TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD TORTURE_KCONFIG_ARG="" TORTURE_KMAKE_ARG="" +TORTURE_QEMU_MEM=512 TORTURE_SHUTDOWN_GRACE=180 TORTURE_SUITE=rcu resdir="" @@ -68,6 +69,7 @@ usage () { echo " --kconfig Kconfig-options" echo " --kmake-arg kernel-make-arguments" echo " --mac nn:nn:nn:nn:nn:nn" + echo " --memory megabytes | nnnG" echo " --no-initrd" echo " --qemu-args qemu-arguments" echo " --qemu-cmd qemu-system-..." @@ -145,6 +147,11 @@ do TORTURE_QEMU_MAC=$2 shift ;; + --memory) + checkarg --memory "(memory size)" $# "$2" '^[0-9]\+[MG]\?$' error + TORTURE_QEMU_MEM=$2 + shift + ;; --no-initrd) TORTURE_INITRD=""; export TORTURE_INITRD ;; @@ -286,6 +293,7 @@ TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC +TORTURE_QEMU_MEM="$TORTURE_QEMU_MEM"; export TORTURE_QEMU_MEM TORTURE_SHUTDOWN_GRACE="$TORTURE_SHUTDOWN_GRACE"; export TORTURE_SHUTDOWN_GRACE TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE if ! test -e $resdir -- cgit v1.3-14-g43fede From adcfe76c61732a0dda5116206c3741733491f1e8 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 30 Jan 2018 19:36:38 -0800 Subject: torture: Default jitter off when running rcuperf The purpose of jitter is to expose concurrency bugs due to invalid assumptions about forward progress. There is usually little point in jitter when measuring performance. This commit therefore defaults jitter off when running rcuperf. You can override this by specifying the kvm.sh "--jitter" argument -after- the "--torture rcuperf" argument. No idea why you would want this, but if you do, that is how you do it. One example of a conccurrency bug that this jitter might expose is one in which the developer assumed that a given short region of code would be guaranteed to execute within some short time limit. Such assumptions are invalid in virtualized environments because the hupervisor can preempt the guest OS at any point, even when the guest OS thinks that it has disabled interrupts. Signed-off-by: Paul E. McKenney --- tools/testing/selftests/rcutorture/bin/kvm.sh | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index f3c3d33150a0..56610dbbdf73 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -179,6 +179,12 @@ do checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuperf\)$' '^--' TORTURE_SUITE=$2 shift + if test "$TORTURE_SUITE" = rcuperf + then + # If you really want jitter for rcuperf, specify + # it after specifying rcuperf. (But why?) + jitter=0 + fi ;; *) echo Unknown argument $1 -- cgit v1.3-14-g43fede From cc839ce55d5c2d08bf25f9ddec6d9ee8854b87f4 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 30 Jan 2018 22:44:33 -0800 Subject: torture: Adjust rcuperf trace processing to allow for workqueues The rcuperf event-trace processing assumes that expedited grace periods start and end on the same task, an assumption that was violated by moving expedited grace-period processing to workqueues. This commit removes this now-fallacious assumption from rcuperf's event-trace processing. Signed-off-by: Paul E. McKenney --- .../selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh index 963f71289d22..dffb553a7bcc 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh @@ -39,7 +39,7 @@ sed -e 's/us : / : /' | tr -d '\015' | awk ' $8 == "start" { - if (starttask != "") + if (startseq != "") nlost++; starttask = $1; starttime = $3; @@ -47,17 +47,17 @@ $8 == "start" { } $8 == "end" { - if (starttask == $1 && startseq == $7) { + if (startseq == $7) { curgpdur = $3 - starttime; gptimes[++n] = curgpdur; gptaskcnt[starttask]++; sum += curgpdur; if (curgpdur > 1000) print "Long GP " starttime "us to " $3 "us (" curgpdur "us)"; - starttask = ""; + startseq = ""; } else { # Lost a message or some such, reset. - starttask = ""; + startseq = ""; nlost++; } } -- cgit v1.3-14-g43fede From 0da8c08d71133ba0dd9f5b24ae0b6519e00275d6 Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Tue, 30 Jan 2018 23:12:27 -0800 Subject: torture: Grace periods do not piggyback off of themselves The rcuperf trace-event processing counted every "done" trace event as a piggyback, which is incorrect because the task that started the grace period didn't piggyback at all. This commit fixes this problem by recording the task that started a given grace period and ignoring that task's "done" record for that grace period. Signed-off-by: Paul E. McKenney --- tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh index dffb553a7bcc..8948f7926b21 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh @@ -44,6 +44,7 @@ $8 == "start" { starttask = $1; starttime = $3; startseq = $7; + seqtask[startseq] = starttask; } $8 == "end" { @@ -62,7 +63,7 @@ $8 == "end" { } } -$8 == "done" { +$8 == "done" && seqtask[$7] != $1 { piggybackcnt[$1]++; } -- cgit v1.3-14-g43fede From 85ba6bfe8bb2a4d907f7380a8f37b31616ad694e Mon Sep 17 00:00:00 2001 From: "Paul E. McKenney" Date: Thu, 1 Feb 2018 19:19:04 -0800 Subject: torture: Provide more sensible nreader/nwriter defaults for rcuperf The default values for nreader and nwriter are apparently not all that user-friendly, resulting in people doing scalability tests that ran all runs at large scale. This commit therefore makes both the nreaders and nwriters module default to the number of CPUs, and adds a comment to rcuperf.c stating that the number of CPUs should be specified using the nr_cpus kernel boot parameter. This commit also eliminates the redundant rcuperf scripting specification of default values for these parameters. Signed-off-by: Paul E. McKenney --- kernel/rcu/rcuperf.c | 21 ++++++++++++++++++- .../rcutorture/configs/rcuperf/ver_functions.sh | 24 +--------------------- 2 files changed, 21 insertions(+), 24 deletions(-) (limited to 'tools/testing') diff --git a/kernel/rcu/rcuperf.c b/kernel/rcu/rcuperf.c index d1ebdf9868bb..777e7a6a0292 100644 --- a/kernel/rcu/rcuperf.c +++ b/kernel/rcu/rcuperf.c @@ -61,11 +61,30 @@ MODULE_AUTHOR("Paul E. McKenney "); #define VERBOSE_PERFOUT_ERRSTRING(s) \ do { if (verbose) pr_alert("%s" PERF_FLAG "!!! %s\n", perf_type, s); } while (0) +/* + * The intended use cases for the nreaders and nwriters module parameters + * are as follows: + * + * 1. Specify only the nr_cpus kernel boot parameter. This will + * set both nreaders and nwriters to the value specified by + * nr_cpus for a mixed reader/writer test. + * + * 2. Specify the nr_cpus kernel boot parameter, but set + * rcuperf.nreaders to zero. This will set nwriters to the + * value specified by nr_cpus for an update-only test. + * + * 3. Specify the nr_cpus kernel boot parameter, but set + * rcuperf.nwriters to zero. This will set nreaders to the + * value specified by nr_cpus for a read-only test. + * + * Various other use cases may of course be specified. + */ + torture_param(bool, gp_async, false, "Use asynchronous GP wait primitives"); torture_param(int, gp_async_max, 1000, "Max # outstanding waits per reader"); torture_param(bool, gp_exp, false, "Use expedited GP wait primitives"); torture_param(int, holdoff, 10, "Holdoff time before test start (s)"); -torture_param(int, nreaders, 0, "Number of RCU reader threads"); +torture_param(int, nreaders, -1, "Number of RCU reader threads"); torture_param(int, nwriters, -1, "Number of RCU updater threads"); torture_param(bool, shutdown, !IS_ENABLED(MODULE), "Shutdown at end of performance tests."); diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh index b9603115d7c7..d36b8fd6f0fc 100644 --- a/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh +++ b/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh @@ -20,32 +20,10 @@ # # Authors: Paul E. McKenney -# rcuperf_param_nreaders bootparam-string -# -# Adds nreaders rcuperf module parameter if not already specified. -rcuperf_param_nreaders () { - if ! echo "$1" | grep -q "rcuperf.nreaders" - then - echo rcuperf.nreaders=-1 - fi -} - -# rcuperf_param_nwriters bootparam-string -# -# Adds nwriters rcuperf module parameter if not already specified. -rcuperf_param_nwriters () { - if ! echo "$1" | grep -q "rcuperf.nwriters" - then - echo rcuperf.nwriters=-1 - fi -} - # per_version_boot_params bootparam-string config-file seconds # # Adds per-version torture-module parameters to kernels supporting them. per_version_boot_params () { - echo $1 `rcuperf_param_nreaders "$1"` \ - `rcuperf_param_nwriters "$1"` \ - rcuperf.shutdown=1 \ + echo $1 rcuperf.shutdown=1 \ rcuperf.verbose=1 } -- cgit v1.3-14-g43fede From cc30c93fa020e13c91f5076e20062df33f944cdc Mon Sep 17 00:00:00 2001 From: Willem de Bruijn Date: Fri, 23 Feb 2018 11:56:20 -0500 Subject: selftests/net: ignore background traffic in psock_fanout The packet fanout test generates UDP traffic and reads this with a pair of packet sockets, testing the various fanout algorithms. Avoid non-determinism from reading unrelated background traffic. Fanout decisions are made before unrelated packets can be dropped with a filter, so that is an insufficient strategy [*]. Run the packet socket tests in a network namespace, similar to msg_zerocopy. It it still good practice to install a filter on a packet socket before accepting traffic. Because this is example code, demonstrate that pattern. Open the socket initially bound to no protocol, install a filter, and only then bind to ETH_P_IP. Another source of non-determinism is hash collisions in FANOUT_HASH. The hash function used to select a socket in the fanout group includes the pseudorandom number hashrnd, which is not visible from userspace. To work around this, the test tries to find a pair of UDP source ports that do not collide. It gives up too soon (5 times, every 32 runs) and output is confusing. Increase tries to 20 and revise the error msg. [*] another approach would be to add a third socket to the fanout group and direct all unexpected traffic here. This is possible only when reimplementing methods like RR or HASH alongside this extra catch-all bucket, using the BPF fanout method. Signed-off-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/in_netns.sh | 23 +++++++++++++++++++ tools/testing/selftests/net/psock_fanout.c | 32 ++++++++++++++++++++++----- tools/testing/selftests/net/run_afpackettests | 4 ++-- 3 files changed, 51 insertions(+), 8 deletions(-) create mode 100755 tools/testing/selftests/net/in_netns.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/in_netns.sh b/tools/testing/selftests/net/in_netns.sh new file mode 100755 index 000000000000..f57a2eaad069 --- /dev/null +++ b/tools/testing/selftests/net/in_netns.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Execute a subprocess in a network namespace + +set -e + +readonly NETNS="ns-$(mktemp -u XXXXXX)" + +setup() { + ip netns add "${NETNS}" + ip -netns "${NETNS}" link set lo up +} + +cleanup() { + ip netns del "${NETNS}" +} + +trap cleanup EXIT +setup + +"$@" +exit "$?" diff --git a/tools/testing/selftests/net/psock_fanout.c b/tools/testing/selftests/net/psock_fanout.c index d4346b16b2c1..bd9b9632c72b 100644 --- a/tools/testing/selftests/net/psock_fanout.c +++ b/tools/testing/selftests/net/psock_fanout.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -73,14 +74,29 @@ * @return -1 if mode is bad, a valid socket otherwise */ static int sock_fanout_open(uint16_t typeflags, uint16_t group_id) { + struct sockaddr_ll addr = {0}; int fd, val; - fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); + fd = socket(PF_PACKET, SOCK_RAW, 0); if (fd < 0) { perror("socket packet"); exit(1); } + pair_udp_setfilter(fd); + + addr.sll_family = AF_PACKET; + addr.sll_protocol = htons(ETH_P_IP); + addr.sll_ifindex = if_nametoindex("lo"); + if (addr.sll_ifindex == 0) { + perror("if_nametoindex"); + exit(1); + } + if (bind(fd, (void *) &addr, sizeof(addr))) { + perror("bind packet"); + exit(1); + } + val = (((int) typeflags) << 16) | group_id; if (setsockopt(fd, SOL_PACKET, PACKET_FANOUT, &val, sizeof(val))) { if (close(fd)) { @@ -90,7 +106,6 @@ static int sock_fanout_open(uint16_t typeflags, uint16_t group_id) return -1; } - pair_udp_setfilter(fd); return fd; } @@ -229,7 +244,7 @@ static int sock_fanout_read(int fds[], char *rings[], const int expect[]) if ((!(ret[0] == expect[0] && ret[1] == expect[1])) && (!(ret[0] == expect[1] && ret[1] == expect[0]))) { - fprintf(stderr, "ERROR: incorrect queue lengths\n"); + fprintf(stderr, "warning: incorrect queue lengths\n"); return 1; } @@ -348,7 +363,8 @@ static int test_datapath(uint16_t typeflags, int port_off, uint8_t type = typeflags & 0xFF; int fds[2], fds_udp[2][2], ret; - fprintf(stderr, "test: datapath 0x%hx\n", typeflags); + fprintf(stderr, "\ntest: datapath 0x%hx ports %hu,%hu\n", + typeflags, PORT_BASE, PORT_BASE + port_off); fds[0] = sock_fanout_open(typeflags, 0); fds[1] = sock_fanout_open(typeflags, 0); @@ -419,7 +435,7 @@ int main(int argc, char **argv) const int expect_cpu1[2][2] = { { 0, 20 }, { 0, 20 } }; const int expect_bpf[2][2] = { { 15, 5 }, { 15, 20 } }; const int expect_uniqueid[2][2] = { { 20, 20}, { 20, 20 } }; - int port_off = 2, tries = 5, ret; + int port_off = 2, tries = 20, ret; test_control_single(); test_control_group(); @@ -428,10 +444,14 @@ int main(int argc, char **argv) /* find a set of ports that do not collide onto the same socket */ ret = test_datapath(PACKET_FANOUT_HASH, port_off, expect_hash[0], expect_hash[1]); - while (ret && tries--) { + while (ret) { fprintf(stderr, "info: trying alternate ports (%d)\n", tries); ret = test_datapath(PACKET_FANOUT_HASH, ++port_off, expect_hash[0], expect_hash[1]); + if (!--tries) { + fprintf(stderr, "too many collisions\n"); + return 1; + } } ret |= test_datapath(PACKET_FANOUT_HASH | PACKET_FANOUT_FLAG_ROLLOVER, diff --git a/tools/testing/selftests/net/run_afpackettests b/tools/testing/selftests/net/run_afpackettests index 21fe149e3de1..bea079edc278 100755 --- a/tools/testing/selftests/net/run_afpackettests +++ b/tools/testing/selftests/net/run_afpackettests @@ -9,7 +9,7 @@ fi echo "--------------------" echo "running psock_fanout test" echo "--------------------" -./psock_fanout +./in_netns.sh ./psock_fanout if [ $? -ne 0 ]; then echo "[FAIL]" else @@ -19,7 +19,7 @@ fi echo "--------------------" echo "running psock_tpacket test" echo "--------------------" -./psock_tpacket +./in_netns.sh ./psock_tpacket if [ $? -ne 0 ]; then echo "[FAIL]" else -- cgit v1.3-14-g43fede From ca36960211eb228bcbc7aaebfa0d027368a94c60 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 23 Feb 2018 22:29:05 +0100 Subject: bpf: allow xadd only on aligned memory The requirements around atomic_add() / atomic64_add() resp. their JIT implementations differ across architectures. E.g. while x86_64 seems just fine with BPF's xadd on unaligned memory, on arm64 it triggers via interpreter but also JIT the following crash: [ 830.864985] Unable to handle kernel paging request at virtual address ffff8097d7ed6703 [...] [ 830.916161] Internal error: Oops: 96000021 [#1] SMP [ 830.984755] CPU: 37 PID: 2788 Comm: test_verifier Not tainted 4.16.0-rc2+ #8 [ 830.991790] Hardware name: Huawei TaiShan 2280 /BC11SPCD, BIOS 1.29 07/17/2017 [ 830.998998] pstate: 80400005 (Nzcv daif +PAN -UAO) [ 831.003793] pc : __ll_sc_atomic_add+0x4/0x18 [ 831.008055] lr : ___bpf_prog_run+0x1198/0x1588 [ 831.012485] sp : ffff00001ccabc20 [ 831.015786] x29: ffff00001ccabc20 x28: ffff8017d56a0f00 [ 831.021087] x27: 0000000000000001 x26: 0000000000000000 [ 831.026387] x25: 000000c168d9db98 x24: 0000000000000000 [ 831.031686] x23: ffff000008203878 x22: ffff000009488000 [ 831.036986] x21: ffff000008b14e28 x20: ffff00001ccabcb0 [ 831.042286] x19: ffff0000097b5080 x18: 0000000000000a03 [ 831.047585] x17: 0000000000000000 x16: 0000000000000000 [ 831.052885] x15: 0000ffffaeca8000 x14: 0000000000000000 [ 831.058184] x13: 0000000000000000 x12: 0000000000000000 [ 831.063484] x11: 0000000000000001 x10: 0000000000000000 [ 831.068783] x9 : 0000000000000000 x8 : 0000000000000000 [ 831.074083] x7 : 0000000000000000 x6 : 000580d428000000 [ 831.079383] x5 : 0000000000000018 x4 : 0000000000000000 [ 831.084682] x3 : ffff00001ccabcb0 x2 : 0000000000000001 [ 831.089982] x1 : ffff8097d7ed6703 x0 : 0000000000000001 [ 831.095282] Process test_verifier (pid: 2788, stack limit = 0x0000000018370044) [ 831.102577] Call trace: [ 831.105012] __ll_sc_atomic_add+0x4/0x18 [ 831.108923] __bpf_prog_run32+0x4c/0x70 [ 831.112748] bpf_test_run+0x78/0xf8 [ 831.116224] bpf_prog_test_run_xdp+0xb4/0x120 [ 831.120567] SyS_bpf+0x77c/0x1110 [ 831.123873] el0_svc_naked+0x30/0x34 [ 831.127437] Code: 97fffe97 17ffffec 00000000 f9800031 (885f7c31) Reason for this is because memory is required to be aligned. In case of BPF, we always enforce alignment in terms of stack access, but not when accessing map values or packet data when the underlying arch (e.g. arm64) has CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS set. xadd on packet data that is local to us anyway is just wrong, so forbid this case entirely. The only place where xadd makes sense in fact are map values; xadd on stack is wrong as well, but it's been around for much longer. Specifically enforce strict alignment in case of xadd, so that we handle this case generically and avoid such crashes in the first place. Fixes: 17a5267067f3 ("bpf: verifier (add verifier core)") Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 42 +++++++++++++-------- tools/testing/selftests/bpf/test_verifier.c | 58 +++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 16 deletions(-) (limited to 'tools/testing') diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 5fb69a85d967..c6eff108aa99 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1356,6 +1356,13 @@ static bool is_ctx_reg(struct bpf_verifier_env *env, int regno) return reg->type == PTR_TO_CTX; } +static bool is_pkt_reg(struct bpf_verifier_env *env, int regno) +{ + const struct bpf_reg_state *reg = cur_regs(env) + regno; + + return type_is_pkt_pointer(reg->type); +} + static int check_pkt_ptr_alignment(struct bpf_verifier_env *env, const struct bpf_reg_state *reg, int off, int size, bool strict) @@ -1416,10 +1423,10 @@ static int check_generic_ptr_alignment(struct bpf_verifier_env *env, } static int check_ptr_alignment(struct bpf_verifier_env *env, - const struct bpf_reg_state *reg, - int off, int size) + const struct bpf_reg_state *reg, int off, + int size, bool strict_alignment_once) { - bool strict = env->strict_alignment; + bool strict = env->strict_alignment || strict_alignment_once; const char *pointer_desc = ""; switch (reg->type) { @@ -1576,9 +1583,9 @@ static void coerce_reg_to_size(struct bpf_reg_state *reg, int size) * if t==write && value_regno==-1, some unknown value is stored into memory * if t==read && value_regno==-1, don't care what we read from memory */ -static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno, int off, - int bpf_size, enum bpf_access_type t, - int value_regno) +static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regno, + int off, int bpf_size, enum bpf_access_type t, + int value_regno, bool strict_alignment_once) { struct bpf_reg_state *regs = cur_regs(env); struct bpf_reg_state *reg = regs + regno; @@ -1590,7 +1597,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn return size; /* alignment checks will add in reg->off themselves */ - err = check_ptr_alignment(env, reg, off, size); + err = check_ptr_alignment(env, reg, off, size, strict_alignment_once); if (err) return err; @@ -1735,21 +1742,23 @@ static int check_xadd(struct bpf_verifier_env *env, int insn_idx, struct bpf_ins return -EACCES; } - if (is_ctx_reg(env, insn->dst_reg)) { - verbose(env, "BPF_XADD stores into R%d context is not allowed\n", - insn->dst_reg); + if (is_ctx_reg(env, insn->dst_reg) || + is_pkt_reg(env, insn->dst_reg)) { + verbose(env, "BPF_XADD stores into R%d %s is not allowed\n", + insn->dst_reg, is_ctx_reg(env, insn->dst_reg) ? + "context" : "packet"); return -EACCES; } /* check whether atomic_add can read the memory */ err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, - BPF_SIZE(insn->code), BPF_READ, -1); + BPF_SIZE(insn->code), BPF_READ, -1, true); if (err) return err; /* check whether atomic_add can write into the same memory */ return check_mem_access(env, insn_idx, insn->dst_reg, insn->off, - BPF_SIZE(insn->code), BPF_WRITE, -1); + BPF_SIZE(insn->code), BPF_WRITE, -1, true); } /* when register 'regno' is passed into function that will read 'access_size' @@ -2388,7 +2397,8 @@ static int check_helper_call(struct bpf_verifier_env *env, int func_id, int insn * is inferred from register state. */ for (i = 0; i < meta.access_size; i++) { - err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B, BPF_WRITE, -1); + err = check_mem_access(env, insn_idx, meta.regno, i, BPF_B, + BPF_WRITE, -1, false); if (err) return err; } @@ -4632,7 +4642,7 @@ static int do_check(struct bpf_verifier_env *env) */ err = check_mem_access(env, insn_idx, insn->src_reg, insn->off, BPF_SIZE(insn->code), BPF_READ, - insn->dst_reg); + insn->dst_reg, false); if (err) return err; @@ -4684,7 +4694,7 @@ static int do_check(struct bpf_verifier_env *env) /* check that memory (dst_reg + off) is writeable */ err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, BPF_SIZE(insn->code), BPF_WRITE, - insn->src_reg); + insn->src_reg, false); if (err) return err; @@ -4719,7 +4729,7 @@ static int do_check(struct bpf_verifier_env *env) /* check that memory (dst_reg + off) is writeable */ err = check_mem_access(env, insn_idx, insn->dst_reg, insn->off, BPF_SIZE(insn->code), BPF_WRITE, - -1); + -1, false); if (err) return err; diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index c73592fa3d41..437c0b1c9d21 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -11163,6 +11163,64 @@ static struct bpf_test tests[] = { .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, + { + "xadd/w check unaligned stack", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_STX_MEM(BPF_DW, BPF_REG_10, BPF_REG_0, -8), + BPF_STX_XADD(BPF_W, BPF_REG_10, BPF_REG_0, -7), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -8), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "misaligned stack access off", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { + "xadd/w check unaligned map", + .insns = { + BPF_ST_MEM(BPF_DW, BPF_REG_10, -8, 0), + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), + BPF_LD_MAP_FD(BPF_REG_1, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_map_lookup_elem), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + BPF_MOV64_IMM(BPF_REG_1, 1), + BPF_STX_XADD(BPF_W, BPF_REG_0, BPF_REG_1, 3), + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 3), + BPF_EXIT_INSN(), + }, + .fixup_map1 = { 3 }, + .result = REJECT, + .errstr = "misaligned value access off", + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + }, + { + "xadd/w check unaligned pkt", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, + offsetof(struct xdp_md, data)), + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, + offsetof(struct xdp_md, data_end)), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 8), + BPF_JMP_REG(BPF_JLT, BPF_REG_1, BPF_REG_3, 2), + BPF_MOV64_IMM(BPF_REG_0, 99), + BPF_JMP_IMM(BPF_JA, 0, 0, 6), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_ST_MEM(BPF_W, BPF_REG_2, 0, 0), + BPF_ST_MEM(BPF_W, BPF_REG_2, 3, 0), + BPF_STX_XADD(BPF_W, BPF_REG_2, BPF_REG_0, 1), + BPF_STX_XADD(BPF_W, BPF_REG_2, BPF_REG_0, 2), + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_2, 1), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "BPF_XADD stores into R2 packet", + .prog_type = BPF_PROG_TYPE_XDP, + }, }; static int probe_filter_length(const struct bpf_insn *fp) -- cgit v1.3-14-g43fede From 23d191a82c133c31bb85aa4b4b26851cd4a4b4ac Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Sat, 24 Feb 2018 01:08:03 +0100 Subject: bpf: add various jit test cases Add few test cases that check the rnu-time results under JIT. Signed-off-by: Daniel Borkmann Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 89 +++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 2971ba2829ac..c987d3a2426f 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -11140,6 +11140,95 @@ static struct bpf_test tests[] = { .result = REJECT, .prog_type = BPF_PROG_TYPE_TRACEPOINT, }, + { + "jit: lsh, rsh, arsh by 1", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_MOV64_IMM(BPF_REG_1, 0xff), + BPF_ALU64_IMM(BPF_LSH, BPF_REG_1, 1), + BPF_ALU32_IMM(BPF_LSH, BPF_REG_1, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0x3fc, 1), + BPF_EXIT_INSN(), + BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 1), + BPF_ALU32_IMM(BPF_RSH, BPF_REG_1, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0xff, 1), + BPF_EXIT_INSN(), + BPF_ALU64_IMM(BPF_ARSH, BPF_REG_1, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_1, 0x7f, 1), + BPF_EXIT_INSN(), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .retval = 2, + }, + { + "jit: mov32 for ldimm64, 1", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_LD_IMM64(BPF_REG_1, 0xfeffffffffffffffULL), + BPF_ALU64_IMM(BPF_RSH, BPF_REG_1, 32), + BPF_LD_IMM64(BPF_REG_2, 0xfeffffffULL), + BPF_JMP_REG(BPF_JEQ, BPF_REG_1, BPF_REG_2, 1), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .retval = 2, + }, + { + "jit: mov32 for ldimm64, 2", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_LD_IMM64(BPF_REG_1, 0x1ffffffffULL), + BPF_LD_IMM64(BPF_REG_2, 0xffffffffULL), + BPF_JMP_REG(BPF_JEQ, BPF_REG_1, BPF_REG_2, 1), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .retval = 2, + }, + { + "jit: various mul tests", + .insns = { + BPF_LD_IMM64(BPF_REG_2, 0xeeff0d413122ULL), + BPF_LD_IMM64(BPF_REG_0, 0xfefefeULL), + BPF_LD_IMM64(BPF_REG_1, 0xefefefULL), + BPF_ALU64_REG(BPF_MUL, BPF_REG_0, BPF_REG_1), + BPF_JMP_REG(BPF_JEQ, BPF_REG_0, BPF_REG_2, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_LD_IMM64(BPF_REG_3, 0xfefefeULL), + BPF_ALU64_REG(BPF_MUL, BPF_REG_3, BPF_REG_1), + BPF_JMP_REG(BPF_JEQ, BPF_REG_3, BPF_REG_2, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_MOV32_REG(BPF_REG_2, BPF_REG_2), + BPF_LD_IMM64(BPF_REG_0, 0xfefefeULL), + BPF_ALU32_REG(BPF_MUL, BPF_REG_0, BPF_REG_1), + BPF_JMP_REG(BPF_JEQ, BPF_REG_0, BPF_REG_2, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_LD_IMM64(BPF_REG_3, 0xfefefeULL), + BPF_ALU32_REG(BPF_MUL, BPF_REG_3, BPF_REG_1), + BPF_JMP_REG(BPF_JEQ, BPF_REG_3, BPF_REG_2, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_LD_IMM64(BPF_REG_0, 0x952a7bbcULL), + BPF_LD_IMM64(BPF_REG_1, 0xfefefeULL), + BPF_LD_IMM64(BPF_REG_2, 0xeeff0d413122ULL), + BPF_ALU32_REG(BPF_MUL, BPF_REG_2, BPF_REG_1), + BPF_JMP_REG(BPF_JEQ, BPF_REG_2, BPF_REG_0, 2), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .retval = 2, + }, + }; static int probe_filter_length(const struct bpf_insn *fp) -- cgit v1.3-14-g43fede From 192b2e742c06af399e8eecb4a1726520bfccece8 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 26 Feb 2018 13:17:07 +1100 Subject: selftests/powerpc: Skip tm-trap if transactional memory is not enabled Some processor revisions do not support transactional memory, and additionally kernel support can be disabled. In either case the tm-trap test should be skipped, otherwise it will fail with a SIGILL. Fixes: a08082f8e4e1 ("powerpc/selftests: Check endianness on trap in TM") Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/tm-trap.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/powerpc/tm/tm-trap.c b/tools/testing/selftests/powerpc/tm/tm-trap.c index 5d92c23ee6cb..179d592f0073 100644 --- a/tools/testing/selftests/powerpc/tm/tm-trap.c +++ b/tools/testing/selftests/powerpc/tm/tm-trap.c @@ -255,6 +255,8 @@ int tm_trap_test(void) struct sigaction trap_sa; + SKIP_IF(!have_htm()); + trap_sa.sa_flags = SA_SIGINFO; trap_sa.sa_sigaction = trap_signal_handler; sigaction(SIGTRAP, &trap_sa, NULL); -- cgit v1.3-14-g43fede From 6a7b75f7c16d85f782ae86c71f0f31f72a61602f Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Fri, 23 Feb 2018 12:16:37 -0500 Subject: tools: tc-testing: Fix indentation Signed-off-by: Brenda J. Butler Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index b3754b9aa302..ab28373dccd7 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -347,9 +347,9 @@ def check_default_settings(args, remaining, pm): global NAMES if args.path != None: - NAMES['TC'] = args.path + NAMES['TC'] = args.path if args.device != None: - NAMES['DEV2'] = args.device + NAMES['DEV2'] = args.device if not os.path.isfile(NAMES['TC']): print("The specified tc path " + NAMES['TC'] + " does not exist.") exit(1) -- cgit v1.3-14-g43fede From f9b63a1c91d4d2b4fcac5c786cdd7de1242c162b Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Fri, 23 Feb 2018 12:16:38 -0500 Subject: tools: tc-testing: better error reporting Do a better job with error handling - in pre- and post-suite, in pre- and post-case. Show a traceback for errors. Signed-off-by: Brenda J. Butler Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 84 +++++++++++++++++++++++++------ 1 file changed, 70 insertions(+), 14 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index ab28373dccd7..6c220bc26d9f 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -15,6 +15,7 @@ import importlib import json import subprocess import time +import traceback from collections import OrderedDict from string import Template @@ -23,6 +24,13 @@ from tdc_helper import * import TdcPlugin + +class PluginMgrTestFail(Exception): + def __init__(self, stage, output, message): + self.stage = stage + self.output = output + self.message = message + class PluginMgr: def __init__(self, argparser): super().__init__() @@ -135,7 +143,7 @@ def exec_cmd(args, pm, stage, command): return proc, foutput -def prepare_env(args, pm, stage, prefix, cmdlist): +def prepare_env(args, pm, stage, prefix, cmdlist, output = None): """ Execute the setup/teardown commands for a test case. Optionally terminate test execution if the command fails. @@ -164,7 +172,9 @@ def prepare_env(args, pm, stage, prefix, cmdlist): print("\n{} *** Aborting test run.".format(prefix), file=sys.stderr) print("\n\n{} *** stdout ***".format(proc.stdout), file=sys.stderr) print("\n\n{} *** stderr ***".format(proc.stderr), file=sys.stderr) - raise Exception('"{}" did not complete successfully'.format(prefix)) + raise PluginMgrTestFail( + stage, output, + '"{}" did not complete successfully'.format(prefix)) def run_one_test(pm, args, index, tidx): result = True @@ -194,8 +204,11 @@ def run_one_test(pm, args, index, tidx): match_pattern = re.compile( str(tidx["matchPattern"]), re.DOTALL | re.MULTILINE) (p, procout) = exec_cmd(args, pm, 'verify', tidx["verifyCmd"]) - match_index = re.findall(match_pattern, procout) - if len(match_index) != int(tidx["matchCount"]): + if procout: + match_index = re.findall(match_pattern, procout) + if len(match_index) != int(tidx["matchCount"]): + result = False + elif int(tidx["matchCount"]) != 0: result = False if not result: @@ -204,9 +217,12 @@ def run_one_test(pm, args, index, tidx): tap += tresult if result == False: - tap += procout + if procout: + tap += procout + else: + tap += 'No output!\n' - prepare_env(args, pm, 'teardown', '-----> teardown stage', tidx['teardown']) + prepare_env(args, pm, 'teardown', '-----> teardown stage', tidx['teardown'], procout) pm.call_post_case() index += 1 @@ -227,30 +243,70 @@ def test_runner(pm, args, filtered_tests): index = 1 tap = str(index) + ".." + str(tcount) + "\n" badtest = None + stage = None + emergency_exit = False + emergency_exit_message = '' - pm.call_pre_suite(tcount, [tidx['id'] for tidx in testlist]) - + try: + pm.call_pre_suite(tcount, [tidx['id'] for tidx in testlist]) + except Exception as ee: + ex_type, ex, ex_tb = sys.exc_info() + print('Exception {} {} (caught in pre_suite).'. + format(ex_type, ex)) + # when the extra print statements are uncommented, + # the traceback does not appear between them + # (it appears way earlier in the tdc.py output) + # so don't bother ... + # print('--------------------(') + # print('traceback') + traceback.print_tb(ex_tb) + # print('--------------------)') + emergency_exit_message = 'EMERGENCY EXIT, call_pre_suite failed with exception {} {}\n'.format(ex_type, ex) + emergency_exit = True + stage = 'pre-SUITE' + + if emergency_exit: + pm.call_post_suite(index) + return emergency_exit_message if args.verbose > 1: - print('Run tests here') + print('give test rig 2 seconds to stabilize') + time.sleep(2) for tidx in testlist: if "flower" in tidx["category"] and args.device == None: + if args.verbose > 1: + print('Not executing test {} {} because DEV2 not defined'. + format(tidx['id'], tidx['name'])) continue try: badtest = tidx # in case it goes bad tap += run_one_test(pm, args, index, tidx) - except Exception as ee: - print('Exception {} (caught in test_runner, running test {} {} {})'. - format(ee, index, tidx['id'], tidx['name'])) + except PluginMgrTestFail as pmtf: + ex_type, ex, ex_tb = sys.exc_info() + stage = pmtf.stage + message = pmtf.message + output = pmtf.output + print(message) + print('Exception {} {} (caught in test_runner, running test {} {} {} stage {})'. + format(ex_type, ex, index, tidx['id'], tidx['name'], stage)) + print('---------------') + print('traceback') + traceback.print_tb(ex_tb) + print('---------------') + if stage == 'teardown': + print('accumulated output for this test:') + if pmtf.output: + print(pmtf.output) + print('---------------') break index += 1 # if we failed in setup or teardown, - # fill in the remaining tests with not ok + # fill in the remaining tests with ok-skipped count = index tap += 'about to flush the tap output if tests need to be skipped\n' if tcount + 1 != index: for tidx in testlist[index - 1:]: - msg = 'skipped - previous setup or teardown failed' + msg = 'skipped - previous {} failed'.format(stage) tap += 'ok {} - {} # {} {} {}\n'.format( count, tidx['id'], msg, index, badtest.get('id', '--Unknown--')) count += 1 -- cgit v1.3-14-g43fede From 3adc1c63e288c3f60b1bdee461a0b15447901bcc Mon Sep 17 00:00:00 2001 From: BTaskaya Date: Fri, 23 Feb 2018 22:57:35 +0300 Subject: tc: python3, string formattings This patch converts old type string formattings to new type string formattings for adapting Linux Traffic Control (tc) unit testing suite python3. Linux Traffic Control (tc) unit testing suite's code quality improved is improved with this patch. According to python documentation; "The built-in string class provides the ability to do complex variable substitutions and value formatting via the format() method described in PEP 3101. " but the project was using old type formattings and new type string formattings together, this patch's main purpose is converting all old types to new types. Following files changed: 1. tools/testing/selftests/tc-testing/tdc.py 2. tools/testing/selftests/tc-testing/tdc_batch.py Following PEP rules applied: 1. PEP8 - Code Styling 2. PEP3101 - Advanced Code Formatting Signed-off-by: Batuhan Osman Taskaya Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 2 +- tools/testing/selftests/tc-testing/tdc_batch.py | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 6c220bc26d9f..7b50775abaf6 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -445,7 +445,7 @@ def generate_case_ids(alltests): for c in alltests: if (c["id"] == ""): while True: - newid = str('%04x' % random.randrange(16**4)) + newid = str('{:04x}'.format(random.randrange(16**4))) if (does_id_exist(alltests, newid)): continue else: diff --git a/tools/testing/selftests/tc-testing/tdc_batch.py b/tools/testing/selftests/tc-testing/tdc_batch.py index 707c6bfef689..52fa539dc662 100755 --- a/tools/testing/selftests/tc-testing/tdc_batch.py +++ b/tools/testing/selftests/tc-testing/tdc_batch.py @@ -49,13 +49,13 @@ index = 0 for i in range(0x100): for j in range(0x100): for k in range(0x100): - mac = ("%02x:%02x:%02x" % (i, j, k)) + mac = ("{:02x}:{:02x}:{:02x}".format(i, j, k)) src_mac = "e4:11:00:" + mac dst_mac = "e4:12:00:" + mac - cmd = ("filter add dev %s %s protocol ip parent ffff: flower %s " - "src_mac %s dst_mac %s action drop %s" % + cmd = ("filter add dev {} {} protocol ip parent ffff: flower {} " + "src_mac {} dst_mac {} action drop {}".format (device, prio, skip, src_mac, dst_mac, share_action)) - file.write("%s\n" % cmd) + file.write("{}\n".format(cmd)) index += 1 if index >= number: file.close() -- cgit v1.3-14-g43fede From fe8d662aef26394388bfcd3b96ce123b6d33044b Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 26 Feb 2018 22:34:32 +0100 Subject: bpf: unify rlimit handling in selftests Unify memlock handling into bpf_rlimit.h and replace all occurences in BPF kselftests with it. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/bpf_rlimit.h | 28 +++++++++++++++++++++++++ tools/testing/selftests/bpf/test_align.c | 6 +----- tools/testing/selftests/bpf/test_dev_cgroup.c | 6 +----- tools/testing/selftests/bpf/test_lpm_map.c | 14 +++---------- tools/testing/selftests/bpf/test_lru_map.c | 6 ++---- tools/testing/selftests/bpf/test_maps.c | 7 ++----- tools/testing/selftests/bpf/test_progs.c | 7 ++----- tools/testing/selftests/bpf/test_tag.c | 4 +--- tools/testing/selftests/bpf/test_tcpbpf_user.c | 6 +----- tools/testing/selftests/bpf/test_verifier.c | 6 +----- tools/testing/selftests/bpf/test_verifier_log.c | 8 ++----- 11 files changed, 44 insertions(+), 54 deletions(-) create mode 100644 tools/testing/selftests/bpf/bpf_rlimit.h (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/bpf_rlimit.h b/tools/testing/selftests/bpf/bpf_rlimit.h new file mode 100644 index 000000000000..9dac9b30f8ef --- /dev/null +++ b/tools/testing/selftests/bpf/bpf_rlimit.h @@ -0,0 +1,28 @@ +#include +#include + +static __attribute__((constructor)) void bpf_rlimit_ctor(void) +{ + struct rlimit rlim_old, rlim_new = { + .rlim_cur = RLIM_INFINITY, + .rlim_max = RLIM_INFINITY, + }; + + getrlimit(RLIMIT_MEMLOCK, &rlim_old); + /* For the sake of running the test cases, we temporarily + * set rlimit to infinity in order for kernel to focus on + * errors from actual test cases and not getting noise + * from hitting memlock limits. The limit is on per-process + * basis and not a global one, hence destructor not really + * needed here. + */ + if (setrlimit(RLIMIT_MEMLOCK, &rlim_new) < 0) { + perror("Unable to lift memlock rlimit"); + /* Trying out lower limit, but expect potential test + * case failures from this! + */ + rlim_new.rlim_cur = rlim_old.rlim_cur + (1UL << 20); + rlim_new.rlim_max = rlim_old.rlim_max + (1UL << 20); + setrlimit(RLIMIT_MEMLOCK, &rlim_new); + } +} diff --git a/tools/testing/selftests/bpf/test_align.c b/tools/testing/selftests/bpf/test_align.c index ff8bd7e3e50c..6b1b302310fe 100644 --- a/tools/testing/selftests/bpf/test_align.c +++ b/tools/testing/selftests/bpf/test_align.c @@ -9,8 +9,6 @@ #include #include -#include - #include #include #include @@ -19,6 +17,7 @@ #include #include "../../../include/linux/filter.h" +#include "bpf_rlimit.h" #ifndef ARRAY_SIZE # define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) @@ -702,9 +701,6 @@ static int do_test(unsigned int from, unsigned int to) int main(int argc, char **argv) { unsigned int from = 0, to = ARRAY_SIZE(tests); - struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; - - setrlimit(RLIMIT_MEMLOCK, &rinf); if (argc == 3) { unsigned int l = atoi(argv[argc - 2]); diff --git a/tools/testing/selftests/bpf/test_dev_cgroup.c b/tools/testing/selftests/bpf/test_dev_cgroup.c index 3489cc283433..9c8b50bac7e0 100644 --- a/tools/testing/selftests/bpf/test_dev_cgroup.c +++ b/tools/testing/selftests/bpf/test_dev_cgroup.c @@ -11,13 +11,13 @@ #include #include #include -#include #include #include #include #include "cgroup_helpers.h" +#include "bpf_rlimit.h" #define DEV_CGROUP_PROG "./dev_cgroup.o" @@ -25,15 +25,11 @@ int main(int argc, char **argv) { - struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; struct bpf_object *obj; int error = EXIT_FAILURE; int prog_fd, cgroup_fd; __u32 prog_cnt; - if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0) - perror("Unable to lift memlock rlimit"); - if (bpf_prog_load(DEV_CGROUP_PROG, BPF_PROG_TYPE_CGROUP_DEVICE, &obj, &prog_fd)) { printf("Failed to load DEV_CGROUP program\n"); diff --git a/tools/testing/selftests/bpf/test_lpm_map.c b/tools/testing/selftests/bpf/test_lpm_map.c index 2be87e9ee28d..147e34cfceb7 100644 --- a/tools/testing/selftests/bpf/test_lpm_map.c +++ b/tools/testing/selftests/bpf/test_lpm_map.c @@ -22,10 +22,11 @@ #include #include #include -#include #include + #include "bpf_util.h" +#include "bpf_rlimit.h" struct tlpm_node { struct tlpm_node *next; @@ -736,17 +737,11 @@ static void test_lpm_multi_thread(void) int main(void) { - struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; - int i, ret; + int i; /* we want predictable, pseudo random tests */ srand(0xf00ba1); - /* allow unlimited locked memory */ - ret = setrlimit(RLIMIT_MEMLOCK, &limit); - if (ret < 0) - perror("Unable to lift memlock rlimit"); - test_lpm_basic(); test_lpm_order(); @@ -755,11 +750,8 @@ int main(void) test_lpm_map(i); test_lpm_ipaddr(); - test_lpm_delete(); - test_lpm_get_next_key(); - test_lpm_multi_thread(); printf("test_lpm: OK\n"); diff --git a/tools/testing/selftests/bpf/test_lru_map.c b/tools/testing/selftests/bpf/test_lru_map.c index 8c10c9180c1a..781c7de343be 100644 --- a/tools/testing/selftests/bpf/test_lru_map.c +++ b/tools/testing/selftests/bpf/test_lru_map.c @@ -16,10 +16,11 @@ #include #include -#include #include + #include "bpf_util.h" +#include "bpf_rlimit.h" #define LOCAL_FREE_TARGET (128) #define PERCPU_FREE_TARGET (4) @@ -613,7 +614,6 @@ static void test_lru_sanity6(int map_type, int map_flags, int tgt_free) int main(int argc, char **argv) { - struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; int map_types[] = {BPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH}; int map_flags[] = {0, BPF_F_NO_COMMON_LRU}; @@ -621,8 +621,6 @@ int main(int argc, char **argv) setbuf(stdout, NULL); - assert(!setrlimit(RLIMIT_MEMLOCK, &r)); - nr_cpus = bpf_num_possible_cpus(); assert(nr_cpus != -1); printf("nr_cpus:%d\n\n", nr_cpus); diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 9e03a4c356a4..1238733c5b33 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -17,13 +17,14 @@ #include #include -#include #include #include #include + #include "bpf_util.h" +#include "bpf_rlimit.h" static int map_flags; @@ -1126,10 +1127,6 @@ static void run_all_tests(void) int main(void) { - struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; - - setrlimit(RLIMIT_MEMLOCK, &rinf); - map_flags = 0; run_all_tests(); diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index b549308abd19..27ad5404389e 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -26,7 +26,6 @@ typedef __u16 __sum16; #include #include -#include #include #include @@ -34,9 +33,11 @@ typedef __u16 __sum16; #include #include #include + #include "test_iptunnel_common.h" #include "bpf_util.h" #include "bpf_endian.h" +#include "bpf_rlimit.h" static int error_cnt, pass_cnt; @@ -965,10 +966,6 @@ out: int main(void) { - struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; - - setrlimit(RLIMIT_MEMLOCK, &rinf); - test_pkt_access(); test_xdp(); test_l4lb_all(); diff --git a/tools/testing/selftests/bpf/test_tag.c b/tools/testing/selftests/bpf/test_tag.c index 8b201895c569..6272c784ca2a 100644 --- a/tools/testing/selftests/bpf/test_tag.c +++ b/tools/testing/selftests/bpf/test_tag.c @@ -12,7 +12,6 @@ #include #include -#include #include #include @@ -21,6 +20,7 @@ #include #include "../../../include/linux/filter.h" +#include "bpf_rlimit.h" static struct bpf_insn prog[BPF_MAXINSNS]; @@ -184,11 +184,9 @@ static void do_test(uint32_t *tests, int start_insns, int fd_map, int main(void) { - struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; uint32_t tests = 0; int i, fd_map; - setrlimit(RLIMIT_MEMLOCK, &rinf); fd_map = bpf_create_map(BPF_MAP_TYPE_HASH, sizeof(int), sizeof(int), 1, BPF_F_NO_PREALLOC); assert(fd_map > 0); diff --git a/tools/testing/selftests/bpf/test_tcpbpf_user.c b/tools/testing/selftests/bpf/test_tcpbpf_user.c index 5d73db416460..84ab5163c828 100644 --- a/tools/testing/selftests/bpf/test_tcpbpf_user.c +++ b/tools/testing/selftests/bpf/test_tcpbpf_user.c @@ -12,13 +12,13 @@ #include #include #include -#include #include #include #include #include #include #include "bpf_util.h" +#include "bpf_rlimit.h" #include #include "test_tcpbpf.h" @@ -44,7 +44,6 @@ static int bpf_find_map(const char *test, struct bpf_object *obj, int main(int argc, char **argv) { - struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; const char *file = "test_tcpbpf_kern.o"; struct tcpbpf_globals g = {0}; int cg_fd, prog_fd, map_fd; @@ -57,9 +56,6 @@ int main(int argc, char **argv) int pid; int rv; - if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0) - perror("Unable to lift memlock rlimit"); - if (argc > 1 && strcmp(argv[1], "-d") == 0) debug_flag = true; diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 2164d218322e..bd3a08c7cc15 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -24,7 +24,6 @@ #include #include -#include #include #include @@ -41,7 +40,7 @@ # define CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS 1 # endif #endif - +#include "bpf_rlimit.h" #include "../../../include/linux/filter.h" #ifndef ARRAY_SIZE @@ -11543,8 +11542,6 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) int main(int argc, char **argv) { - struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY }; - struct rlimit rlim = { 1 << 20, 1 << 20 }; unsigned int from = 0, to = ARRAY_SIZE(tests); bool unpriv = !is_admin(); @@ -11572,6 +11569,5 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - setrlimit(RLIMIT_MEMLOCK, unpriv ? &rlim : &rinf); return do_test(unpriv, from, to); } diff --git a/tools/testing/selftests/bpf/test_verifier_log.c b/tools/testing/selftests/bpf/test_verifier_log.c index e9626cf5607a..8d6918c3b4a2 100644 --- a/tools/testing/selftests/bpf/test_verifier_log.c +++ b/tools/testing/selftests/bpf/test_verifier_log.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -12,6 +11,8 @@ #include +#include "bpf_rlimit.h" + #define LOG_SIZE (1 << 20) #define err(str...) printf("ERROR: " str) @@ -133,16 +134,11 @@ static void test_log_bad(char *log, size_t log_len, int log_level) int main(int argc, char **argv) { - struct rlimit limit = { RLIM_INFINITY, RLIM_INFINITY }; char full_log[LOG_SIZE]; char log[LOG_SIZE]; size_t want_len; int i; - /* allow unlimited locked memory to have more consistent error code */ - if (setrlimit(RLIMIT_MEMLOCK, &limit) < 0) - perror("Unable to lift memlock rlimit"); - memset(log, 1, LOG_SIZE); /* Test incorrect attr */ -- cgit v1.3-14-g43fede From b33eb735836224e55cd8182aff9bbb7ddc17f38b Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 26 Feb 2018 22:34:33 +0100 Subject: bpf: add tail call tests to test_verifier One of the downsides of the test_bpf module was that since being in kernel space, it couldn't test-run tail calls. Now that the test_verifier has the ability to perform run-time tests, populate the prog array so we actually jump into other BPF programs and can check all corner cases. Most useful in combination with JITs. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: Alexei Starovoitov --- tools/testing/selftests/bpf/test_verifier.c | 117 ++++++++++++++++++++++++++-- 1 file changed, 110 insertions(+), 7 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index bd3a08c7cc15..9eb05f3135ac 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -2588,6 +2588,62 @@ static struct bpf_test tests[] = { .result_unpriv = REJECT, .result = ACCEPT, }, + { + "runtime/jit: tail_call within bounds, prog once", + .insns = { + BPF_MOV64_IMM(BPF_REG_3, 0), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_prog = { 1 }, + .result = ACCEPT, + .retval = 42, + }, + { + "runtime/jit: tail_call within bounds, prog loop", + .insns = { + BPF_MOV64_IMM(BPF_REG_3, 1), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_prog = { 1 }, + .result = ACCEPT, + .retval = 41, + }, + { + "runtime/jit: tail_call within bounds, no prog", + .insns = { + BPF_MOV64_IMM(BPF_REG_3, 2), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + .fixup_prog = { 1 }, + .result = ACCEPT, + .retval = 1, + }, + { + "runtime/jit: tail_call out of bounds", + .insns = { + BPF_MOV64_IMM(BPF_REG_3, 256), + BPF_LD_MAP_FD(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + }, + .fixup_prog = { 1 }, + .result = ACCEPT, + .retval = 2, + }, { "runtime/jit: pass negative index to tail_call", .insns = { @@ -2595,11 +2651,12 @@ static struct bpf_test tests[] = { BPF_LD_MAP_FD(BPF_REG_2, 0), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_tail_call), - BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 2), BPF_EXIT_INSN(), }, .fixup_prog = { 1 }, .result = ACCEPT, + .retval = 2, }, { "runtime/jit: pass > 32bit index to tail_call", @@ -2608,11 +2665,12 @@ static struct bpf_test tests[] = { BPF_LD_MAP_FD(BPF_REG_2, 0), BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_tail_call), - BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_MOV64_IMM(BPF_REG_0, 2), BPF_EXIT_INSN(), }, .fixup_prog = { 2 }, .result = ACCEPT, + .retval = 42, }, { "stack pointer arithmetic", @@ -11278,16 +11336,61 @@ static int create_map(uint32_t size_value, uint32_t max_elem) return fd; } +static int create_prog_dummy1(void) +{ + struct bpf_insn prog[] = { + BPF_MOV64_IMM(BPF_REG_0, 42), + BPF_EXIT_INSN(), + }; + + return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog, + ARRAY_SIZE(prog), "GPL", 0, NULL, 0); +} + +static int create_prog_dummy2(int mfd, int idx) +{ + struct bpf_insn prog[] = { + BPF_MOV64_IMM(BPF_REG_3, idx), + BPF_LD_MAP_FD(BPF_REG_2, mfd), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_tail_call), + BPF_MOV64_IMM(BPF_REG_0, 41), + BPF_EXIT_INSN(), + }; + + return bpf_load_program(BPF_PROG_TYPE_SOCKET_FILTER, prog, + ARRAY_SIZE(prog), "GPL", 0, NULL, 0); +} + static int create_prog_array(void) { - int fd; + int p1key = 0, p2key = 1; + int mfd, p1fd, p2fd; - fd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(int), - sizeof(int), 4, 0); - if (fd < 0) + mfd = bpf_create_map(BPF_MAP_TYPE_PROG_ARRAY, sizeof(int), + sizeof(int), 4, 0); + if (mfd < 0) { printf("Failed to create prog array '%s'!\n", strerror(errno)); + return -1; + } - return fd; + p1fd = create_prog_dummy1(); + p2fd = create_prog_dummy2(mfd, p2key); + if (p1fd < 0 || p2fd < 0) + goto out; + if (bpf_map_update_elem(mfd, &p1key, &p1fd, BPF_ANY) < 0) + goto out; + if (bpf_map_update_elem(mfd, &p2key, &p2fd, BPF_ANY) < 0) + goto out; + close(p2fd); + close(p1fd); + + return mfd; +out: + close(p2fd); + close(p1fd); + close(mfd); + return -1; } static int create_map_in_map(void) -- cgit v1.3-14-g43fede From a52b839752aab7063c38c1cb7b8e63efc54e3c30 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 26 Feb 2018 09:53:15 -0800 Subject: selftests: Add fib-onlink-tests.sh to TEST_PROGS Fixes: 153e1b84f477 ("selftests: Add FIB onlink tests") Reported-by: Ido Schimmel Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index d7c30d366935..229a038966e3 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -5,7 +5,7 @@ CFLAGS = -Wall -Wl,--no-as-needed -O2 -g CFLAGS += -I../../../../usr/include/ TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh -TEST_PROGS += fib_tests.sh +TEST_PROGS += fib_tests.sh fib-onlink-tests.sh TEST_GEN_FILES = socket TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa -- cgit v1.3-14-g43fede From 67490e34ba2b1c02fb554a8059cd6ce12b47ccfb Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Tue, 27 Feb 2018 09:52:42 -0800 Subject: selftests/net: revert the zerocopy Rx path for PF_RDS In preparation for optimized reception of zerocopy completion, revert the Rx side changes introduced by Commit dfb8434b0a94 ("selftests/net: add zerocopy support for PF_RDS test case") Signed-off-by: Sowmini Varadhan Acked-by: Willem de Bruijn Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller --- tools/testing/selftests/net/msg_zerocopy.c | 67 ------------------------------ 1 file changed, 67 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c index 5cc2a53bb71c..eff9cf2ff04d 100644 --- a/tools/testing/selftests/net/msg_zerocopy.c +++ b/tools/testing/selftests/net/msg_zerocopy.c @@ -344,26 +344,6 @@ static int do_setup_tx(int domain, int type, int protocol) return fd; } -static int do_process_zerocopy_cookies(struct sock_extended_err *serr, - uint32_t *ckbuf, size_t nbytes) -{ - int ncookies, i; - - if (serr->ee_errno != 0) - error(1, 0, "serr: wrong error code: %u", serr->ee_errno); - ncookies = serr->ee_data; - if (ncookies > SO_EE_ORIGIN_MAX_ZCOOKIES) - error(1, 0, "Returned %d cookies, max expected %d\n", - ncookies, SO_EE_ORIGIN_MAX_ZCOOKIES); - if (nbytes != ncookies * sizeof(uint32_t)) - error(1, 0, "Expected %d cookies, got %ld\n", - ncookies, nbytes/sizeof(uint32_t)); - for (i = 0; i < ncookies; i++) - if (cfg_verbose >= 2) - fprintf(stderr, "%d\n", ckbuf[i]); - return ncookies; -} - static bool do_recv_completion(int fd) { struct sock_extended_err *serr; @@ -372,17 +352,10 @@ static bool do_recv_completion(int fd) uint32_t hi, lo, range; int ret, zerocopy; char control[100]; - uint32_t ckbuf[SO_EE_ORIGIN_MAX_ZCOOKIES]; - struct iovec iov; msg.msg_control = control; msg.msg_controllen = sizeof(control); - iov.iov_base = ckbuf; - iov.iov_len = (SO_EE_ORIGIN_MAX_ZCOOKIES * sizeof(ckbuf[0])); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - ret = recvmsg(fd, &msg, MSG_ERRQUEUE); if (ret == -1 && errno == EAGAIN) return false; @@ -402,10 +375,6 @@ static bool do_recv_completion(int fd) serr = (void *) CMSG_DATA(cm); - if (serr->ee_origin == SO_EE_ORIGIN_ZCOOKIE) { - completions += do_process_zerocopy_cookies(serr, ckbuf, ret); - return true; - } if (serr->ee_origin != SO_EE_ORIGIN_ZEROCOPY) error(1, 0, "serr: wrong origin: %u", serr->ee_origin); if (serr->ee_errno != 0) @@ -631,40 +600,6 @@ static void do_flush_datagram(int fd, int type) bytes += cfg_payload_len; } - -static void do_recvmsg(int fd) -{ - int ret, off = 0; - char *buf; - struct iovec iov; - struct msghdr msg; - struct sockaddr_storage din; - - buf = calloc(cfg_payload_len, sizeof(char)); - iov.iov_base = buf; - iov.iov_len = cfg_payload_len; - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = &din; - msg.msg_namelen = sizeof(din); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - ret = recvmsg(fd, &msg, MSG_TRUNC); - - if (ret == -1) - error(1, errno, "recv"); - if (ret != cfg_payload_len) - error(1, 0, "recv: ret=%u != %u", ret, cfg_payload_len); - - if (memcmp(buf + off, payload, ret)) - error(1, 0, "recv: data mismatch"); - - free(buf); - packets++; - bytes += cfg_payload_len; -} - static void do_rx(int domain, int type, int protocol) { uint64_t tstop; @@ -676,8 +611,6 @@ static void do_rx(int domain, int type, int protocol) do { if (type == SOCK_STREAM) do_flush_tcp(fd); - else if (domain == PF_RDS) - do_recvmsg(fd); else do_flush_datagram(fd, type); -- cgit v1.3-14-g43fede From 6f3899e602b0f4ec3d62ff385bb805e7109defa4 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Tue, 27 Feb 2018 09:52:44 -0800 Subject: selftests/net: reap zerocopy completions passed up as ancillary data. PF_RDS sockets pass up cookies for zerocopy completion as ancillary data. Update msg_zerocopy to reap this information. Signed-off-by: Sowmini Varadhan Acked-by: Willem de Bruijn Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller --- tools/testing/selftests/net/msg_zerocopy.c | 65 ++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/msg_zerocopy.c b/tools/testing/selftests/net/msg_zerocopy.c index eff9cf2ff04d..406cc70c571d 100644 --- a/tools/testing/selftests/net/msg_zerocopy.c +++ b/tools/testing/selftests/net/msg_zerocopy.c @@ -344,7 +344,53 @@ static int do_setup_tx(int domain, int type, int protocol) return fd; } -static bool do_recv_completion(int fd) +static uint32_t do_process_zerocopy_cookies(struct rds_zcopy_cookies *ck) +{ + int i; + + if (ck->num > RDS_MAX_ZCOOKIES) + error(1, 0, "Returned %d cookies, max expected %d\n", + ck->num, RDS_MAX_ZCOOKIES); + for (i = 0; i < ck->num; i++) + if (cfg_verbose >= 2) + fprintf(stderr, "%d\n", ck->cookies[i]); + return ck->num; +} + +static bool do_recvmsg_completion(int fd) +{ + char cmsgbuf[CMSG_SPACE(sizeof(struct rds_zcopy_cookies))]; + struct rds_zcopy_cookies *ck; + struct cmsghdr *cmsg; + struct msghdr msg; + bool ret = false; + + memset(&msg, 0, sizeof(msg)); + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + + if (recvmsg(fd, &msg, MSG_DONTWAIT)) + return ret; + + if (msg.msg_flags & MSG_CTRUNC) + error(1, errno, "recvmsg notification: truncated"); + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_RDS && + cmsg->cmsg_type == RDS_CMSG_ZCOPY_COMPLETION) { + + ck = (struct rds_zcopy_cookies *)CMSG_DATA(cmsg); + completions += do_process_zerocopy_cookies(ck); + ret = true; + break; + } + error(0, 0, "ignoring cmsg at level %d type %d\n", + cmsg->cmsg_level, cmsg->cmsg_type); + } + return ret; +} + +static bool do_recv_completion(int fd, int domain) { struct sock_extended_err *serr; struct msghdr msg = {}; @@ -353,6 +399,9 @@ static bool do_recv_completion(int fd) int ret, zerocopy; char control[100]; + if (domain == PF_RDS) + return do_recvmsg_completion(fd); + msg.msg_control = control; msg.msg_controllen = sizeof(control); @@ -409,20 +458,20 @@ static bool do_recv_completion(int fd) } /* Read all outstanding messages on the errqueue */ -static void do_recv_completions(int fd) +static void do_recv_completions(int fd, int domain) { - while (do_recv_completion(fd)) {} + while (do_recv_completion(fd, domain)) {} } /* Wait for all remaining completions on the errqueue */ -static void do_recv_remaining_completions(int fd) +static void do_recv_remaining_completions(int fd, int domain) { int64_t tstop = gettimeofday_ms() + cfg_waittime_ms; while (completions < expected_completions && gettimeofday_ms() < tstop) { - if (do_poll(fd, POLLERR)) - do_recv_completions(fd); + if (do_poll(fd, domain == PF_RDS ? POLLIN : POLLERR)) + do_recv_completions(fd, domain); } if (completions < expected_completions) @@ -503,13 +552,13 @@ static void do_tx(int domain, int type, int protocol) while (!do_poll(fd, POLLOUT)) { if (cfg_zerocopy) - do_recv_completions(fd); + do_recv_completions(fd, domain); } } while (gettimeofday_ms() < tstop); if (cfg_zerocopy) - do_recv_remaining_completions(fd); + do_recv_remaining_completions(fd, domain); if (close(fd)) error(1, errno, "close"); -- cgit v1.3-14-g43fede From b7abbd5a3533a31a1e7d4696ea275df543440c51 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Wed, 28 Feb 2018 15:15:56 +1100 Subject: selftests/powerpc: Fix missing clean of pmu/lib.o The tm-resched-dscr test links against pmu/lib.o, but we don't have a rule to clean pmu/lib.o. This can lead to a build break if you build for big endian and then little, or vice versa. Fix it by making tm-resched-dscr depend on pmu/lib.c, causing the code to be built directly in, meaning no .o is generated. Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index a23453943ad2..5c72ff978f27 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -16,7 +16,7 @@ $(OUTPUT)/tm-syscall: tm-syscall-asm.S $(OUTPUT)/tm-syscall: CFLAGS += -I../../../../../usr/include $(OUTPUT)/tm-tmspr: CFLAGS += -pthread $(OUTPUT)/tm-vmx-unavail: CFLAGS += -pthread -m64 -$(OUTPUT)/tm-resched-dscr: ../pmu/lib.o +$(OUTPUT)/tm-resched-dscr: ../pmu/lib.c $(OUTPUT)/tm-unavailable: CFLAGS += -O0 -pthread -m64 -Wno-error=uninitialized -mvsx $(OUTPUT)/tm-trap: CFLAGS += -O0 -pthread -m64 -- cgit v1.3-14-g43fede From 73bae6736b6b577b52fbba2d4b71a5a3e9920fb5 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:06 +0200 Subject: selftests: forwarding: Add initial testing framework Add initial framework to test packet forwarding functionality. The tests can run on actual devices using loop-backed cables or using veth pairs. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/.gitignore | 1 + tools/testing/selftests/net/forwarding/README | 56 ++++ .../selftests/net/forwarding/bridge_vlan_aware.sh | 83 ++++++ tools/testing/selftests/net/forwarding/config | 12 + .../net/forwarding/forwarding.config.sample | 31 +++ tools/testing/selftests/net/forwarding/lib.sh | 282 +++++++++++++++++++++ 6 files changed, 465 insertions(+) create mode 100644 tools/testing/selftests/net/forwarding/.gitignore create mode 100644 tools/testing/selftests/net/forwarding/README create mode 100755 tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh create mode 100644 tools/testing/selftests/net/forwarding/config create mode 100644 tools/testing/selftests/net/forwarding/forwarding.config.sample create mode 100644 tools/testing/selftests/net/forwarding/lib.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/.gitignore b/tools/testing/selftests/net/forwarding/.gitignore new file mode 100644 index 000000000000..a793eef5b876 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/.gitignore @@ -0,0 +1 @@ +forwarding.config diff --git a/tools/testing/selftests/net/forwarding/README b/tools/testing/selftests/net/forwarding/README new file mode 100644 index 000000000000..4a0964c42860 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/README @@ -0,0 +1,56 @@ +Motivation +========== + +One of the nice things about network namespaces is that they allow one +to easily create and test complex environments. + +Unfortunately, these namespaces can not be used with actual switching +ASICs, as their ports can not be migrated to other network namespaces +(NETIF_F_NETNS_LOCAL) and most of them probably do not support the +L1-separation provided by namespaces. + +However, a similar kind of flexibility can be achieved by using VRFs and +by looping the switch ports together. For example: + + br0 + + + vrf-h1 | vrf-h2 + + +---+----+ + + | | | | + 192.0.2.1/24 + + + + 192.0.2.2/24 + swp1 swp2 swp3 swp4 + + + + + + | | | | + +--------+ +--------+ + +The VRFs act as lightweight namespaces representing hosts connected to +the switch. + +This approach for testing switch ASICs has several advantages over the +traditional method that requires multiple physical machines, to name a +few: + +1. Only the device under test (DUT) is being tested without noise from +other system. + +2. Ability to easily provision complex topologies. Testing bridging +between 4-ports LAGs or 8-way ECMP requires many physical links that are +not always available. With the VRF-based approach one merely needs to +loopback more ports. + +These tests are written with switch ASICs in mind, but they can be run +on any Linux box using veth pairs to emulate physical loopbacks. + +Guidelines for Writing Tests +============================ + +o Where possible, reuse an existing topology for different tests instead + of recreating the same topology. +o Where possible, IPv6 and IPv4 addresses shall conform to RFC 3849 and + RFC 5737, respectively. +o Where possible, tests shall be written so that they can be reused by + multiple topologies and added to lib.sh. +o Checks shall be added to lib.sh for any external dependencies. +o Code shall be checked using ShellCheck [1] prior to submission. + +1. https://www.shellcheck.net/ diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh new file mode 100755 index 000000000000..e6faa9548460 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=4 +source lib.sh + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64 +} + +h2_destroy() +{ + simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64 +} + +switch_create() +{ + ip link add dev br0 type bridge vlan_filtering 1 mcast_snooping 0 + + ip link set dev $swp1 master br0 + ip link set dev $swp2 master br0 + + ip link set dev br0 up + ip link set dev $swp1 up + ip link set dev $swp2 up +} + +switch_destroy() +{ + ip link set dev $swp2 down + ip link set dev $swp1 down + + ip link del dev br0 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + + h1_create + h2_create + + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +ping_test $h1 192.0.2.2 +ping6_test $h1 2001:db8:1::2 + +exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/config b/tools/testing/selftests/net/forwarding/config new file mode 100644 index 000000000000..5cd2aed97958 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/config @@ -0,0 +1,12 @@ +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_NET_L3_MASTER_DEV=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NET_VRF=m +CONFIG_BPF_SYSCALL=y +CONFIG_CGROUP_BPF=y +CONFIG_NET_CLS_FLOWER=m +CONFIG_NET_SCH_INGRESS=m +CONFIG_NET_ACT_GACT=m +CONFIG_VETH=m diff --git a/tools/testing/selftests/net/forwarding/forwarding.config.sample b/tools/testing/selftests/net/forwarding/forwarding.config.sample new file mode 100644 index 000000000000..ab235c124f20 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/forwarding.config.sample @@ -0,0 +1,31 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +############################################################################## +# Topology description. p1 looped back to p2, p3 to p4 and so on. +declare -A NETIFS + +NETIFS[p1]=veth0 +NETIFS[p2]=veth1 +NETIFS[p3]=veth2 +NETIFS[p4]=veth3 +NETIFS[p5]=veth4 +NETIFS[p6]=veth5 +NETIFS[p7]=veth6 +NETIFS[p8]=veth7 + +############################################################################## +# Defines + +# IPv4 ping utility name +PING=ping +# IPv6 ping utility name. Some distributions use 'ping' for IPv6. +PING6=ping6 +# Packet generator. Some distributions use 'mz'. +MZ=mausezahn +# Time to wait after interfaces participating in the test are all UP +WAIT_TIME=5 +# Whether to pause on failure or not. +PAUSE_ON_FAIL=no +# Whether to pause on cleanup or not. +PAUSE_ON_CLEANUP=no diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh new file mode 100644 index 000000000000..ff6550e9ddaf --- /dev/null +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -0,0 +1,282 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +############################################################################## +# Defines + +# Can be overridden by the configuration file. +PING=${PING:=ping} +PING6=${PING6:=ping6} +WAIT_TIME=${WAIT_TIME:=5} +PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} +PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} + +if [[ -f forwarding.config ]]; then + source forwarding.config +fi + +############################################################################## +# Sanity checks + +if [[ "$(id -u)" -ne 0 ]]; then + echo "SKIP: need root privileges" + exit 0 +fi + +tc -j &> /dev/null +if [[ $? -ne 0 ]]; then + echo "SKIP: iproute2 too old, missing JSON support" + exit 0 +fi + +if [[ ! -x "$(command -v jq)" ]]; then + echo "SKIP: jq not installed" + exit 0 +fi + +if [[ ! -v NUM_NETIFS ]]; then + echo "SKIP: importer does not define \"NUM_NETIFS\"" + exit 0 +fi + +############################################################################## +# Network interfaces configuration + +for i in $(eval echo {1..$NUM_NETIFS}); do + ip link show dev ${NETIFS[p$i]} &> /dev/null + if [[ $? -ne 0 ]]; then + echo "SKIP: could not find all required interfaces" + exit 0 + fi +done + +############################################################################## +# Helpers + +# Exit status to return at the end. Set in case one of the tests fails. +EXIT_STATUS=0 +# Per-test return value. Clear at the beginning of each test. +RET=0 + +check_err() +{ + local err=$1 + local msg=$2 + + if [[ $RET -eq 0 && $err -ne 0 ]]; then + RET=$err + retmsg=$msg + fi +} + +check_fail() +{ + local err=$1 + local msg=$2 + + if [[ $RET -eq 0 && $err -eq 0 ]]; then + RET=1 + retmsg=$msg + fi +} + +log_test() +{ + local test_name=$1 + local opt_str=$2 + + if [[ $# -eq 2 ]]; then + opt_str="($opt_str)" + fi + + if [[ $RET -ne 0 ]]; then + EXIT_STATUS=1 + printf "TEST: %-60s [FAIL]\n" "$test_name $opt_str" + if [[ ! -z "$retmsg" ]]; then + printf "\t%s\n" "$retmsg" + fi + if [ "${PAUSE_ON_FAIL}" = "yes" ]; then + echo "Hit enter to continue, 'q' to quit" + read a + [ "$a" = "q" ] && exit 1 + fi + return 1 + fi + + printf "TEST: %-60s [PASS]\n" "$test_name $opt_str" + return 0 +} + +setup_wait() +{ + for i in $(eval echo {1..$NUM_NETIFS}); do + while true; do + ip link show dev ${NETIFS[p$i]} up \ + | grep 'state UP' &> /dev/null + if [[ $? -ne 0 ]]; then + sleep 1 + else + break + fi + done + done + + # Make sure links are ready. + sleep $WAIT_TIME +} + +pre_cleanup() +{ + if [ "${PAUSE_ON_CLEANUP}" = "yes" ]; then + echo "Pausing before cleanup, hit any key to continue" + read + fi +} + +vrf_prepare() +{ + ip -4 rule add pref 32765 table local + ip -4 rule del pref 0 + ip -6 rule add pref 32765 table local + ip -6 rule del pref 0 +} + +vrf_cleanup() +{ + ip -6 rule add pref 0 table local + ip -6 rule del pref 32765 + ip -4 rule add pref 0 table local + ip -4 rule del pref 32765 +} + +__last_tb_id=0 +declare -A __TB_IDS + +__vrf_td_id_assign() +{ + local vrf_name=$1 + + __last_tb_id=$((__last_tb_id + 1)) + __TB_IDS[$vrf_name]=$__last_tb_id + return $__last_tb_id +} + +__vrf_td_id_lookup() +{ + local vrf_name=$1 + + return ${__TB_IDS[$vrf_name]} +} + +vrf_create() +{ + local vrf_name=$1 + local tb_id + + __vrf_td_id_assign $vrf_name + tb_id=$? + + ip link add dev $vrf_name type vrf table $tb_id + ip -4 route add table $tb_id unreachable default metric 4278198272 + ip -6 route add table $tb_id unreachable default metric 4278198272 +} + +vrf_destroy() +{ + local vrf_name=$1 + local tb_id + + __vrf_td_id_lookup $vrf_name + tb_id=$? + + ip -6 route del table $tb_id unreachable default metric 4278198272 + ip -4 route del table $tb_id unreachable default metric 4278198272 + ip link del dev $vrf_name +} + +__addr_add_del() +{ + local if_name=$1 + local add_del=$2 + local array + + shift + shift + array=("${@}") + + for addrstr in "${array[@]}"; do + ip address $add_del $addrstr dev $if_name + done +} + +simple_if_init() +{ + local if_name=$1 + local vrf_name + local array + + shift + vrf_name=v$if_name + array=("${@}") + + vrf_create $vrf_name + ip link set dev $if_name master $vrf_name + ip link set dev $vrf_name up + ip link set dev $if_name up + + __addr_add_del $if_name add "${array[@]}" +} + +simple_if_fini() +{ + local if_name=$1 + local vrf_name + local array + + shift + vrf_name=v$if_name + array=("${@}") + + __addr_add_del $if_name del "${array[@]}" + + ip link set dev $if_name down + vrf_destroy $vrf_name +} + +master_name_get() +{ + local if_name=$1 + + ip -j link show dev $if_name | jq -r '.[]["master"]' +} + +############################################################################## +# Tests + +ping_test() +{ + local if_name=$1 + local dip=$2 + local vrf_name + + RET=0 + + vrf_name=$(master_name_get $if_name) + ip vrf exec $vrf_name $PING $dip -c 10 -i 0.1 -w 2 &> /dev/null + check_err $? + log_test "ping" +} + +ping6_test() +{ + local if_name=$1 + local dip=$2 + local vrf_name + + RET=0 + + vrf_name=$(master_name_get $if_name) + ip vrf exec $vrf_name $PING6 $dip -c 10 -i 0.1 -w 2 &> /dev/null + check_err $? + log_test "ping6" +} -- cgit v1.3-14-g43fede From d4deb01467ec9ed33fe0f4b4fa4632c94f2dd8c9 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:07 +0200 Subject: selftests: forwarding: Add a test for FDB learning Send a packet with a specific destination MAC, make sure it was learned on the ingress port and then aged-out. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/bridge_vlan_aware.sh | 5 +- tools/testing/selftests/net/forwarding/lib.sh | 92 ++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh index e6faa9548460..1ba119f28963 100755 --- a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh @@ -26,7 +26,9 @@ h2_destroy() switch_create() { - ip link add dev br0 type bridge vlan_filtering 1 mcast_snooping 0 + # 10 Seconds ageing time. + ip link add dev br0 type bridge vlan_filtering 1 ageing_time 1000 \ + mcast_snooping 0 ip link set dev $swp1 master br0 ip link set dev $swp2 master br0 @@ -79,5 +81,6 @@ setup_wait ping_test $h1 192.0.2.2 ping6_test $h1 2001:db8:1::2 +learning_test "br0" $swp1 $h1 $h2 exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index ff6550e9ddaf..21af63e860dc 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -7,6 +7,7 @@ # Can be overridden by the configuration file. PING=${PING:=ping} PING6=${PING6:=ping6} +MZ=${MZ:=mausezahn} WAIT_TIME=${WAIT_TIME:=5} PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} @@ -34,6 +35,11 @@ if [[ ! -x "$(command -v jq)" ]]; then exit 0 fi +if [[ ! -x "$(command -v $MZ)" ]]; then + echo "SKIP: $MZ not installed" + exit 0 +fi + if [[ ! -v NUM_NETIFS ]]; then echo "SKIP: importer does not define \"NUM_NETIFS\"" exit 0 @@ -250,6 +256,17 @@ master_name_get() ip -j link show dev $if_name | jq -r '.[]["master"]' } +bridge_ageing_time_get() +{ + local bridge=$1 + local ageing_time + + # Need to divide by 100 to convert to seconds. + ageing_time=$(ip -j -d link show dev $bridge \ + | jq '.[]["linkinfo"]["info_data"]["ageing_time"]') + echo $((ageing_time / 100)) +} + ############################################################################## # Tests @@ -280,3 +297,78 @@ ping6_test() check_err $? log_test "ping6" } + +learning_test() +{ + local bridge=$1 + local br_port1=$2 # Connected to `host1_if`. + local host1_if=$3 + local host2_if=$4 + local mac=de:ad:be:ef:13:37 + local ageing_time + + RET=0 + + bridge -j fdb show br $bridge brport $br_port1 \ + | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null + check_fail $? "Found FDB record when should not" + + # Disable unknown unicast flooding on `br_port1` to make sure + # packets are only forwarded through the port after a matching + # FDB entry was installed. + bridge link set dev $br_port1 flood off + + tc qdisc add dev $host1_if ingress + tc filter add dev $host1_if ingress protocol ip pref 1 handle 101 \ + flower dst_mac $mac action drop + + $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q + sleep 1 + + tc -j -s filter show dev $host1_if ingress \ + | jq -e ".[] | select(.options.handle == 101) \ + | select(.options.actions[0].stats.packets == 1)" &> /dev/null + check_fail $? "Packet reached second host when should not" + + $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q + sleep 1 + + bridge -j fdb show br $bridge brport $br_port1 \ + | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null + check_err $? "Did not find FDB record when should" + + $MZ $host2_if -c 1 -p 64 -b $mac -t ip -q + sleep 1 + + tc -j -s filter show dev $host1_if ingress \ + | jq -e ".[] | select(.options.handle == 101) \ + | select(.options.actions[0].stats.packets == 1)" &> /dev/null + check_err $? "Packet did not reach second host when should" + + # Wait for 10 seconds after the ageing time to make sure FDB + # record was aged-out. + ageing_time=$(bridge_ageing_time_get $bridge) + sleep $((ageing_time + 10)) + + bridge -j fdb show br $bridge brport $br_port1 \ + | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null + check_fail $? "Found FDB record when should not" + + bridge link set dev $br_port1 learning off + + $MZ $host1_if -c 1 -p 64 -a $mac -t ip -q + sleep 1 + + bridge -j fdb show br $bridge brport $br_port1 \ + | jq -e ".[] | select(.mac == \"$mac\")" &> /dev/null + check_fail $? "Found FDB record when should not" + + bridge link set dev $br_port1 learning on + + tc filter del dev $host1_if ingress protocol ip pref 1 handle 101 flower + tc qdisc del dev $host1_if ingress + + bridge link set dev $br_port1 flood on + + log_test "FDB learning" +} -- cgit v1.3-14-g43fede From 236dd50bf67a2ab5fd39d82e712d1fafdd4c602d Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:08 +0200 Subject: selftests: forwarding: Add a test for flooded traffic Add test cases for unknown unicast and unregistered multicast flooding. For each traffic type, turn off flooding on one bridged port and inject a packet of the specified type through the second bridged port. Make sure the packet was not received by checking the ACL counters on the other end. Later, turn on flooding and make sure the packet was received. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/bridge_vlan_aware.sh | 1 + tools/testing/selftests/net/forwarding/lib.sh | 89 ++++++++++++++++++++++ 2 files changed, 90 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh index 1ba119f28963..651998e70557 100755 --- a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh @@ -82,5 +82,6 @@ setup_wait ping_test $h1 192.0.2.2 ping6_test $h1 2001:db8:1::2 learning_test "br0" $swp1 $h1 $h2 +flood_test $swp2 $h1 $h2 exit $EXIT_STATUS diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 21af63e860dc..e2a4ee8946ef 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -372,3 +372,92 @@ learning_test() log_test "FDB learning" } + +flood_test_do() +{ + local should_flood=$1 + local mac=$2 + local ip=$3 + local host1_if=$4 + local host2_if=$5 + local err=0 + + # Add an ACL on `host2_if` which will tell us whether the packet + # was flooded to it or not. + tc qdisc add dev $host2_if ingress + tc filter add dev $host2_if ingress protocol ip pref 1 handle 101 \ + flower dst_mac $mac action drop + + $MZ $host1_if -c 1 -p 64 -b $mac -B $ip -t ip -q + sleep 1 + + tc -j -s filter show dev $host2_if ingress \ + | jq -e ".[] | select(.options.handle == 101) \ + | select(.options.actions[0].stats.packets == 1)" &> /dev/null + if [[ $? -ne 0 && $should_flood == "true" || \ + $? -eq 0 && $should_flood == "false" ]]; then + err=1 + fi + + tc filter del dev $host2_if ingress protocol ip pref 1 handle 101 flower + tc qdisc del dev $host2_if ingress + + return $err +} + +flood_unicast_test() +{ + local br_port=$1 + local host1_if=$2 + local host2_if=$3 + local mac=de:ad:be:ef:13:37 + local ip=192.0.2.100 + + RET=0 + + bridge link set dev $br_port flood off + + flood_test_do false $mac $ip $host1_if $host2_if + check_err $? "Packet flooded when should not" + + bridge link set dev $br_port flood on + + flood_test_do true $mac $ip $host1_if $host2_if + check_err $? "Packet was not flooded when should" + + log_test "Unknown unicast flood" +} + +flood_multicast_test() +{ + local br_port=$1 + local host1_if=$2 + local host2_if=$3 + local mac=01:00:5e:00:00:01 + local ip=239.0.0.1 + + RET=0 + + bridge link set dev $br_port mcast_flood off + + flood_test_do false $mac $ip $host1_if $host2_if + check_err $? "Packet flooded when should not" + + bridge link set dev $br_port mcast_flood on + + flood_test_do true $mac $ip $host1_if $host2_if + check_err $? "Packet was not flooded when should" + + log_test "Unregistered multicast flood" +} + +flood_test() +{ + # `br_port` is connected to `host2_if` + local br_port=$1 + local host1_if=$2 + local host2_if=$3 + + flood_unicast_test $br_port $host1_if $host2_if + flood_multicast_test $br_port $host1_if $host2_if +} -- cgit v1.3-14-g43fede From 7b7bc875559c0c06406d77a7f71e3c0e289a60be Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:09 +0200 Subject: selftests: forwarding: Add a test for basic IPv4 and IPv6 routing Configure two hosts which are directly connected to the same router and test IPv4 and IPv6 ping. Use a large MTU and check that ping is unaffected. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 15 +++ tools/testing/selftests/net/forwarding/router.sh | 125 +++++++++++++++++++++++ 2 files changed, 140 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/router.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index e2a4ee8946ef..962153b7181b 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -267,6 +267,21 @@ bridge_ageing_time_get() echo $((ageing_time / 100)) } +forwarding_enable() +{ + ipv4_fwd=$(sysctl -n net.ipv4.conf.all.forwarding) + ipv6_fwd=$(sysctl -n net.ipv6.conf.all.forwarding) + + sysctl -q -w net.ipv4.conf.all.forwarding=1 + sysctl -q -w net.ipv6.conf.all.forwarding=1 +} + +forwarding_restore() +{ + sysctl -q -w net.ipv6.conf.all.forwarding=$ipv6_fwd + sysctl -q -w net.ipv4.conf.all.forwarding=$ipv4_fwd +} + ############################################################################## # Tests diff --git a/tools/testing/selftests/net/forwarding/router.sh b/tools/testing/selftests/net/forwarding/router.sh new file mode 100755 index 000000000000..cc6a14abfa87 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/router.sh @@ -0,0 +1,125 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=4 +source lib.sh + +h1_create() +{ + vrf_create "vrf-h1" + ip link set dev $h1 master vrf-h1 + + ip link set dev vrf-h1 up + ip link set dev $h1 up + + ip address add 192.0.2.2/24 dev $h1 + ip address add 2001:db8:1::2/64 dev $h1 + + ip route add 198.51.100.0/24 vrf vrf-h1 nexthop via 192.0.2.1 + ip route add 2001:db8:2::/64 vrf vrf-h1 nexthop via 2001:db8:1::1 +} + +h1_destroy() +{ + ip route del 2001:db8:2::/64 vrf vrf-h1 + ip route del 198.51.100.0/24 vrf vrf-h1 + + ip address del 2001:db8:1::2/64 dev $h1 + ip address del 192.0.2.2/24 dev $h1 + + ip link set dev $h1 down + vrf_destroy "vrf-h1" +} + +h2_create() +{ + vrf_create "vrf-h2" + ip link set dev $h2 master vrf-h2 + + ip link set dev vrf-h2 up + ip link set dev $h2 up + + ip address add 198.51.100.2/24 dev $h2 + ip address add 2001:db8:2::2/64 dev $h2 + + ip route add 192.0.2.0/24 vrf vrf-h2 nexthop via 198.51.100.1 + ip route add 2001:db8:1::/64 vrf vrf-h2 nexthop via 2001:db8:2::1 +} + +h2_destroy() +{ + ip route del 2001:db8:1::/64 vrf vrf-h2 + ip route del 192.0.2.0/24 vrf vrf-h2 + + ip address del 2001:db8:2::2/64 dev $h2 + ip address del 198.51.100.2/24 dev $h2 + + ip link set dev $h2 down + vrf_destroy "vrf-h2" +} + +router_create() +{ + ip link set dev $rp1 up + ip link set dev $rp2 up + + ip address add 192.0.2.1/24 dev $rp1 + ip address add 2001:db8:1::1/64 dev $rp1 + + ip address add 198.51.100.1/24 dev $rp2 + ip address add 2001:db8:2::1/64 dev $rp2 +} + +router_destroy() +{ + ip address del 2001:db8:2::1/64 dev $rp2 + ip address del 198.51.100.1/24 dev $rp2 + + ip address del 2001:db8:1::1/64 dev $rp1 + ip address del 192.0.2.1/24 dev $rp1 + + ip link set dev $rp2 down + ip link set dev $rp1 down +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + rp1=${NETIFS[p2]} + + rp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + + h1_create + h2_create + + router_create + + forwarding_enable +} + +cleanup() +{ + pre_cleanup + + forwarding_restore + + router_destroy + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +ping_test $h1 198.51.100.2 +ping6_test $h1 2001:db8:2::2 + +exit $EXIT_STATUS -- cgit v1.3-14-g43fede From 937eeb3482748bb85486070e10b5fbeb6b973f63 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:10 +0200 Subject: selftests: forwarding: Create test topology for multipath routing Create a topology with two hosts, each directly connected to a different router. Both routers are connected using two links, enabling multipath routing. Test IPv4 and IPv6 ping using default MTU and large MTU. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/router_multipath.sh | 209 +++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/router_multipath.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh new file mode 100755 index 000000000000..86d189b42e9b --- /dev/null +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -0,0 +1,209 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=8 +source lib.sh + +h1_create() +{ + vrf_create "vrf-h1" + ip link set dev $h1 master vrf-h1 + + ip link set dev vrf-h1 up + ip link set dev $h1 up + + ip address add 192.0.2.2/24 dev $h1 + ip address add 2001:db8:1::2/64 dev $h1 + + ip route add 198.51.100.0/24 vrf vrf-h1 nexthop via 192.0.2.1 + ip route add 2001:db8:2::/64 vrf vrf-h1 nexthop via 2001:db8:1::1 +} + +h1_destroy() +{ + ip route del 2001:db8:2::/64 vrf vrf-h1 + ip route del 198.51.100.0/24 vrf vrf-h1 + + ip address del 2001:db8:1::2/64 dev $h1 + ip address del 192.0.2.2/24 dev $h1 + + ip link set dev $h1 down + vrf_destroy "vrf-h1" +} + +h2_create() +{ + vrf_create "vrf-h2" + ip link set dev $h2 master vrf-h2 + + ip link set dev vrf-h2 up + ip link set dev $h2 up + + ip address add 198.51.100.2/24 dev $h2 + ip address add 2001:db8:2::2/64 dev $h2 + + ip route add 192.0.2.0/24 vrf vrf-h2 nexthop via 198.51.100.1 + ip route add 2001:db8:1::/64 vrf vrf-h2 nexthop via 2001:db8:2::1 +} + +h2_destroy() +{ + ip route del 2001:db8:1::/64 vrf vrf-h2 + ip route del 192.0.2.0/24 vrf vrf-h2 + + ip address del 2001:db8:2::2/64 dev $h2 + ip address del 198.51.100.2/24 dev $h2 + + ip link set dev $h2 down + vrf_destroy "vrf-h2" +} + +router1_create() +{ + vrf_create "vrf-r1" + ip link set dev $rp11 master vrf-r1 + ip link set dev $rp12 master vrf-r1 + ip link set dev $rp13 master vrf-r1 + + ip link set dev vrf-r1 up + ip link set dev $rp11 up + ip link set dev $rp12 up + ip link set dev $rp13 up + + ip address add 192.0.2.1/24 dev $rp11 + ip address add 2001:db8:1::1/64 dev $rp11 + + ip address add 169.254.2.12/24 dev $rp12 + ip address add fe80:2::12/64 dev $rp12 + + ip address add 169.254.3.13/24 dev $rp13 + ip address add fe80:3::13/64 dev $rp13 + + ip route add 198.51.100.0/24 vrf vrf-r1 \ + nexthop via 169.254.2.22 dev $rp12 \ + nexthop via 169.254.3.23 dev $rp13 + ip route add 2001:db8:2::/64 vrf vrf-r1 \ + nexthop via fe80:2::22 dev $rp12 \ + nexthop via fe80:3::23 dev $rp13 +} + +router1_destroy() +{ + ip route del 2001:db8:2::/64 vrf vrf-r1 + ip route del 198.51.100.0/24 vrf vrf-r1 + + ip address del fe80:3::13/64 dev $rp13 + ip address del 169.254.3.13/24 dev $rp13 + + ip address del fe80:2::12/64 dev $rp12 + ip address del 169.254.2.12/24 dev $rp12 + + ip address del 2001:db8:1::1/64 dev $rp11 + ip address del 192.0.2.1/24 dev $rp11 + + ip link set dev $rp13 down + ip link set dev $rp12 down + ip link set dev $rp11 down + + vrf_destroy "vrf-r1" +} + +router2_create() +{ + vrf_create "vrf-r2" + ip link set dev $rp21 master vrf-r2 + ip link set dev $rp22 master vrf-r2 + ip link set dev $rp23 master vrf-r2 + + ip link set dev vrf-r2 up + ip link set dev $rp21 up + ip link set dev $rp22 up + ip link set dev $rp23 up + + ip address add 198.51.100.1/24 dev $rp21 + ip address add 2001:db8:2::1/64 dev $rp21 + + ip address add 169.254.2.22/24 dev $rp22 + ip address add fe80:2::22/64 dev $rp22 + + ip address add 169.254.3.23/24 dev $rp23 + ip address add fe80:3::23/64 dev $rp23 + + ip route add 192.0.2.0/24 vrf vrf-r2 \ + nexthop via 169.254.2.12 dev $rp22 \ + nexthop via 169.254.3.13 dev $rp23 + ip route add 2001:db8:1::/64 vrf vrf-r2 \ + nexthop via fe80:2::12 dev $rp22 \ + nexthop via fe80:3::13 dev $rp23 +} + +router2_destroy() +{ + ip route del 2001:db8:1::/64 vrf vrf-r2 + ip route del 192.0.2.0/24 vrf vrf-r2 + + ip address del fe80:3::23/64 dev $rp23 + ip address del 169.254.3.23/24 dev $rp23 + + ip address del fe80:2::22/64 dev $rp22 + ip address del 169.254.2.22/24 dev $rp22 + + ip address del 2001:db8:2::1/64 dev $rp21 + ip address del 198.51.100.1/24 dev $rp21 + + ip link set dev $rp23 down + ip link set dev $rp22 down + ip link set dev $rp21 down + + vrf_destroy "vrf-r2" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + rp11=${NETIFS[p2]} + + rp12=${NETIFS[p3]} + rp22=${NETIFS[p4]} + + rp13=${NETIFS[p5]} + rp23=${NETIFS[p6]} + + rp21=${NETIFS[p7]} + h2=${NETIFS[p8]} + + vrf_prepare + + h1_create + h2_create + + router1_create + router2_create + + forwarding_enable +} + +cleanup() +{ + pre_cleanup + + forwarding_restore + + router2_destroy + router1_destroy + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +ping_test $h1 198.51.100.2 +ping6_test $h1 2001:db8:2::2 + +exit $EXIT_STATUS -- cgit v1.3-14-g43fede From 3d578d879517a97f4af867e6a8a021baf15e5101 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:11 +0200 Subject: selftests: forwarding: Test IPv4 weighted nexthops Use different weights for the multipath route configured on the first router and check that the different flows generated by the first host are distributed according to the provided weights. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 14 ++++ .../selftests/net/forwarding/router_multipath.sh | 77 ++++++++++++++++++++++ 2 files changed, 91 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 962153b7181b..6866f4a4bc4e 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -113,6 +113,13 @@ log_test() return 0 } +log_info() +{ + local msg=$1 + + echo "INFO: $msg" +} + setup_wait() { for i in $(eval echo {1..$NUM_NETIFS}); do @@ -256,6 +263,13 @@ master_name_get() ip -j link show dev $if_name | jq -r '.[]["master"]' } +link_stats_tx_packets_get() +{ + local if_name=$1 + + ip -j -s link show dev $if_name | jq '.[]["stats64"]["tx"]["packets"]' +} + bridge_ageing_time_get() { local bridge=$1 diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index 86d189b42e9b..5b425dffb5d0 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -158,6 +158,82 @@ router2_destroy() vrf_destroy "vrf-r2" } +multipath_eval() +{ + local weight_rp12=$1 + local weight_rp13=$2 + local packets_rp12=$3 + local packets_rp13=$4 + local weights_ratio packets_ratio diff + + RET=0 + + if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then + weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \ + | bc -l) + packets_ratio=$(echo "scale=2; $packets_rp12 / $packets_rp13" \ + | bc -l) + else + weights_ratio=$(echo "scale=2; $weight_rp13 / $weight_rp12" | \ + bc -l) + packets_ratio=$(echo "scale=2; $packets_rp13 / $packets_rp12" | \ + bc -l) + fi + + diff=$(echo $weights_ratio - $packets_ratio | bc -l) + diff=${diff#-} + + test "$(echo "$diff / $weights_ratio > 0.1" | bc -l)" -eq 0 + check_err $? "Too large discrepancy between expected and measured ratios" + log_test "Multipath" + log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio" +} + +multipath4_test() +{ + local weight_rp12=$1 + local weight_rp13=$2 + local t0_rp12 t0_rp13 t1_rp12 t1_rp13 + local packets_rp12 packets_rp13 + local hash_policy + + # Transmit multiple flows from h1 to h2 and make sure they are + # distributed between both multipath links (rp12 and rp13) + # according to the configured weights. + hash_policy=$(sysctl -n net.ipv4.fib_multipath_hash_policy) + sysctl -q -w net.ipv4.fib_multipath_hash_policy=1 + ip route replace 198.51.100.0/24 vrf vrf-r1 \ + nexthop via 169.254.2.22 dev $rp12 weight $weight_rp12 \ + nexthop via 169.254.3.23 dev $rp13 weight $weight_rp13 + + t0_rp12=$(link_stats_tx_packets_get $rp12) + t0_rp13=$(link_stats_tx_packets_get $rp13) + + ip vrf exec vrf-h1 $MZ -q -p 64 -A 192.0.2.2 -B 198.51.100.2 \ + -d 1msec -t udp "sp=1024,dp=0-32768" + + t1_rp12=$(link_stats_tx_packets_get $rp12) + t1_rp13=$(link_stats_tx_packets_get $rp13) + + let "packets_rp12 = $t1_rp12 - $t0_rp12" + let "packets_rp13 = $t1_rp13 - $t0_rp13" + multipath_eval $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 + + # Restore settings. + ip route replace 198.51.100.0/24 vrf vrf-r1 \ + nexthop via 169.254.2.22 dev $rp12 \ + nexthop via 169.254.3.23 dev $rp13 + sysctl -q -w net.ipv4.fib_multipath_hash_policy=$hash_policy +} + +multipath_test() +{ + log_info "Running IPv4 multipath tests" + multipath4_test 1 1 + multipath4_test 2 1 + multipath4_test 11 45 +} + setup_prepare() { h1=${NETIFS[p1]} @@ -205,5 +281,6 @@ setup_wait ping_test $h1 198.51.100.2 ping6_test $h1 2001:db8:2::2 +multipath_test exit $EXIT_STATUS -- cgit v1.3-14-g43fede From 4fb20ae13711ee05fba6e5dd2b81a83d9e5b5249 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Wed, 28 Feb 2018 12:25:12 +0200 Subject: selftests: forwarding: Test IPv6 weighted nexthops Have one host generate 16K IPv6 echo requests with a random flow label and check that they are distributed between both multipath links according to the provided weights. Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/router_multipath.sh | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index 5b425dffb5d0..d31888e3133e 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -226,12 +226,48 @@ multipath4_test() sysctl -q -w net.ipv4.fib_multipath_hash_policy=$hash_policy } +multipath6_test() +{ + local weight_rp12=$1 + local weight_rp13=$2 + local t0_rp12 t0_rp13 t1_rp12 t1_rp13 + local packets_rp12 packets_rp13 + + ip route replace 2001:db8:2::/64 vrf vrf-r1 \ + nexthop via fe80:2::22 dev $rp12 weight $weight_rp12 \ + nexthop via fe80:3::23 dev $rp13 weight $weight_rp13 + + t0_rp12=$(link_stats_tx_packets_get $rp12) + t0_rp13=$(link_stats_tx_packets_get $rp13) + + # Generate 16384 echo requests, each with a random flow label. + for _ in $(seq 1 16384); do + ip vrf exec vrf-h1 ping 2001:db8:2::2 -F 0 -c 1 -q &> /dev/null + done + + t1_rp12=$(link_stats_tx_packets_get $rp12) + t1_rp13=$(link_stats_tx_packets_get $rp13) + + let "packets_rp12 = $t1_rp12 - $t0_rp12" + let "packets_rp13 = $t1_rp13 - $t0_rp13" + multipath_eval $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 + + ip route replace 2001:db8:2::/64 vrf vrf-r1 \ + nexthop via fe80:2::22 dev $rp12 \ + nexthop via fe80:3::23 dev $rp13 +} + multipath_test() { log_info "Running IPv4 multipath tests" multipath4_test 1 1 multipath4_test 2 1 multipath4_test 11 45 + + log_info "Running IPv6 multipath tests" + multipath6_test 1 1 + multipath6_test 2 1 + multipath6_test 11 45 } setup_prepare() -- cgit v1.3-14-g43fede From 2f19f2125d824fc607359f6d9248bd765edf7183 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:13 +0200 Subject: selftests: forwarding: Add tc offload check helper Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 6866f4a4bc4e..92e46426bd1d 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -296,6 +296,19 @@ forwarding_restore() sysctl -q -w net.ipv4.conf.all.forwarding=$ipv4_fwd } +tc_offload_check() +{ + for i in $(eval echo {1..$NUM_NETIFS}); do + ethtool -k ${NETIFS[p$i]} \ + | grep "hw-tc-offload: on" &> /dev/null + if [[ $? -ne 0 ]]; then + return 1 + fi + done + + return 0 +} + ############################################################################## # Tests -- cgit v1.3-14-g43fede From 4e4272d2a68dcdd2555774dba9d8b237fe0eb63d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:14 +0200 Subject: selftests: forwarding: Add MAC get helper Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 92e46426bd1d..083a16eb7803 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -270,6 +270,13 @@ link_stats_tx_packets_get() ip -j -s link show dev $if_name | jq '.[]["stats64"]["tx"]["packets"]' } +mac_get() +{ + local if_name=$1 + + ip -j link show dev $if_name | jq -r '.[]["address"]' +} + bridge_ageing_time_get() { local bridge=$1 -- cgit v1.3-14-g43fede From 781fe631fafda37402abdbc4647698a107e2284d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:15 +0200 Subject: selftests: forwarding: Allow to get netdev interfaces names from commandline Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 083a16eb7803..3385ba76ac19 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -45,6 +45,21 @@ if [[ ! -v NUM_NETIFS ]]; then exit 0 fi +############################################################################## +# Command line options handling + +count=0 + +while [[ $# -gt 0 ]]; do + if [[ "$count" -eq "0" ]]; then + unset NETIFS + declare -A NETIFS + fi + count=$((count + 1)) + NETIFS[p$count]="$1" + shift +done + ############################################################################## # Network interfaces configuration -- cgit v1.3-14-g43fede From 07e5c75184a11c46eddb08f2435ba4f3e7152e62 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:16 +0200 Subject: selftests: forwarding: Introduce tc flower matching tests Add first part of flower tests. This patch only contains dst/src ip/mac matching. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../testing/selftests/net/forwarding/tc_common.sh | 23 +++ .../testing/selftests/net/forwarding/tc_flower.sh | 196 +++++++++++++++++++++ 2 files changed, 219 insertions(+) create mode 100644 tools/testing/selftests/net/forwarding/tc_common.sh create mode 100755 tools/testing/selftests/net/forwarding/tc_flower.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_common.sh b/tools/testing/selftests/net/forwarding/tc_common.sh new file mode 100644 index 000000000000..acd0b520241c --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_common.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +tc_check_packets() +{ + local id=$1 + local handle=$2 + local count=$3 + local ret + + output="$(tc -j -s filter show $id)" + # workaround the jq bug which causes jq to return 0 in case input is "" + ret=$? + if [[ $ret -ne 0 ]]; then + return $ret + fi + echo $output | \ + jq -e ".[] \ + | select(.options.handle == $handle) \ + | select(.options.actions[0].stats.packets == $count)" \ + &> /dev/null + return $? +} diff --git a/tools/testing/selftests/net/forwarding/tc_flower.sh b/tools/testing/selftests/net/forwarding/tc_flower.sh new file mode 100755 index 000000000000..026a4ea4b2fb --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_flower.sh @@ -0,0 +1,196 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=2 +source lib.sh +source tc_common.sh + +tcflags="skip_hw" + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 198.51.100.1/24 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 198.51.100.1/24 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 198.51.100.2/24 + tc qdisc add dev $h2 clsact +} + +h2_destroy() +{ + tc qdisc del dev $h2 clsact + simple_if_fini $h2 192.0.2.2/24 198.51.100.2/24 +} + +match_dst_mac_test() +{ + local dummy_mac=de:ad:be:ef:aa:aa + + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_mac $dummy_mac action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_mac $h2mac action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_fail $? "Matched on a wrong filter" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct filter" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + log_test "dst_mac match ($tcflags)" +} + +match_src_mac_test() +{ + local dummy_mac=de:ad:be:ef:aa:aa + + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags src_mac $dummy_mac action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags src_mac $h1mac action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_fail $? "Matched on a wrong filter" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct filter" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + log_test "src_mac match ($tcflags)" +} + +match_dst_ip_test() +{ + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 198.51.100.2 action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_ip 192.0.2.2 action drop + tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \ + $tcflags dst_ip 192.0.2.0/24 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_fail $? "Matched on a wrong filter" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct filter" + + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Did not match on correct filter with mask" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower + + log_test "dst_ip match ($tcflags)" +} + +match_src_ip_test() +{ + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags src_ip 198.51.100.1 action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags src_ip 192.0.2.1 action drop + tc filter add dev $h2 ingress protocol ip pref 3 handle 103 flower \ + $tcflags src_ip 192.0.2.0/24 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_fail $? "Matched on a wrong filter" + + tc_check_packets "dev $h2 ingress" 102 1 + check_err $? "Did not match on correct filter" + + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 103 1 + check_err $? "Did not match on correct filter with mask" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 3 handle 103 flower + + log_test "src_ip match ($tcflags)" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + h2=${NETIFS[p2]} + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + vrf_prepare + + h1_create + h2_create +} + +cleanup() +{ + pre_cleanup + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +match_dst_mac_test +match_src_mac_test +match_dst_ip_test +match_src_ip_test + +tc_offload_check +if [[ $? -ne 0 ]]; then + log_info "Could not test offloaded functionality" +else + tcflags="skip_sw" + match_dst_mac_test + match_src_mac_test + match_dst_ip_test + match_src_ip_test +fi + +exit $EXIT_STATUS -- cgit v1.3-14-g43fede From bc13af291ebba244226b12e75d36a6eb6373a5d6 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:17 +0200 Subject: selftests: forwarding: Introduce tc actions tests Add first part of actions tests. This patch only contains tests of gact ok/drop/trap and mirred redirect egress. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../testing/selftests/net/forwarding/tc_actions.sh | 195 +++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_actions.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh new file mode 100755 index 000000000000..84234317a25d --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -0,0 +1,195 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=4 +source lib.sh +source tc_common.sh + +tcflags="skip_hw" + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 + tc qdisc add dev $h2 clsact +} + +h2_destroy() +{ + tc qdisc del dev $h2 clsact + simple_if_fini $h2 192.0.2.2/24 +} + +switch_create() +{ + simple_if_init $swp1 192.0.2.2/24 + tc qdisc add dev $swp1 clsact + + simple_if_init $swp2 192.0.2.1/24 +} + +switch_destroy() +{ + simple_if_fini $swp2 192.0.2.1/24 + + tc qdisc del dev $swp1 clsact + simple_if_fini $swp1 192.0.2.2/24 +} + +mirred_egress_redirect_test() +{ + RET=0 + + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_fail $? "Matched without redirect rule inserted" + + tc filter add dev $swp1 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action mirred egress redirect \ + dev $swp2 + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match incoming redirected packet" + + tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + + log_test "mirred egress redirect ($tcflags)" +} + +gact_drop_and_ok_test() +{ + RET=0 + + tc filter add dev $swp1 ingress protocol ip pref 2 handle 102 flower \ + skip_hw dst_ip 192.0.2.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $swp1 ingress" 102 1 + check_err $? "Packet was not dropped" + + tc filter add dev $swp1 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action ok + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $swp1 ingress" 101 1 + check_err $? "Did not see trapped packet" + + tc filter del dev $swp1 ingress protocol ip pref 2 handle 102 flower + tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower + + log_test "gact drop and ok ($tcflags)" +} + +gact_trap_test() +{ + RET=0 + + tc filter add dev $swp1 ingress protocol ip pref 1 handle 101 flower \ + skip_hw dst_ip 192.0.2.2 action drop + tc filter add dev $swp1 ingress protocol ip pref 3 handle 103 flower \ + $tcflags dst_ip 192.0.2.2 action mirred egress redirect \ + dev $swp2 + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $swp1 ingress" 101 1 + check_fail $? "Saw packet without trap rule inserted" + + tc filter add dev $swp1 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_ip 192.0.2.2 action trap + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $swp1 ingress" 102 1 + check_err $? "Packet was not trapped" + + tc_check_packets "dev $swp1 ingress" 101 1 + check_err $? "Did not see trapped packet" + + tc filter del dev $swp1 ingress protocol ip pref 3 handle 103 flower + tc filter del dev $swp1 ingress protocol ip pref 2 handle 102 flower + tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower + + log_test "trap ($tcflags)" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + swp1origmac=$(mac_get $swp1) + swp2origmac=$(mac_get $swp2) + ip link set $swp1 address $h2mac + ip link set $swp2 address $h1mac + + vrf_prepare + + h1_create + h2_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h2_destroy + h1_destroy + + vrf_cleanup + + ip link set $swp2 address $swp2origmac + ip link set $swp1 address $swp1origmac +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +gact_drop_and_ok_test +mirred_egress_redirect_test + +tc_offload_check +if [[ $? -ne 0 ]]; then + log_info "Could not test offloaded functionality" +else + tcflags="skip_sw" + gact_drop_and_ok_test + mirred_egress_redirect_test + gact_trap_test +fi + +exit $EXIT_STATUS -- cgit v1.3-14-g43fede From b13f245e844d1535597298ac0f0f0a94f56c239b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:18 +0200 Subject: selftests: forwarding: Introduce basic tc chains tests Tests chains matching and goto chain action. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../testing/selftests/net/forwarding/tc_chains.sh | 122 +++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_chains.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_chains.sh b/tools/testing/selftests/net/forwarding/tc_chains.sh new file mode 100755 index 000000000000..94c114ad8b44 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_chains.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=2 +source lib.sh +source tc_common.sh + +tcflags="skip_hw" + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 + tc qdisc add dev $h2 clsact +} + +h2_destroy() +{ + tc qdisc del dev $h2 clsact + simple_if_fini $h2 192.0.2.2/24 +} + +unreachable_chain_test() +{ + RET=0 + + tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ + flower $tcflags dst_mac $h2mac action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 1101 1 + check_fail $? "matched on filter in unreachable chain" + + tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ + flower + + log_test "unreachable chain ($tcflags)" +} + +gact_goto_chain_test() +{ + RET=0 + + tc filter add dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ + flower $tcflags dst_mac $h2mac action drop + tc filter add dev $h2 ingress protocol ip pref 2 handle 102 flower \ + $tcflags dst_mac $h2mac action drop + tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ + $tcflags dst_mac $h2mac action goto chain 1 + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "dev $h2 ingress" 102 1 + check_fail $? "Matched on a wrong filter" + + tc_check_packets "dev $h2 ingress" 101 1 + check_err $? "Did not match on correct filter with goto chain action" + + tc_check_packets "dev $h2 ingress" 1101 1 + check_err $? "Did not match on correct filter in chain 1" + + tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower + tc filter del dev $h2 ingress protocol ip pref 2 handle 102 flower + tc filter del dev $h2 ingress chain 1 protocol ip pref 1 handle 1101 \ + flower + + log_test "gact goto chain ($tcflags)" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + h2=${NETIFS[p2]} + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + vrf_prepare + + h1_create + h2_create +} + +cleanup() +{ + pre_cleanup + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +unreachable_chain_test +gact_goto_chain_test + +tc_offload_check +if [[ $? -ne 0 ]]; then + log_info "Could not test offloaded functionality" +else + tcflags="skip_sw" + unreachable_chain_test + gact_goto_chain_test +fi + +exit $EXIT_STATUS -- cgit v1.3-14-g43fede From 4908e24b812d74d0534e8b33edd58417aefa93d0 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 28 Feb 2018 12:25:19 +0200 Subject: selftests: forwarding: Introduce basic shared blocks tests Test shared block infrastructure. This is a basic test that shares TC block in between 2 clsact qdiscs. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 6 + .../selftests/net/forwarding/tc_shblocks.sh | 122 +++++++++++++++++++++ 2 files changed, 128 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/tc_shblocks.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 3385ba76ac19..23866a685f77 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -30,6 +30,12 @@ if [[ $? -ne 0 ]]; then exit 0 fi +tc filter help 2>&1 | grep block &> /dev/null +if [[ $? -ne 0 ]]; then + echo "SKIP: iproute2 too old, missing shared block support" + exit 0 +fi + if [[ ! -x "$(command -v jq)" ]]; then echo "SKIP: jq not installed" exit 0 diff --git a/tools/testing/selftests/net/forwarding/tc_shblocks.sh b/tools/testing/selftests/net/forwarding/tc_shblocks.sh new file mode 100755 index 000000000000..cfc8a2ace388 --- /dev/null +++ b/tools/testing/selftests/net/forwarding/tc_shblocks.sh @@ -0,0 +1,122 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=4 +source lib.sh +source tc_common.sh + +tcflags="skip_hw" + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.1/24 +} + +h2_destroy() +{ + simple_if_fini $h2 192.0.2.1/24 +} + +switch_create() +{ + simple_if_init $swp1 192.0.2.2/24 + tc qdisc add dev $swp1 ingress_block 22 egress_block 23 clsact + + simple_if_init $swp2 192.0.2.2/24 + tc qdisc add dev $swp2 ingress_block 22 egress_block 23 clsact +} + +switch_destroy() +{ + tc qdisc del dev $swp2 clsact + simple_if_fini $swp2 192.0.2.2/24 + + tc qdisc del dev $swp1 clsact + simple_if_fini $swp1 192.0.2.2/24 +} + +shared_block_test() +{ + RET=0 + + tc filter add block 22 protocol ip pref 1 handle 101 flower \ + $tcflags dst_ip 192.0.2.2 action drop + + $MZ $h1 -c 1 -p 64 -a $h1mac -b $swmac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "block 22" 101 1 + check_err $? "Did not match first incoming packet on a block" + + $MZ $h2 -c 1 -p 64 -a $h2mac -b $swmac -A 192.0.2.1 -B 192.0.2.2 \ + -t ip -q + + tc_check_packets "block 22" 101 2 + check_err $? "Did not match second incoming packet on a block" + + tc filter del block 22 protocol ip pref 1 handle 101 flower + + log_test "shared block ($tcflags)" +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + h1mac=$(mac_get $h1) + h2mac=$(mac_get $h2) + + swmac=$(mac_get $swp1) + swp2origmac=$(mac_get $swp2) + ip link set $swp2 address $swmac + + vrf_prepare + + h1_create + h2_create + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + h2_destroy + h1_destroy + + vrf_cleanup + + ip link set $swp2 address $swp2origmac +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +shared_block_test + +tc_offload_check +if [[ $? -ne 0 ]]; then + log_info "Could not test offloaded functionality" +else + tcflags="skip_sw" + shared_block_test +fi + +exit $EXIT_STATUS -- cgit v1.3-14-g43fede From cd4a6f3ab4d80cb919d15897eb3cbc85c2009d4b Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Mon, 26 Feb 2018 15:22:22 +1100 Subject: selftests/powerpc: Skip the subpage_prot tests if the syscall is unavailable The subpage_prot syscall is only functional when the system is using the Hash MMU. Since commit 5b2b80714796 ("powerpc/mm: Invalidate subpage_prot() system call on radix platforms") it returns ENOENT when the Radix MMU is active. Currently this just makes the test fail. Additionally the syscall is not available if the kernel is built with 4K pages, or if CONFIG_PPC_SUBPAGE_PROT=n, in which case it returns ENOSYS because the syscall is missing entirely. So check explicitly for ENOENT and ENOSYS and skip if we see either of those. Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/mm/subpage_prot.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/powerpc/mm/subpage_prot.c b/tools/testing/selftests/powerpc/mm/subpage_prot.c index 35ade7406dcd..3ae77ba93208 100644 --- a/tools/testing/selftests/powerpc/mm/subpage_prot.c +++ b/tools/testing/selftests/powerpc/mm/subpage_prot.c @@ -135,6 +135,16 @@ static int run_test(void *addr, unsigned long size) return 0; } +static int syscall_available(void) +{ + int rc; + + errno = 0; + rc = syscall(__NR_subpage_prot, 0, 0, 0); + + return rc == 0 || (errno != ENOENT && errno != ENOSYS); +} + int test_anon(void) { unsigned long align; @@ -145,6 +155,8 @@ int test_anon(void) void *mallocblock; unsigned long mallocsize; + SKIP_IF(!syscall_available()); + if (getpagesize() != 0x10000) { fprintf(stderr, "Kernel page size must be 64K!\n"); return 1; @@ -180,6 +192,8 @@ int test_file(void) off_t filesize; int fd; + SKIP_IF(!syscall_available()); + fd = open(file_name, O_RDWR); if (fd == -1) { perror("failed to open file"); -- cgit v1.3-14-g43fede From 198979be6c16aa62025d5a47680f2c7849b7e64c Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 1 Mar 2018 13:49:30 -0800 Subject: selftests: forwarding: Only check tc version for tc tests Capabilities of tc command are irrelevant for router tests: $ ./router.sh SKIP: iproute2 too old, missing shared block support Add a CHECK_TC flag and only check tc capabilities if set. Add flag to tc_common.sh and have it sourced before lib.sh Also, if the command lacks some feature the test should exit non-0. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- .../selftests/net/forwarding/bridge_vlan_aware.sh | 1 + tools/testing/selftests/net/forwarding/lib.sh | 29 ++++++++++++++-------- .../testing/selftests/net/forwarding/tc_actions.sh | 2 +- .../testing/selftests/net/forwarding/tc_chains.sh | 2 +- .../testing/selftests/net/forwarding/tc_common.sh | 2 ++ .../testing/selftests/net/forwarding/tc_flower.sh | 2 +- .../selftests/net/forwarding/tc_shblocks.sh | 2 +- 7 files changed, 25 insertions(+), 15 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh index 651998e70557..75d922438bc9 100755 --- a/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_aware.sh @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-2.0 NUM_NETIFS=4 +CHECK_TC="yes" source lib.sh h1_create() diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 23866a685f77..d0af52109360 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -19,26 +19,33 @@ fi ############################################################################## # Sanity checks +check_tc_version() +{ + tc -j &> /dev/null + if [[ $? -ne 0 ]]; then + echo "SKIP: iproute2 too old; tc is missing JSON support" + exit 1 + fi + + tc filter help 2>&1 | grep block &> /dev/null + if [[ $? -ne 0 ]]; then + echo "SKIP: iproute2 too old; tc is missing shared block support" + exit 1 + fi +} + if [[ "$(id -u)" -ne 0 ]]; then echo "SKIP: need root privileges" exit 0 fi -tc -j &> /dev/null -if [[ $? -ne 0 ]]; then - echo "SKIP: iproute2 too old, missing JSON support" - exit 0 -fi - -tc filter help 2>&1 | grep block &> /dev/null -if [[ $? -ne 0 ]]; then - echo "SKIP: iproute2 too old, missing shared block support" - exit 0 +if [[ "$CHECK_TC" = "yes" ]]; then + check_tc_version fi if [[ ! -x "$(command -v jq)" ]]; then echo "SKIP: jq not installed" - exit 0 + exit 1 fi if [[ ! -x "$(command -v $MZ)" ]]; then diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh index 84234317a25d..8ab5cf0a960b 100755 --- a/tools/testing/selftests/net/forwarding/tc_actions.sh +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -2,8 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 NUM_NETIFS=4 -source lib.sh source tc_common.sh +source lib.sh tcflags="skip_hw" diff --git a/tools/testing/selftests/net/forwarding/tc_chains.sh b/tools/testing/selftests/net/forwarding/tc_chains.sh index 94c114ad8b44..2fd15226974b 100755 --- a/tools/testing/selftests/net/forwarding/tc_chains.sh +++ b/tools/testing/selftests/net/forwarding/tc_chains.sh @@ -2,8 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 NUM_NETIFS=2 -source lib.sh source tc_common.sh +source lib.sh tcflags="skip_hw" diff --git a/tools/testing/selftests/net/forwarding/tc_common.sh b/tools/testing/selftests/net/forwarding/tc_common.sh index acd0b520241c..9d3b64a2a264 100644 --- a/tools/testing/selftests/net/forwarding/tc_common.sh +++ b/tools/testing/selftests/net/forwarding/tc_common.sh @@ -1,6 +1,8 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 +CHECK_TC="yes" + tc_check_packets() { local id=$1 diff --git a/tools/testing/selftests/net/forwarding/tc_flower.sh b/tools/testing/selftests/net/forwarding/tc_flower.sh index 026a4ea4b2fb..032b882adfc0 100755 --- a/tools/testing/selftests/net/forwarding/tc_flower.sh +++ b/tools/testing/selftests/net/forwarding/tc_flower.sh @@ -2,8 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 NUM_NETIFS=2 -source lib.sh source tc_common.sh +source lib.sh tcflags="skip_hw" diff --git a/tools/testing/selftests/net/forwarding/tc_shblocks.sh b/tools/testing/selftests/net/forwarding/tc_shblocks.sh index cfc8a2ace388..077b98048ef4 100755 --- a/tools/testing/selftests/net/forwarding/tc_shblocks.sh +++ b/tools/testing/selftests/net/forwarding/tc_shblocks.sh @@ -2,8 +2,8 @@ # SPDX-License-Identifier: GPL-2.0 NUM_NETIFS=4 -source lib.sh source tc_common.sh +source lib.sh tcflags="skip_hw" -- cgit v1.3-14-g43fede From 5ee0902a0d584bd765165448fec8bb1409d5d027 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 1 Mar 2018 13:49:31 -0800 Subject: selftests: forwarding: Handle 0 for packet difference in multipath tests If the packet stats have a difference of 0, the test output shows: INFO: Expected ratio 2.00 Measured ratio Runtime error (func=(main), adr=9): Divide by zero (standard_in) 2: syntax error (standard_in) 1: syntax error ./router_multipath.sh: line 187: test: : integer expression expected TEST: Multipath [FAIL] Too large discrepancy between expected and measured ratios Handle the 0 and display a cleaner message: INFO: Running IPv6 multipath tests TEST: Multipath [FAIL] Packet difference is 0 Signed-off-by: David Ahern Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/router_multipath.sh | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index d31888e3133e..c1a437c5b15f 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -168,6 +168,13 @@ multipath_eval() RET=0 + if [[ "$packets_rp12" -eq "0" || "$packets_rp13" -eq "0" ]]; then + check_err 1 "Packet difference is 0" + log_test "Multipath" + log_info "Expected ratio $weights_ratio" + return + fi + if [[ "$weight_rp12" -gt "$weight_rp13" ]]; then weights_ratio=$(echo "scale=2; $weight_rp12 / $weight_rp13" \ | bc -l) -- cgit v1.3-14-g43fede From 993d337c242e292dca89de4558dd8ebfc216fc83 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 1 Mar 2018 13:49:32 -0800 Subject: selftests: forwarding: Use PING6 instead of ping for ipv6 multipath test On Debian jessie ping can not handle IPv6 addresses so the command fails. Use PING6 which is set to ping6. Signed-off-by: David Ahern Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/router_multipath.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index c1a437c5b15f..745fb40bfa44 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -249,7 +249,7 @@ multipath6_test() # Generate 16384 echo requests, each with a random flow label. for _ in $(seq 1 16384); do - ip vrf exec vrf-h1 ping 2001:db8:2::2 -F 0 -c 1 -q &> /dev/null + ip vrf exec vrf-h1 $PING6 2001:db8:2::2 -F 0 -c 1 -q &> /dev/null done t1_rp12=$(link_stats_tx_packets_get $rp12) -- cgit v1.3-14-g43fede From 36b4c0adad2662464a5a392b592311524bd3a854 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 1 Mar 2018 13:49:33 -0800 Subject: selftests: forwarding: Add description to the multipath tests Add a better description to the summary for multipath tests. e.g., INFO: Running IPv6 multipath tests TEST: ECMP [PASS] INFO: Expected ratio 1.00 Measured ratio 1.02 TEST: Weighted MP 2:1 [PASS] INFO: Expected ratio 2.00 Measured ratio 2.02 TEST: Weighted MP 11:45 [PASS] INFO: Expected ratio 4.09 Measured ratio 4.03 Signed-off-by: David Ahern Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/router_multipath.sh | 37 ++++++++++++---------- 1 file changed, 20 insertions(+), 17 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index 745fb40bfa44..55595305a604 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -160,10 +160,11 @@ router2_destroy() multipath_eval() { - local weight_rp12=$1 - local weight_rp13=$2 - local packets_rp12=$3 - local packets_rp13=$4 + local desc="$1" + local weight_rp12=$2 + local weight_rp13=$3 + local packets_rp12=$4 + local packets_rp13=$5 local weights_ratio packets_ratio diff RET=0 @@ -192,14 +193,15 @@ multipath_eval() test "$(echo "$diff / $weights_ratio > 0.1" | bc -l)" -eq 0 check_err $? "Too large discrepancy between expected and measured ratios" - log_test "Multipath" + log_test "$desc" log_info "Expected ratio $weights_ratio Measured ratio $packets_ratio" } multipath4_test() { - local weight_rp12=$1 - local weight_rp13=$2 + local desc="$1" + local weight_rp12=$2 + local weight_rp13=$3 local t0_rp12 t0_rp13 t1_rp12 t1_rp13 local packets_rp12 packets_rp13 local hash_policy @@ -224,7 +226,7 @@ multipath4_test() let "packets_rp12 = $t1_rp12 - $t0_rp12" let "packets_rp13 = $t1_rp13 - $t0_rp13" - multipath_eval $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 + multipath_eval "$desc" $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 # Restore settings. ip route replace 198.51.100.0/24 vrf vrf-r1 \ @@ -235,8 +237,9 @@ multipath4_test() multipath6_test() { - local weight_rp12=$1 - local weight_rp13=$2 + local desc="$1" + local weight_rp12=$2 + local weight_rp13=$3 local t0_rp12 t0_rp13 t1_rp12 t1_rp13 local packets_rp12 packets_rp13 @@ -257,7 +260,7 @@ multipath6_test() let "packets_rp12 = $t1_rp12 - $t0_rp12" let "packets_rp13 = $t1_rp13 - $t0_rp13" - multipath_eval $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 + multipath_eval "$desc" $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 ip route replace 2001:db8:2::/64 vrf vrf-r1 \ nexthop via fe80:2::22 dev $rp12 \ @@ -267,14 +270,14 @@ multipath6_test() multipath_test() { log_info "Running IPv4 multipath tests" - multipath4_test 1 1 - multipath4_test 2 1 - multipath4_test 11 45 + multipath4_test "ECMP" 1 1 + multipath4_test "Weighted MP 2:1" 2 1 + multipath4_test "Weighted MP 11:45" 11 45 log_info "Running IPv6 multipath tests" - multipath6_test 1 1 - multipath6_test 2 1 - multipath6_test 11 45 + multipath6_test "ECMP" 1 1 + multipath6_test "Weighted MP 2:1" 2 1 + multipath6_test "Weighted MP 11:45" 11 45 } setup_prepare() -- cgit v1.3-14-g43fede From ba004a2955f759946d8c98ca1a9c8d09818b1223 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 1 Mar 2018 13:04:28 -0700 Subject: selftests: memory-hotplug: fix emit_tests regression Commit 16c513b13477 ("selftests: memory-hotplug: silence test command echo") introduced regression in emit_tests and results in the following failure when selftests are installed and run. Fix it. Running tests in memory-hotplug ======================================== ./run_kselftest.sh: line 121: @./mem-on-off-test.sh: No such file or directory selftests: memory-hotplug [FAIL] Fixes: 16c513b13477 (selftests: memory-hotplug: silence test command echo") Reported-by: Naresh Kamboju Tested-by: Anders Roxell Signed-off-by: Shuah Khan --- tools/testing/selftests/memory-hotplug/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile index 183b46883875..686da510f989 100644 --- a/tools/testing/selftests/memory-hotplug/Makefile +++ b/tools/testing/selftests/memory-hotplug/Makefile @@ -5,7 +5,8 @@ include ../lib.mk TEST_PROGS := mem-on-off-test.sh override RUN_TESTS := @./mem-on-off-test.sh -r 2 && echo "selftests: memory-hotplug [PASS]" || echo "selftests: memory-hotplug [FAIL]" -override EMIT_TESTS := echo "$(RUN_TESTS)" + +override EMIT_TESTS := echo "$(subst @,,$(RUN_TESTS))" run_full_test: @/bin/bash ./mem-on-off-test.sh && echo "memory-hotplug selftests: [PASS]" || echo "memory-hotplug selftests: [FAIL]" -- cgit v1.3-14-g43fede From 91a5c1ecba9f23f247b3772e6d54aabfebc0e300 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 2 Mar 2018 08:32:21 -0800 Subject: selftests: forwarding: Add multipath test for L4 hashing Add IPv6 multipath test using L4 hashing. Created with inputs from Ido Schimmel. Signed-off-by: David Ahern Reviewed-by: Ido Schimmel Tested-by: Ido Schimmel Signed-off-by: David S. Miller --- .../selftests/net/forwarding/router_multipath.sh | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/router_multipath.sh b/tools/testing/selftests/net/forwarding/router_multipath.sh index 55595305a604..3bc351008db6 100755 --- a/tools/testing/selftests/net/forwarding/router_multipath.sh +++ b/tools/testing/selftests/net/forwarding/router_multipath.sh @@ -235,6 +235,45 @@ multipath4_test() sysctl -q -w net.ipv4.fib_multipath_hash_policy=$hash_policy } +multipath6_l4_test() +{ + local desc="$1" + local weight_rp12=$2 + local weight_rp13=$3 + local t0_rp12 t0_rp13 t1_rp12 t1_rp13 + local packets_rp12 packets_rp13 + local hash_policy + + # Transmit multiple flows from h1 to h2 and make sure they are + # distributed between both multipath links (rp12 and rp13) + # according to the configured weights. + hash_policy=$(sysctl -n net.ipv6.fib_multipath_hash_policy) + sysctl -q -w net.ipv6.fib_multipath_hash_policy=1 + + ip route replace 2001:db8:2::/64 vrf vrf-r1 \ + nexthop via fe80:2::22 dev $rp12 weight $weight_rp12 \ + nexthop via fe80:3::23 dev $rp13 weight $weight_rp13 + + t0_rp12=$(link_stats_tx_packets_get $rp12) + t0_rp13=$(link_stats_tx_packets_get $rp13) + + $MZ $h1 -6 -q -p 64 -A 2001:db8:1::2 -B 2001:db8:2::2 \ + -d 1msec -t udp "sp=1024,dp=0-32768" + + t1_rp12=$(link_stats_tx_packets_get $rp12) + t1_rp13=$(link_stats_tx_packets_get $rp13) + + let "packets_rp12 = $t1_rp12 - $t0_rp12" + let "packets_rp13 = $t1_rp13 - $t0_rp13" + multipath_eval "$desc" $weight_rp12 $weight_rp13 $packets_rp12 $packets_rp13 + + ip route replace 2001:db8:2::/64 vrf vrf-r1 \ + nexthop via fe80:2::22 dev $rp12 \ + nexthop via fe80:3::23 dev $rp13 + + sysctl -q -w net.ipv6.fib_multipath_hash_policy=$hash_policy +} + multipath6_test() { local desc="$1" @@ -278,6 +317,11 @@ multipath_test() multipath6_test "ECMP" 1 1 multipath6_test "Weighted MP 2:1" 2 1 multipath6_test "Weighted MP 11:45" 11 45 + + log_info "Running IPv6 L4 hash multipath tests" + multipath6_l4_test "ECMP" 1 1 + multipath6_l4_test "Weighted MP 2:1" 2 1 + multipath6_l4_test "Weighted MP 11:45" 11 45 } setup_prepare() -- cgit v1.3-14-g43fede From efab163bbc19e5dbd2b7756c1f26defc9c27d6ba Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Wed, 28 Feb 2018 15:36:19 -0500 Subject: tools: tc-testing: Add notap option Add a command line arg to suppress tap output. Handy in case all the tap output is being supplied by the plugins. Signed-off-by: Brenda J. Butler Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 34 +++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 7b50775abaf6..241eea37e4a4 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -241,12 +241,17 @@ def test_runner(pm, args, filtered_tests): testlist = filtered_tests tcount = len(testlist) index = 1 - tap = str(index) + ".." + str(tcount) + "\n" + tap = '' badtest = None stage = None emergency_exit = False emergency_exit_message = '' + if args.notap: + if args.verbose: + tap = 'notap requested: omitting test plan\n' + else: + tap = str(index) + ".." + str(tcount) + "\n" try: pm.call_pre_suite(tcount, [tidx['id'] for tidx in testlist]) except Exception as ee: @@ -303,15 +308,16 @@ def test_runner(pm, args, filtered_tests): # if we failed in setup or teardown, # fill in the remaining tests with ok-skipped count = index - tap += 'about to flush the tap output if tests need to be skipped\n' - if tcount + 1 != index: - for tidx in testlist[index - 1:]: - msg = 'skipped - previous {} failed'.format(stage) - tap += 'ok {} - {} # {} {} {}\n'.format( - count, tidx['id'], msg, index, badtest.get('id', '--Unknown--')) - count += 1 - - tap += 'done flushing skipped test tap output\n' + if not args.notap: + tap += 'about to flush the tap output if tests need to be skipped\n' + if tcount + 1 != index: + for tidx in testlist[index - 1:]: + msg = 'skipped - previous {} failed'.format(stage) + tap += 'ok {} - {} # {} {} {}\n'.format( + count, tidx['id'], msg, index, badtest.get('id', '--Unknown--')) + count += 1 + + tap += 'done flushing skipped test tap output\n' pm.call_post_suite(index) return tap @@ -389,6 +395,9 @@ def set_args(parser): parser.add_argument( '-v', '--verbose', action='count', default=0, help='Show the commands that are being run') + parser.add_argument( + '-N', '--notap', action='store_true', + help='Suppress tap results for command under test') parser.add_argument('-d', '--device', help='Execute the test case in flower category') return parser @@ -601,7 +610,10 @@ def set_operation_mode(pm, args): catresults = test_runner(pm, args, alltests) else: catresults = 'No tests found\n' - print('All test results: \n\n{}'.format(catresults)) + if args.notap: + print('Tap output suppression requested\n') + else: + print('All test results: \n\n{}'.format(catresults)) def main(): """ -- cgit v1.3-14-g43fede From 053533fc7577ddbe14b2a7c4a8fc70ce3fbb3547 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Fri, 2 Mar 2018 11:22:20 +0900 Subject: selftests: rtnetlink: remove testns on test fail This patch removes testns after test failure so that next test can continue with clean ns Signed-off-by: Prashant Bhole Acked-by: William Tu Signed-off-by: David S. Miller --- tools/testing/selftests/net/rtnetlink.sh | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh index a622eeecc3a6..e6f485235435 100755 --- a/tools/testing/selftests/net/rtnetlink.sh +++ b/tools/testing/selftests/net/rtnetlink.sh @@ -517,6 +517,7 @@ kci_test_gretap() ip link help gretap 2>&1 | grep -q "^Usage:" if [ $? -ne 0 ];then echo "SKIP: gretap: iproute2 too old" + ip netns del "$testns" return 1 fi @@ -543,6 +544,7 @@ kci_test_gretap() if [ $ret -ne 0 ]; then echo "FAIL: gretap" + ip netns del "$testns" return 1 fi echo "PASS: gretap" @@ -565,6 +567,7 @@ kci_test_ip6gretap() ip link help ip6gretap 2>&1 | grep -q "^Usage:" if [ $? -ne 0 ];then echo "SKIP: ip6gretap: iproute2 too old" + ip netns del "$testns" return 1 fi @@ -591,6 +594,7 @@ kci_test_ip6gretap() if [ $ret -ne 0 ]; then echo "FAIL: ip6gretap" + ip netns del "$testns" return 1 fi echo "PASS: ip6gretap" @@ -655,6 +659,7 @@ kci_test_erspan() if [ $ret -ne 0 ]; then echo "FAIL: erspan" + ip netns del "$testns" return 1 fi echo "PASS: erspan" @@ -720,6 +725,7 @@ kci_test_ip6erspan() if [ $ret -ne 0 ]; then echo "FAIL: ip6erspan" + ip netns del "$testns" return 1 fi echo "PASS: ip6erspan" -- cgit v1.3-14-g43fede From 79f3a8e662c1ae6e85737eca9ae7d6b52cf87815 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Fri, 2 Mar 2018 14:44:39 +0100 Subject: tc-testing: skbmod: fix match value of ethertype iproute2 print_skbmod() prints the configured ethertype using format 0x%X: therefore, test 9aa8 systematically fails, because it configures action #4 using ethertype 0x0031, and expects 0x0031 when it reads it back. Changing the expected value to 0x31 lets the test result 'not ok' become 'ok'. tested with: # ./tdc.py -e 9aa8 Test 9aa8: Get a single skbmod action from a list All test results: 1..1 ok 1 9aa8 Get a single skbmod action from a list Fixes: cf797ac49b94 ("tc-testing: Add test cases for police and skbmod") Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json index e34075059c26..90bba48c3f07 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json @@ -315,7 +315,7 @@ "cmdUnderTest": "$TC actions ls action skbmod", "expExitCode": "0", "verifyCmd": "$TC actions get action skbmod index 4", - "matchPattern": "action order [0-9]*: skbmod pipe set etype 0x0031", + "matchPattern": "action order [0-9]*: skbmod pipe set etype 0x31", "matchCount": "1", "teardown": [ "$TC actions flush action skbmod" -- cgit v1.3-14-g43fede From 200066a5bdcc2d4527562ee3760d405b6ec5b5d5 Mon Sep 17 00:00:00 2001 From: Arkadi Sharshevsky Date: Sun, 4 Mar 2018 16:35:26 +0200 Subject: selftests: Extend the tc action test for action mirror Currently the tc action test is used only to test mirred redirect action. This patch extends it for mirred mirror. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: Arkadi Sharshevsky Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/tc_actions.sh | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh index 8ab5cf0a960b..6b18ba2d3982 100755 --- a/tools/testing/selftests/net/forwarding/tc_actions.sh +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -45,8 +45,10 @@ switch_destroy() simple_if_fini $swp1 192.0.2.2/24 } -mirred_egress_redirect_test() +mirred_egress_test() { + local action=$1 + RET=0 tc filter add dev $h2 ingress protocol ip pref 1 handle 101 flower \ @@ -59,19 +61,19 @@ mirred_egress_redirect_test() check_fail $? "Matched without redirect rule inserted" tc filter add dev $swp1 ingress protocol ip pref 1 handle 101 flower \ - $tcflags dst_ip 192.0.2.2 action mirred egress redirect \ + $tcflags dst_ip 192.0.2.2 action mirred egress $action \ dev $swp2 $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ -t ip -q tc_check_packets "dev $h2 ingress" 101 1 - check_err $? "Did not match incoming redirected packet" + check_err $? "Did not match incoming $action packet" tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower tc filter del dev $h2 ingress protocol ip pref 1 handle 101 flower - log_test "mirred egress redirect ($tcflags)" + log_test "mirred egress $action ($tcflags)" } gact_drop_and_ok_test() @@ -180,7 +182,8 @@ setup_prepare setup_wait gact_drop_and_ok_test -mirred_egress_redirect_test +mirred_egress_test "redirect" +mirred_egress_test "mirror" tc_offload_check if [[ $? -ne 0 ]]; then @@ -188,7 +191,8 @@ if [[ $? -ne 0 ]]; then else tcflags="skip_sw" gact_drop_and_ok_test - mirred_egress_redirect_test + mirred_egress_test "redirect" + mirred_egress_test "mirror" gact_trap_test fi -- cgit v1.3-14-g43fede From 190f887c3cd0d07e53a7d44162c951451f4f5528 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 4 Mar 2018 17:37:47 -0800 Subject: selftests: forwarding: Add suppport to create veth interfaces For tests using veth interfaces, the test infrastructure can create the netdevs if they do not exist. Arguably this is a preferred approach since the tests require p$N and p$(N+1) to be pairs. Signed-off-by: David Ahern Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- .../net/forwarding/forwarding.config.sample | 5 ++++ tools/testing/selftests/net/forwarding/lib.sh | 35 ++++++++++++++++++++++ 2 files changed, 40 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/forwarding.config.sample b/tools/testing/selftests/net/forwarding/forwarding.config.sample index ab235c124f20..df54c9eb5100 100644 --- a/tools/testing/selftests/net/forwarding/forwarding.config.sample +++ b/tools/testing/selftests/net/forwarding/forwarding.config.sample @@ -14,6 +14,11 @@ NETIFS[p6]=veth5 NETIFS[p7]=veth6 NETIFS[p8]=veth7 +NETIF_TYPE=veth + +# only virtual interfaces (veth) can be created by test infra +#NETIF_CREATE=yes + ############################################################################## # Defines diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index d0af52109360..273511ef2b43 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -76,6 +76,41 @@ done ############################################################################## # Network interfaces configuration +create_netif_veth() +{ + local i + + for i in $(eval echo {1..$NUM_NETIFS}); do + local j=$((i+1)) + + ip link show dev ${NETIFS[p$i]} &> /dev/null + if [[ $? -ne 0 ]]; then + ip link add ${NETIFS[p$i]} type veth \ + peer name ${NETIFS[p$j]} + if [[ $? -ne 0 ]]; then + echo "Failed to create netif" + exit 1 + fi + fi + i=$j + done +} + +create_netif() +{ + case "$NETIF_TYPE" in + veth) create_netif_veth + ;; + *) echo "Can not create interfaces of type \'$NETIF_TYPE\'" + exit 1 + ;; + esac +} + +if [[ "$NETIF_CREATE" = "yes" ]]; then + create_netif +fi + for i in $(eval echo {1..$NUM_NETIFS}); do ip link show dev ${NETIFS[p$i]} &> /dev/null if [[ $? -ne 0 ]]; then -- cgit v1.3-14-g43fede From 829dd7d642c90b641f14aed03a722a4d3e058083 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Thu, 15 Feb 2018 17:24:44 -0800 Subject: selftests: ion: Remove some prints There's no need to print messages each time we alloc and free. Remove them. Signed-off-by: Laura Abbott Signed-off-by: Shuah Khan --- tools/testing/selftests/android/ion/ionutils.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/android/ion/ionutils.c b/tools/testing/selftests/android/ion/ionutils.c index ce69c14f51fa..7d1d37c4ef6a 100644 --- a/tools/testing/selftests/android/ion/ionutils.c +++ b/tools/testing/selftests/android/ion/ionutils.c @@ -80,11 +80,6 @@ int ion_export_buffer_fd(struct ion_buffer_info *ion_info) heap_id = MAX_HEAP_COUNT + 1; for (i = 0; i < query.cnt; i++) { if (heap_data[i].type == ion_info->heap_type) { - printf("--------------------------------------\n"); - printf("heap type: %d\n", heap_data[i].type); - printf(" heap id: %d\n", heap_data[i].heap_id); - printf("heap name: %s\n", heap_data[i].name); - printf("--------------------------------------\n"); heap_id = heap_data[i].heap_id; break; } @@ -204,7 +199,6 @@ void ion_close_buffer_fd(struct ion_buffer_info *ion_info) /* Finally, close the client fd */ if (ion_info->ionfd > 0) close(ion_info->ionfd); - printf("<%s>: buffer release successfully....\n", __func__); } } -- cgit v1.3-14-g43fede From ac93f7046a5371ff08268965c9a696bf97bec105 Mon Sep 17 00:00:00 2001 From: Laura Abbott Date: Thu, 15 Feb 2018 17:24:45 -0800 Subject: selftests: ion: Add simple test with the vgem driver Ion is designed to be a framework used by other clients who perform operations on the buffer. Use the DRM vgem client as a simple consumer. In conjunction with the dma-buf sync ioctls, this tests the full attach/map path for the system heap. Signed-off-by: Laura Abbott Reviewed-by: Daniel Vetter Signed-off-by: Shuah Khan --- tools/testing/selftests/android/ion/Makefile | 3 +- tools/testing/selftests/android/ion/config | 1 + tools/testing/selftests/android/ion/ionmap_test.c | 136 ++++++++++++++++++++++ 3 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/android/ion/ionmap_test.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/android/ion/Makefile b/tools/testing/selftests/android/ion/Makefile index 96e0c448b39d..d23b6d537d8b 100644 --- a/tools/testing/selftests/android/ion/Makefile +++ b/tools/testing/selftests/android/ion/Makefile @@ -2,7 +2,7 @@ INCLUDEDIR := -I. -I../../../../../drivers/staging/android/uapi/ CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g -TEST_GEN_FILES := ionapp_export ionapp_import +TEST_GEN_FILES := ionapp_export ionapp_import ionmap_test all: $(TEST_GEN_FILES) @@ -14,3 +14,4 @@ include ../../lib.mk $(OUTPUT)/ionapp_export: ionapp_export.c ipcsocket.c ionutils.c $(OUTPUT)/ionapp_import: ionapp_import.c ipcsocket.c ionutils.c +$(OUTPUT)/ionmap_test: ionmap_test.c ionutils.c diff --git a/tools/testing/selftests/android/ion/config b/tools/testing/selftests/android/ion/config index 19db6ca9aa2b..b4ad748a9dd9 100644 --- a/tools/testing/selftests/android/ion/config +++ b/tools/testing/selftests/android/ion/config @@ -2,3 +2,4 @@ CONFIG_ANDROID=y CONFIG_STAGING=y CONFIG_ION=y CONFIG_ION_SYSTEM_HEAP=y +CONFIG_DRM_VGEM=y diff --git a/tools/testing/selftests/android/ion/ionmap_test.c b/tools/testing/selftests/android/ion/ionmap_test.c new file mode 100644 index 000000000000..dab36b06b37d --- /dev/null +++ b/tools/testing/selftests/android/ion/ionmap_test.c @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include "ion.h" +#include "ionutils.h" + +int check_vgem(int fd) +{ + drm_version_t version = { 0 }; + char name[5]; + int ret; + + version.name_len = 4; + version.name = name; + + ret = ioctl(fd, DRM_IOCTL_VERSION, &version); + if (ret) + return 1; + + return strcmp(name, "vgem"); +} + +int open_vgem(void) +{ + int i, fd; + const char *drmstr = "/dev/dri/card"; + + fd = -1; + for (i = 0; i < 16; i++) { + char name[80]; + + sprintf(name, "%s%u", drmstr, i); + + fd = open(name, O_RDWR); + if (fd < 0) + continue; + + if (check_vgem(fd)) { + close(fd); + continue; + } else { + break; + } + + } + return fd; +} + +int import_vgem_fd(int vgem_fd, int dma_buf_fd, uint32_t *handle) +{ + struct drm_prime_handle import_handle = { 0 }; + int ret; + + import_handle.fd = dma_buf_fd; + import_handle.flags = 0; + import_handle.handle = 0; + + ret = ioctl(vgem_fd, DRM_IOCTL_PRIME_FD_TO_HANDLE, &import_handle); + if (ret == 0) + *handle = import_handle.handle; + return ret; +} + +void close_handle(int vgem_fd, uint32_t handle) +{ + struct drm_gem_close close = { 0 }; + + close.handle = handle; + ioctl(vgem_fd, DRM_IOCTL_GEM_CLOSE, &close); +} + +int main() +{ + int ret, vgem_fd; + struct ion_buffer_info info; + uint32_t handle = 0; + struct dma_buf_sync sync = { 0 }; + + info.heap_type = ION_HEAP_TYPE_SYSTEM; + info.heap_size = 4096; + info.flag_type = ION_FLAG_CACHED; + + ret = ion_export_buffer_fd(&info); + if (ret < 0) { + printf("ion buffer alloc failed\n"); + return -1; + } + + vgem_fd = open_vgem(); + if (vgem_fd < 0) { + ret = vgem_fd; + printf("Failed to open vgem\n"); + goto out_ion; + } + + ret = import_vgem_fd(vgem_fd, info.buffd, &handle); + + if (ret < 0) { + printf("Failed to import buffer\n"); + goto out_vgem; + } + + sync.flags = DMA_BUF_SYNC_START | DMA_BUF_SYNC_RW; + ret = ioctl(info.buffd, DMA_BUF_IOCTL_SYNC, &sync); + if (ret) + printf("sync start failed %d\n", errno); + + memset(info.buffer, 0xff, 4096); + + sync.flags = DMA_BUF_SYNC_END | DMA_BUF_SYNC_RW; + ret = ioctl(info.buffd, DMA_BUF_IOCTL_SYNC, &sync); + if (ret) + printf("sync end failed %d\n", errno); + + close_handle(vgem_fd, handle); + ret = 0; + +out_vgem: + close(vgem_fd); +out_ion: + ion_close_buffer_fd(&info); + printf("done.\n"); + return ret; +} -- cgit v1.3-14-g43fede From 10f531f6748228583b8c4244216e9e3f34d47379 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 21 Feb 2018 17:11:54 -0700 Subject: selftests: kselftest framework: add handling for TAP header level Introduce environment variable KSFT_TAP_LEVEL to avoid printing nested TAP headers for each test. lib.mk run_tests target prints TAP header before invoking the test program or test script. Tests need a way to suppress TAP headers if it is already printed out. This new environment variable adds a way for ksft_print_header() print TAP header only when KSFT_TAP_LEVEL isn't set. lib.mk run_tests and test program should print TAP header and set KSFT_TAP_LEVEL to avoid a second TAP header to be printed. selftests Makefile should export KSFT_TAP_LEVEL and add TAP Header echo to the run_kselftest.sh script from emit_tests target handling. Signed-off-by: Shuah Khan --- tools/testing/selftests/kselftest.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h index 1a52b03962a3..1b9d8ecdebce 100644 --- a/tools/testing/selftests/kselftest.h +++ b/tools/testing/selftests/kselftest.h @@ -57,7 +57,8 @@ static inline int ksft_get_error_cnt(void) { return ksft_cnt.ksft_error; } static inline void ksft_print_header(void) { - printf("TAP version 13\n"); + if (!(getenv("KSFT_TAP_LEVEL"))) + printf("TAP version 13\n"); } static inline void ksft_print_cnts(void) -- cgit v1.3-14-g43fede From 771cbc3bcbb59084766a501772853f2de7009534 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 21 Feb 2018 17:22:08 -0700 Subject: selftests: lib.mk set KSFT_TAP_LEVEL to prevent nested TAP headers Set KSFT_TAP_LEVEL before running tests to prevent nested TAP header printing from tests. Signed-off-by: Shuah Khan --- tools/testing/selftests/lib.mk | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk index 7de482a0519d..195e9d4739a9 100644 --- a/tools/testing/selftests/lib.mk +++ b/tools/testing/selftests/lib.mk @@ -20,6 +20,7 @@ all: $(TEST_GEN_PROGS) $(TEST_GEN_PROGS_EXTENDED) $(TEST_GEN_FILES) .ONESHELL: define RUN_TESTS + @export KSFT_TAP_LEVEL=`echo 1`; @test_num=`echo 0`; @echo "TAP version 13"; @for TEST in $(1); do \ -- cgit v1.3-14-g43fede From 44f013522c3abbfb86e940026e3409dbb6e4317d Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 21 Feb 2018 17:25:55 -0700 Subject: selftests: Makefile set KSFT_TAP_LEVEL to prevent nested TAP headers Export KSFT_TAP_LEVEL and add TAP Header echo to the run_kselftest.sh script from emit_tests target handling. Signed-off-by: Shuah Khan --- tools/testing/selftests/Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 7442dfb73b7f..a41b4be28b9f 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -66,6 +66,12 @@ ifndef BUILD BUILD := $(shell pwd) endif +# KSFT_TAP_LEVEL is used from KSFT framework to prevent nested TAP header +# printing from tests. Applicable to run_tests case where run_tests adds +# TAP header prior running tests and when a test program invokes another +# with system() call. Export it here to cover override RUN_TESTS defines. +export KSFT_TAP_LEVEL=`echo 1` + export BUILD all: @for TARGET in $(TARGETS); do \ @@ -125,10 +131,12 @@ ifdef INSTALL_PATH echo "else" >> $(ALL_SCRIPT) echo " OUTPUT=/dev/stdout" >> $(ALL_SCRIPT) echo "fi" >> $(ALL_SCRIPT) + echo "export KSFT_TAP_LEVEL=`echo 1`" >> $(ALL_SCRIPT) for TARGET in $(TARGETS); do \ BUILD_TARGET=$$BUILD/$$TARGET; \ - echo "echo ; echo Running tests in $$TARGET" >> $(ALL_SCRIPT); \ + echo "echo ; echo TAP version 13" >> $(ALL_SCRIPT); \ + echo "echo Running tests in $$TARGET" >> $(ALL_SCRIPT); \ echo "echo ========================================" >> $(ALL_SCRIPT); \ echo "cd $$TARGET" >> $(ALL_SCRIPT); \ make -s --no-print-directory OUTPUT=$$BUILD_TARGET -C $$TARGET emit_tests >> $(ALL_SCRIPT); \ -- cgit v1.3-14-g43fede From d7d8464dcc27dfc9d0d23c7924b2e6f4bb16c6c2 Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Tue, 27 Feb 2018 10:29:50 -0700 Subject: nfit_test: improve structure offset handling In nfit_test0_setup() and nfit_test1_setup() we keep an 'offset' value which we use to calculate where in our 'nfit_buf' we will place our next structure. The handling of 'offset' and the calculation of the placement of the next structure is a bit inconsistent, though. We don't update 'offset' after we insert each structure, sometimes causing us to update it for multiple structures' sizes at once. When calculating the position of the next structure we aren't always able to just use 'offset', but sometimes have to add in other structure sizes as well. Fix this by updating 'offset' after each structure insertion in a consistent way, allowing us to always calculate the position of the next structure to be inserted by just using 'nfit_buf + offset'. Signed-off-by: Ross Zwisler Signed-off-by: Dan Williams --- tools/testing/nvdimm/test/nfit.c | 183 +++++++++++++++++++++++---------------- 1 file changed, 109 insertions(+), 74 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 620fa78b3b1b..1376fc95c33a 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -1366,7 +1366,7 @@ static void nfit_test0_setup(struct nfit_test *t) struct acpi_nfit_data_region *bdw; struct acpi_nfit_flush_address *flush; struct acpi_nfit_capabilities *pcap; - unsigned int offset, i; + unsigned int offset = 0, i; /* * spa0 (interleave first half of dimm0 and dimm1, note storage @@ -1380,93 +1380,102 @@ static void nfit_test0_setup(struct nfit_test *t) spa->range_index = 0+1; spa->address = t->spa_set_dma[0]; spa->length = SPA0_SIZE; + offset += spa->header.length; /* * spa1 (interleave last half of the 4 DIMMS, note storage * does not actually alias the related block-data-window * regions) */ - spa = nfit_buf + sizeof(*spa); + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); spa->range_index = 1+1; spa->address = t->spa_set_dma[1]; spa->length = SPA1_SIZE; + offset += spa->header.length; /* spa2 (dcr0) dimm0 */ - spa = nfit_buf + sizeof(*spa) * 2; + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); spa->range_index = 2+1; spa->address = t->dcr_dma[0]; spa->length = DCR_SIZE; + offset += spa->header.length; /* spa3 (dcr1) dimm1 */ - spa = nfit_buf + sizeof(*spa) * 3; + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); spa->range_index = 3+1; spa->address = t->dcr_dma[1]; spa->length = DCR_SIZE; + offset += spa->header.length; /* spa4 (dcr2) dimm2 */ - spa = nfit_buf + sizeof(*spa) * 4; + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); spa->range_index = 4+1; spa->address = t->dcr_dma[2]; spa->length = DCR_SIZE; + offset += spa->header.length; /* spa5 (dcr3) dimm3 */ - spa = nfit_buf + sizeof(*spa) * 5; + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_DCR), 16); spa->range_index = 5+1; spa->address = t->dcr_dma[3]; spa->length = DCR_SIZE; + offset += spa->header.length; /* spa6 (bdw for dcr0) dimm0 */ - spa = nfit_buf + sizeof(*spa) * 6; + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); spa->range_index = 6+1; spa->address = t->dimm_dma[0]; spa->length = DIMM_SIZE; + offset += spa->header.length; /* spa7 (bdw for dcr1) dimm1 */ - spa = nfit_buf + sizeof(*spa) * 7; + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); spa->range_index = 7+1; spa->address = t->dimm_dma[1]; spa->length = DIMM_SIZE; + offset += spa->header.length; /* spa8 (bdw for dcr2) dimm2 */ - spa = nfit_buf + sizeof(*spa) * 8; + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); spa->range_index = 8+1; spa->address = t->dimm_dma[2]; spa->length = DIMM_SIZE; + offset += spa->header.length; /* spa9 (bdw for dcr3) dimm3 */ - spa = nfit_buf + sizeof(*spa) * 9; + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); spa->range_index = 9+1; spa->address = t->dimm_dma[3]; spa->length = DIMM_SIZE; + offset += spa->header.length; - offset = sizeof(*spa) * 10; /* mem-region0 (spa0, dimm0) */ memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; @@ -1481,9 +1490,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 2; + offset += memdev->header.length; /* mem-region1 (spa0, dimm1) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map); + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[1]; @@ -1497,9 +1507,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->interleave_index = 0; memdev->interleave_ways = 2; memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; + offset += memdev->header.length; /* mem-region2 (spa1, dimm0) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 2; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[0]; @@ -1513,9 +1524,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->interleave_index = 0; memdev->interleave_ways = 4; memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; + offset += memdev->header.length; /* mem-region3 (spa1, dimm1) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 3; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[1]; @@ -1528,9 +1540,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = SPA0_SIZE/2; memdev->interleave_index = 0; memdev->interleave_ways = 4; + offset += memdev->header.length; /* mem-region4 (spa1, dimm2) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 4; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[2]; @@ -1544,9 +1557,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->interleave_index = 0; memdev->interleave_ways = 4; memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; + offset += memdev->header.length; /* mem-region5 (spa1, dimm3) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 5; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[3]; @@ -1559,9 +1573,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = SPA0_SIZE/2; memdev->interleave_index = 0; memdev->interleave_ways = 4; + offset += memdev->header.length; /* mem-region6 (spa/dcr0, dimm0) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 6; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[0]; @@ -1574,9 +1589,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + offset += memdev->header.length; /* mem-region7 (spa/dcr1, dimm1) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 7; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[1]; @@ -1589,9 +1605,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + offset += memdev->header.length; /* mem-region8 (spa/dcr2, dimm2) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 8; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[2]; @@ -1604,9 +1621,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + offset += memdev->header.length; /* mem-region9 (spa/dcr3, dimm3) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 9; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[3]; @@ -1619,9 +1637,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + offset += memdev->header.length; /* mem-region10 (spa/bdw0, dimm0) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 10; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[0]; @@ -1634,9 +1653,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + offset += memdev->header.length; /* mem-region11 (spa/bdw1, dimm1) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 11; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[1]; @@ -1649,9 +1669,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + offset += memdev->header.length; /* mem-region12 (spa/bdw2, dimm2) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 12; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[2]; @@ -1664,9 +1685,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + offset += memdev->header.length; /* mem-region13 (spa/dcr3, dimm3) */ - memdev = nfit_buf + offset + sizeof(struct acpi_nfit_memory_map) * 13; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[3]; @@ -1680,12 +1702,12 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->interleave_index = 0; memdev->interleave_ways = 1; memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; + offset += memdev->header.length; - offset = offset + sizeof(struct acpi_nfit_memory_map) * 14; /* dcr-descriptor0: blk */ dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; - dcr->header.length = sizeof(struct acpi_nfit_control_region); + dcr->header.length = sizeof(*dcr); dcr->region_index = 0+1; dcr_common_init(dcr); dcr->serial_number = ~handle[0]; @@ -1696,11 +1718,12 @@ static void nfit_test0_setup(struct nfit_test *t) dcr->command_size = 8; dcr->status_offset = 8; dcr->status_size = 4; + offset += dcr->header.length; /* dcr-descriptor1: blk */ - dcr = nfit_buf + offset + sizeof(struct acpi_nfit_control_region); + dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; - dcr->header.length = sizeof(struct acpi_nfit_control_region); + dcr->header.length = sizeof(*dcr); dcr->region_index = 1+1; dcr_common_init(dcr); dcr->serial_number = ~handle[1]; @@ -1711,11 +1734,12 @@ static void nfit_test0_setup(struct nfit_test *t) dcr->command_size = 8; dcr->status_offset = 8; dcr->status_size = 4; + offset += dcr->header.length; /* dcr-descriptor2: blk */ - dcr = nfit_buf + offset + sizeof(struct acpi_nfit_control_region) * 2; + dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; - dcr->header.length = sizeof(struct acpi_nfit_control_region); + dcr->header.length = sizeof(*dcr); dcr->region_index = 2+1; dcr_common_init(dcr); dcr->serial_number = ~handle[2]; @@ -1726,11 +1750,12 @@ static void nfit_test0_setup(struct nfit_test *t) dcr->command_size = 8; dcr->status_offset = 8; dcr->status_size = 4; + offset += dcr->header.length; /* dcr-descriptor3: blk */ - dcr = nfit_buf + offset + sizeof(struct acpi_nfit_control_region) * 3; + dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; - dcr->header.length = sizeof(struct acpi_nfit_control_region); + dcr->header.length = sizeof(*dcr); dcr->region_index = 3+1; dcr_common_init(dcr); dcr->serial_number = ~handle[3]; @@ -1741,8 +1766,8 @@ static void nfit_test0_setup(struct nfit_test *t) dcr->command_size = 8; dcr->status_offset = 8; dcr->status_size = 4; + offset += dcr->header.length; - offset = offset + sizeof(struct acpi_nfit_control_region) * 4; /* dcr-descriptor0: pmem */ dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; @@ -1753,10 +1778,10 @@ static void nfit_test0_setup(struct nfit_test *t) dcr->serial_number = ~handle[0]; dcr->code = NFIT_FIC_BYTEN; dcr->windows = 0; + offset += dcr->header.length; /* dcr-descriptor1: pmem */ - dcr = nfit_buf + offset + offsetof(struct acpi_nfit_control_region, - window_size); + dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; dcr->header.length = offsetof(struct acpi_nfit_control_region, window_size); @@ -1765,10 +1790,10 @@ static void nfit_test0_setup(struct nfit_test *t) dcr->serial_number = ~handle[1]; dcr->code = NFIT_FIC_BYTEN; dcr->windows = 0; + offset += dcr->header.length; /* dcr-descriptor2: pmem */ - dcr = nfit_buf + offset + offsetof(struct acpi_nfit_control_region, - window_size) * 2; + dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; dcr->header.length = offsetof(struct acpi_nfit_control_region, window_size); @@ -1777,10 +1802,10 @@ static void nfit_test0_setup(struct nfit_test *t) dcr->serial_number = ~handle[2]; dcr->code = NFIT_FIC_BYTEN; dcr->windows = 0; + offset += dcr->header.length; /* dcr-descriptor3: pmem */ - dcr = nfit_buf + offset + offsetof(struct acpi_nfit_control_region, - window_size) * 3; + dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; dcr->header.length = offsetof(struct acpi_nfit_control_region, window_size); @@ -1789,54 +1814,56 @@ static void nfit_test0_setup(struct nfit_test *t) dcr->serial_number = ~handle[3]; dcr->code = NFIT_FIC_BYTEN; dcr->windows = 0; + offset += dcr->header.length; - offset = offset + offsetof(struct acpi_nfit_control_region, - window_size) * 4; /* bdw0 (spa/dcr0, dimm0) */ bdw = nfit_buf + offset; bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; - bdw->header.length = sizeof(struct acpi_nfit_data_region); + bdw->header.length = sizeof(*bdw); bdw->region_index = 0+1; bdw->windows = 1; bdw->offset = 0; bdw->size = BDW_SIZE; bdw->capacity = DIMM_SIZE; bdw->start_address = 0; + offset += bdw->header.length; /* bdw1 (spa/dcr1, dimm1) */ - bdw = nfit_buf + offset + sizeof(struct acpi_nfit_data_region); + bdw = nfit_buf + offset; bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; - bdw->header.length = sizeof(struct acpi_nfit_data_region); + bdw->header.length = sizeof(*bdw); bdw->region_index = 1+1; bdw->windows = 1; bdw->offset = 0; bdw->size = BDW_SIZE; bdw->capacity = DIMM_SIZE; bdw->start_address = 0; + offset += bdw->header.length; /* bdw2 (spa/dcr2, dimm2) */ - bdw = nfit_buf + offset + sizeof(struct acpi_nfit_data_region) * 2; + bdw = nfit_buf + offset; bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; - bdw->header.length = sizeof(struct acpi_nfit_data_region); + bdw->header.length = sizeof(*bdw); bdw->region_index = 2+1; bdw->windows = 1; bdw->offset = 0; bdw->size = BDW_SIZE; bdw->capacity = DIMM_SIZE; bdw->start_address = 0; + offset += bdw->header.length; /* bdw3 (spa/dcr3, dimm3) */ - bdw = nfit_buf + offset + sizeof(struct acpi_nfit_data_region) * 3; + bdw = nfit_buf + offset; bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; - bdw->header.length = sizeof(struct acpi_nfit_data_region); + bdw->header.length = sizeof(*bdw); bdw->region_index = 3+1; bdw->windows = 1; bdw->offset = 0; bdw->size = BDW_SIZE; bdw->capacity = DIMM_SIZE; bdw->start_address = 0; + offset += bdw->header.length; - offset = offset + sizeof(struct acpi_nfit_data_region) * 4; /* flush0 (dimm0) */ flush = nfit_buf + offset; flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; @@ -1845,48 +1872,52 @@ static void nfit_test0_setup(struct nfit_test *t) flush->hint_count = NUM_HINTS; for (i = 0; i < NUM_HINTS; i++) flush->hint_address[i] = t->flush_dma[0] + i * sizeof(u64); + offset += flush->header.length; /* flush1 (dimm1) */ - flush = nfit_buf + offset + flush_hint_size * 1; + flush = nfit_buf + offset; flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; flush->header.length = flush_hint_size; flush->device_handle = handle[1]; flush->hint_count = NUM_HINTS; for (i = 0; i < NUM_HINTS; i++) flush->hint_address[i] = t->flush_dma[1] + i * sizeof(u64); + offset += flush->header.length; /* flush2 (dimm2) */ - flush = nfit_buf + offset + flush_hint_size * 2; + flush = nfit_buf + offset; flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; flush->header.length = flush_hint_size; flush->device_handle = handle[2]; flush->hint_count = NUM_HINTS; for (i = 0; i < NUM_HINTS; i++) flush->hint_address[i] = t->flush_dma[2] + i * sizeof(u64); + offset += flush->header.length; /* flush3 (dimm3) */ - flush = nfit_buf + offset + flush_hint_size * 3; + flush = nfit_buf + offset; flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; flush->header.length = flush_hint_size; flush->device_handle = handle[3]; flush->hint_count = NUM_HINTS; for (i = 0; i < NUM_HINTS; i++) flush->hint_address[i] = t->flush_dma[3] + i * sizeof(u64); + offset += flush->header.length; /* platform capabilities */ - pcap = nfit_buf + offset + flush_hint_size * 4; + pcap = nfit_buf + offset; pcap->header.type = ACPI_NFIT_TYPE_CAPABILITIES; pcap->header.length = sizeof(*pcap); pcap->highest_capability = 1; pcap->capabilities = ACPI_NFIT_CAPABILITY_CACHE_FLUSH | ACPI_NFIT_CAPABILITY_MEM_FLUSH; + offset += pcap->header.length; if (t->setup_hotplug) { - offset = offset + flush_hint_size * 4 + sizeof(*pcap); /* dcr-descriptor4: blk */ dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; - dcr->header.length = sizeof(struct acpi_nfit_control_region); + dcr->header.length = sizeof(*dcr); dcr->region_index = 8+1; dcr_common_init(dcr); dcr->serial_number = ~handle[4]; @@ -1897,8 +1928,8 @@ static void nfit_test0_setup(struct nfit_test *t) dcr->command_size = 8; dcr->status_offset = 8; dcr->status_size = 4; + offset += dcr->header.length; - offset = offset + sizeof(struct acpi_nfit_control_region); /* dcr-descriptor4: pmem */ dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; @@ -1909,21 +1940,20 @@ static void nfit_test0_setup(struct nfit_test *t) dcr->serial_number = ~handle[4]; dcr->code = NFIT_FIC_BYTEN; dcr->windows = 0; + offset += dcr->header.length; - offset = offset + offsetof(struct acpi_nfit_control_region, - window_size); /* bdw4 (spa/dcr4, dimm4) */ bdw = nfit_buf + offset; bdw->header.type = ACPI_NFIT_TYPE_DATA_REGION; - bdw->header.length = sizeof(struct acpi_nfit_data_region); + bdw->header.length = sizeof(*bdw); bdw->region_index = 8+1; bdw->windows = 1; bdw->offset = 0; bdw->size = BDW_SIZE; bdw->capacity = DIMM_SIZE; bdw->start_address = 0; + offset += bdw->header.length; - offset = offset + sizeof(struct acpi_nfit_data_region); /* spa10 (dcr4) dimm4 */ spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; @@ -1932,30 +1962,32 @@ static void nfit_test0_setup(struct nfit_test *t) spa->range_index = 10+1; spa->address = t->dcr_dma[4]; spa->length = DCR_SIZE; + offset += spa->header.length; /* * spa11 (single-dimm interleave for hotplug, note storage * does not actually alias the related block-data-window * regions) */ - spa = nfit_buf + offset + sizeof(*spa); + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_PM), 16); spa->range_index = 11+1; spa->address = t->spa_set_dma[2]; spa->length = SPA0_SIZE; + offset += spa->header.length; /* spa12 (bdw for dcr4) dimm4 */ - spa = nfit_buf + offset + sizeof(*spa) * 2; + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_BDW), 16); spa->range_index = 12+1; spa->address = t->dimm_dma[4]; spa->length = DIMM_SIZE; + offset += spa->header.length; - offset = offset + sizeof(*spa) * 3; /* mem-region14 (spa/dcr4, dimm4) */ memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; @@ -1970,10 +2002,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + offset += memdev->header.length; - /* mem-region15 (spa0, dimm4) */ - memdev = nfit_buf + offset + - sizeof(struct acpi_nfit_memory_map); + /* mem-region15 (spa11, dimm4) */ + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[4]; @@ -1987,10 +2019,10 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->interleave_index = 0; memdev->interleave_ways = 1; memdev->flags = ACPI_NFIT_MEM_HEALTH_ENABLED; + offset += memdev->header.length; /* mem-region16 (spa/bdw4, dimm4) */ - memdev = nfit_buf + offset + - sizeof(struct acpi_nfit_memory_map) * 2; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); memdev->device_handle = handle[4]; @@ -2003,8 +2035,8 @@ static void nfit_test0_setup(struct nfit_test *t) memdev->address = 0; memdev->interleave_index = 0; memdev->interleave_ways = 1; + offset += memdev->header.length; - offset = offset + sizeof(struct acpi_nfit_memory_map) * 3; /* flush3 (dimm4) */ flush = nfit_buf + offset; flush->header.type = ACPI_NFIT_TYPE_FLUSH_ADDRESS; @@ -2014,6 +2046,7 @@ static void nfit_test0_setup(struct nfit_test *t) for (i = 0; i < NUM_HINTS; i++) flush->hint_address[i] = t->flush_dma[4] + i * sizeof(u64); + offset += flush->header.length; } post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], @@ -2061,17 +2094,18 @@ static void nfit_test1_setup(struct nfit_test *t) spa->range_index = 0+1; spa->address = t->spa_set_dma[0]; spa->length = SPA2_SIZE; + offset += spa->header.length; /* virtual cd region */ - spa = nfit_buf + sizeof(*spa); + spa = nfit_buf + offset; spa->header.type = ACPI_NFIT_TYPE_SYSTEM_ADDRESS; spa->header.length = sizeof(*spa); memcpy(spa->range_guid, to_nfit_uuid(NFIT_SPA_VCD), 16); spa->range_index = 0; spa->address = t->spa_set_dma[1]; spa->length = SPA_VCD_SIZE; + offset += spa->header.length; - offset += sizeof(*spa) * 2; /* mem-region0 (spa0, dimm0) */ memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; @@ -2089,8 +2123,8 @@ static void nfit_test1_setup(struct nfit_test *t) memdev->flags = ACPI_NFIT_MEM_SAVE_FAILED | ACPI_NFIT_MEM_RESTORE_FAILED | ACPI_NFIT_MEM_FLUSH_FAILED | ACPI_NFIT_MEM_HEALTH_OBSERVED | ACPI_NFIT_MEM_NOT_ARMED; + offset += memdev->header.length; - offset += sizeof(*memdev); /* dcr-descriptor0 */ dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; @@ -2101,8 +2135,8 @@ static void nfit_test1_setup(struct nfit_test *t) dcr->serial_number = ~handle[5]; dcr->code = NFIT_FIC_BYTE; dcr->windows = 0; - offset += dcr->header.length; + memdev = nfit_buf + offset; memdev->header.type = ACPI_NFIT_TYPE_MEMORY_MAP; memdev->header.length = sizeof(*memdev); @@ -2117,9 +2151,9 @@ static void nfit_test1_setup(struct nfit_test *t) memdev->interleave_index = 0; memdev->interleave_ways = 1; memdev->flags = ACPI_NFIT_MEM_MAP_FAILED; + offset += memdev->header.length; /* dcr-descriptor1 */ - offset += sizeof(*memdev); dcr = nfit_buf + offset; dcr->header.type = ACPI_NFIT_TYPE_CONTROL_REGION; dcr->header.length = offsetof(struct acpi_nfit_control_region, @@ -2129,6 +2163,7 @@ static void nfit_test1_setup(struct nfit_test *t) dcr->serial_number = ~handle[6]; dcr->code = NFIT_FIC_BYTE; dcr->windows = 0; + offset += dcr->header.length; post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], SPA2_SIZE); -- cgit v1.3-14-g43fede From 9741a559971856fca61a83840b558b4f94500d89 Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Tue, 27 Feb 2018 10:29:51 -0700 Subject: nfit_test: fix buffer overrun, add sanity check It turns out that we were overrunning the 'nfit_buf' buffer in nfit_test0_setup() in the (t->setup_hotplug == 1) case because we failed to correctly account for all of the acpi_nfit_memory_map structures. Fix the structure count which will increase the allocation size of 'nfit_buf' in nfit_test0_alloc(). Also add some WARN_ON()s to nfit_test0_setup() and nfit_test1_setup() to catch future issues where the size of the buffer doesn't match the amount of data we're writing. Signed-off-by: Ross Zwisler Signed-off-by: Dan Williams --- tools/testing/nvdimm/test/nfit.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 1376fc95c33a..fcd233342273 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -104,7 +104,8 @@ enum { NUM_HINTS = 8, NUM_BDW = NUM_DCR, NUM_SPA = NUM_PM + NUM_DCR + NUM_BDW, - NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + 4 /* spa1 iset */, + NUM_MEM = NUM_DCR + NUM_BDW + 2 /* spa0 iset */ + + 4 /* spa1 iset */ + 1 /* spa11 iset */, DIMM_SIZE = SZ_32M, LABEL_SIZE = SZ_128K, SPA_VCD_SIZE = SZ_4M, @@ -2047,6 +2048,9 @@ static void nfit_test0_setup(struct nfit_test *t) flush->hint_address[i] = t->flush_dma[4] + i * sizeof(u64); offset += flush->header.length; + + /* sanity check to make sure we've filled the buffer */ + WARN_ON(offset != t->nfit_size); } post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], @@ -2165,6 +2169,9 @@ static void nfit_test1_setup(struct nfit_test *t) dcr->windows = 0; offset += dcr->header.length; + /* sanity check to make sure we've filled the buffer */ + WARN_ON(offset != t->nfit_size); + post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], SPA2_SIZE); -- cgit v1.3-14-g43fede From 1526f9e2ac1df62106c15a18fd6895258c579c90 Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Tue, 27 Feb 2018 10:29:52 -0700 Subject: nfit_test: prevent parsing error of nfit_test.0 When you load nfit_test you currently see the following error in dmesg: nfit_test nfit_test.0: found a zero length table '0' parsing nfit This happens because when we parse the nfit_test.0 table via acpi_nfit_init(), we specify a size of nfit_test->nfit_size. For the first pass through nfit_test.0 where (t->setup_hotplug == 0) this is the size of the entire buffer we allocated, including space for the hot plug structures, not the size that we've actually filled in. Fix this by only trying to parse the size of the structures that we've filled in. Signed-off-by: Ross Zwisler Signed-off-by: Dan Williams --- tools/testing/nvdimm/test/nfit.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index fcd233342273..d785235ba04e 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -154,6 +154,7 @@ struct nfit_test { void *nfit_buf; dma_addr_t nfit_dma; size_t nfit_size; + size_t nfit_filled; int dcr_idx; int num_dcr; int num_pm; @@ -2053,6 +2054,8 @@ static void nfit_test0_setup(struct nfit_test *t) WARN_ON(offset != t->nfit_size); } + t->nfit_filled = offset; + post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], SPA0_SIZE); @@ -2172,6 +2175,8 @@ static void nfit_test1_setup(struct nfit_test *t) /* sanity check to make sure we've filled the buffer */ WARN_ON(offset != t->nfit_size); + t->nfit_filled = offset; + post_ars_status(&t->ars_state, &t->badrange, t->spa_set_dma[0], SPA2_SIZE); @@ -2529,7 +2534,7 @@ static int nfit_test_probe(struct platform_device *pdev) nd_desc->ndctl = nfit_test_ctl; rc = acpi_nfit_init(acpi_desc, nfit_test->nfit_buf, - nfit_test->nfit_size); + nfit_test->nfit_filled); if (rc) return rc; -- cgit v1.3-14-g43fede From 78972f51ccf8d0682edf99f03d1367b8c2ce7336 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 22 Feb 2018 18:17:50 -0700 Subject: selftests: futex Makefile add top level TAP header echo to RUN_TESTS Add top level TAP header echo, testname and separator line to make the output consistent with the common run_tests target. This change prevents nested TAP13 headers output from individual tests. Nested TAP13 headers could cause problems for some parsers. Signed-off-by: Shuah Khan Reviewed-by: Darren Hart (VMware) Signed-off-by: Shuah Khan --- tools/testing/selftests/futex/Makefile | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile index a63e8453984d..8497a376ef9d 100644 --- a/tools/testing/selftests/futex/Makefile +++ b/tools/testing/selftests/futex/Makefile @@ -18,6 +18,10 @@ all: done override define RUN_TESTS + @export KSFT_TAP_LEVEL=`echo 1`; + @echo "TAP version 13"; + @echo "selftests: futex"; + @echo "========================================"; @cd $(OUTPUT); ./run.sh endef -- cgit v1.3-14-g43fede From 4d1e46a55ea9f8d693ceabe1ba4b056e55fb6625 Mon Sep 17 00:00:00 2001 From: Prashant Bhole Date: Tue, 6 Mar 2018 17:31:32 +0900 Subject: selftests/net: fix in_netns.sh script execute the subprocess in netns using 'ip netns exec' Fixes: cc30c93fa020 ("selftests/net: ignore background traffic in psock_fanout") Signed-off-by: Prashant Bhole Acked-by: Willem de Bruijn Signed-off-by: David S. Miller --- tools/testing/selftests/net/in_netns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/in_netns.sh b/tools/testing/selftests/net/in_netns.sh index f57a2eaad069..88795b510b32 100755 --- a/tools/testing/selftests/net/in_netns.sh +++ b/tools/testing/selftests/net/in_netns.sh @@ -19,5 +19,5 @@ cleanup() { trap cleanup EXIT setup -"$@" +ip netns exec "${NETNS}" "$@" exit "$?" -- cgit v1.3-14-g43fede From d1f1b9cbf34c667d06adc44136e448cade8e28d9 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Tue, 6 Mar 2018 22:16:27 +0100 Subject: selftests: net: Introduce first PMTU test One single test implemented so far: test_pmtu_vti6_exception checks that the PMTU of a route exception, caused by a tunnel exceeding the link layer MTU, is affected by administrative changes of the tunnel MTU. Creation of the route exception is checked too. Requested-by: David Ahern Signed-off-by: Stefano Brivio Acked-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/Makefile | 2 +- tools/testing/selftests/net/pmtu.sh | 163 +++++++++++++++++++++++++++++++++++ 2 files changed, 164 insertions(+), 1 deletion(-) create mode 100755 tools/testing/selftests/net/pmtu.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index 229a038966e3..785fc18a16b4 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile @@ -5,7 +5,7 @@ CFLAGS = -Wall -Wl,--no-as-needed -O2 -g CFLAGS += -I../../../../usr/include/ TEST_PROGS := run_netsocktests run_afpackettests test_bpf.sh netdevice.sh rtnetlink.sh -TEST_PROGS += fib_tests.sh fib-onlink-tests.sh +TEST_PROGS += fib_tests.sh fib-onlink-tests.sh pmtu.sh TEST_GEN_FILES = socket TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy TEST_GEN_PROGS = reuseport_bpf reuseport_bpf_cpu reuseport_bpf_numa diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh new file mode 100755 index 000000000000..6c19c148cef8 --- /dev/null +++ b/tools/testing/selftests/net/pmtu.sh @@ -0,0 +1,163 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# +# Check that route PMTU values match expectations +# +# Tests currently implemented: +# +# - test_pmtu_vti6_exception +# Set up vti6 tunnel on top of veth, with xfrm states and policies, in two +# namespaces with matching endpoints. Check that route exception is +# created by exceeding link layer MTU with ping to other endpoint. Then +# decrease and increase MTU of tunnel, checking that route exception PMTU +# changes accordingly + +NS_A="ns-$(mktemp -u XXXXXX)" +NS_B="ns-$(mktemp -u XXXXXX)" +ns_a="ip netns exec ${NS_A}" +ns_b="ip netns exec ${NS_B}" + +veth6_a_addr="fd00:1::a" +veth6_b_addr="fd00:1::b" +veth6_mask="64" + +vti6_a_addr="fd00:2::a" +vti6_b_addr="fd00:2::b" +vti6_mask="64" + +setup_namespaces() { + ip netns add ${NS_A} || return 0 + ip netns add ${NS_B} + + return 1 +} + +setup_veth() { + ${ns_a} ip link add veth_a type veth peer name veth_b || return 0 + ${ns_a} ip link set veth_b netns ${NS_B} + + ${ns_a} ip addr add ${veth6_a_addr}/${veth6_mask} dev veth_a + ${ns_b} ip addr add ${veth6_b_addr}/${veth6_mask} dev veth_b + + ${ns_a} ip link set veth_a up + ${ns_b} ip link set veth_b up + + return 1 +} + +setup_vti6() { + ${ns_a} ip link add vti_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 || return 0 + ${ns_b} ip link add vti_b type vti6 local ${veth6_b_addr} remote ${veth6_a_addr} key 10 + + ${ns_a} ip addr add ${vti6_a_addr}/${vti6_mask} dev vti_a + ${ns_b} ip addr add ${vti6_b_addr}/${vti6_mask} dev vti_b + + ${ns_a} ip link set vti_a up + ${ns_b} ip link set vti_b up + + sleep 1 + + return 1 +} + +setup_xfrm() { + ${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 0 + ${ns_a} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_a} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel + ${ns_a} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel + + ${ns_b} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_b} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_b} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel + ${ns_b} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel + + return 1 +} + +setup() { + tunnel_type="$1" + + [ "$(id -u)" -ne 0 ] && echo "SKIP: need to run as root" && exit 0 + + setup_namespaces && echo "SKIP: namespaces not supported" && exit 0 + setup_veth && echo "SKIP: veth not supported" && exit 0 + + case ${tunnel_type} in + "vti6") + setup_vti6 && echo "SKIP: vti6 not supported" && exit 0 + setup_xfrm && echo "SKIP: xfrm not supported" && exit 0 + ;; + *) + ;; + esac +} + +cleanup() { + ip netns del ${NS_A} 2 > /dev/null + ip netns del ${NS_B} 2 > /dev/null +} + +mtu() { + ns_cmd="${1}" + dev="${2}" + mtu="${3}" + + ${ns_cmd} ip link set dev ${dev} mtu ${mtu} +} + +route_get_dst_exception() { + dst="${1}" + + ${ns_a} ip route get "${dst}" +} + +route_get_dst_pmtu_from_exception() { + dst="${1}" + + exception="$(route_get_dst_exception ${dst})" + next=0 + for i in ${exception}; do + [ ${next} -eq 1 ] && echo "${i}" && return + [ "${i}" = "mtu" ] && next=1 + done +} + +test_pmtu_vti6_exception() { + setup vti6 + + # Create route exception by exceeding link layer MTU + mtu "${ns_a}" veth_a 4000 + mtu "${ns_b}" veth_b 4000 + mtu "${ns_a}" vti_a 5000 + mtu "${ns_b}" vti_b 5000 + ${ns_a} ping6 -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null + + # Check that exception was created + if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" = "" ]; then + echo "FAIL: Tunnel exceeding link layer MTU didn't create route exception" + exit 1 + fi + + # Decrease tunnel MTU, check for PMTU decrease in route exception + mtu "${ns_a}" vti_a 3000 + + if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" -ne 3000 ]; then + echo "FAIL: Decreasing tunnel MTU didn't decrease route exception PMTU" + exit 1 + fi + + # Increase tunnel MTU, check for PMTU increase in route exception + mtu "${ns_a}" vti_a 9000 + if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" -ne 9000 ]; then + echo "FAIL: Increasing tunnel MTU didn't increase route exception PMTU" + exit 1 + fi + + echo "PASS" +} + +trap cleanup EXIT + +test_pmtu_vti6_exception + +exit 0 -- cgit v1.3-14-g43fede From 0c17db05ec982607121b8f01cf4ce03513964d9c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 7 Mar 2018 13:57:59 +0100 Subject: selftests: forwarding: fix "ok" action test Fix the "ok" action test so it checks that packet that is okayed does not continue to be processed by other rules. Fix error message as well. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/tc_actions.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh index 6b18ba2d3982..ac6b6a1057d8 100755 --- a/tools/testing/selftests/net/forwarding/tc_actions.sh +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -96,7 +96,10 @@ gact_drop_and_ok_test() -t ip -q tc_check_packets "dev $swp1 ingress" 101 1 - check_err $? "Did not see trapped packet" + check_err $? "Did not see passed packet" + + tc_check_packets "dev $swp1 ingress" 102 2 + check_fail $? "Packet was dropped and it should not reach here" tc filter del dev $swp1 ingress protocol ip pref 2 handle 102 flower tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower -- cgit v1.3-14-g43fede From dff58a09d77e152056a4803ff89b6ec3fc6c9b2c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Wed, 7 Mar 2018 13:58:00 +0100 Subject: selftests: forwarding: fix flags passed to first drop rule in gact_drop_and_ok_test Fix copy&paste error and pass proper flags. Signed-off-by: Jiri Pirko Reviewed-by: Ido Schimmel Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/tc_actions.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/tc_actions.sh b/tools/testing/selftests/net/forwarding/tc_actions.sh index ac6b6a1057d8..3a6385ebd5d0 100755 --- a/tools/testing/selftests/net/forwarding/tc_actions.sh +++ b/tools/testing/selftests/net/forwarding/tc_actions.sh @@ -81,7 +81,7 @@ gact_drop_and_ok_test() RET=0 tc filter add dev $swp1 ingress protocol ip pref 2 handle 102 flower \ - skip_hw dst_ip 192.0.2.2 action drop + $tcflags dst_ip 192.0.2.2 action drop $MZ $h1 -c 1 -p 64 -a $h1mac -b $h2mac -A 192.0.2.1 -B 192.0.2.2 \ -t ip -q -- cgit v1.3-14-g43fede From 076ca272a14cea558b1092ec85cea08510283f2a Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Wed, 7 Mar 2018 11:12:27 -0800 Subject: x86/vsyscall/64: Drop "native" vsyscalls Since Linux v3.2, vsyscalls have been deprecated and slow. From v3.2 on, Linux had three vsyscall modes: "native", "emulate", and "none". "emulate" is the default. All known user programs work correctly in emulate mode, but vsyscalls turn into page faults and are emulated. This is very slow. In "native" mode, the vsyscall page is easily usable as an exploit gadget, but vsyscalls are a bit faster -- they turn into normal syscalls. (This is in contrast to vDSO functions, which can be much faster than syscalls.) In "none" mode, there are no vsyscalls. For all practical purposes, "native" was really just a chicken bit in case something went wrong with the emulation. It's been over six years, and nothing has gone wrong. Delete it. Signed-off-by: Andy Lutomirski Acked-by: Kees Cook Acked-by: Linus Torvalds Cc: Borislav Petkov Cc: Dominik Brodowski Cc: Kernel Hardening Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/519fee5268faea09ae550776ce969fa6e88668b0.1520449896.git.luto@kernel.org Signed-off-by: Ingo Molnar --- arch/x86/Kconfig | 11 +---------- arch/x86/entry/vsyscall/vsyscall_64.c | 16 +++------------- arch/x86/include/asm/pgtable_types.h | 2 -- tools/testing/selftests/x86/test_vsyscall.c | 11 ++++++----- 4 files changed, 10 insertions(+), 30 deletions(-) (limited to 'tools/testing') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index c1aed6c0e413..09c599e0900d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -2266,7 +2266,7 @@ choice it can be used to assist security vulnerability exploitation. This setting can be changed at boot time via the kernel command - line parameter vsyscall=[native|emulate|none]. + line parameter vsyscall=[emulate|none]. On a system with recent enough glibc (2.14 or newer) and no static binaries, you can say None without a performance penalty @@ -2274,15 +2274,6 @@ choice If unsure, select "Emulate". - config LEGACY_VSYSCALL_NATIVE - bool "Native" - help - Actual executable code is located in the fixed vsyscall - address mapping, implementing time() efficiently. Since - this makes the mapping executable, it can be used during - security vulnerability exploitation (traditionally as - ROP gadgets). This configuration is not recommended. - config LEGACY_VSYSCALL_EMULATE bool "Emulate" help diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index 577fa8adb785..8560ef68a9d6 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -42,10 +42,8 @@ #define CREATE_TRACE_POINTS #include "vsyscall_trace.h" -static enum { EMULATE, NATIVE, NONE } vsyscall_mode = -#if defined(CONFIG_LEGACY_VSYSCALL_NATIVE) - NATIVE; -#elif defined(CONFIG_LEGACY_VSYSCALL_NONE) +static enum { EMULATE, NONE } vsyscall_mode = +#ifdef CONFIG_LEGACY_VSYSCALL_NONE NONE; #else EMULATE; @@ -56,8 +54,6 @@ static int __init vsyscall_setup(char *str) if (str) { if (!strcmp("emulate", str)) vsyscall_mode = EMULATE; - else if (!strcmp("native", str)) - vsyscall_mode = NATIVE; else if (!strcmp("none", str)) vsyscall_mode = NONE; else @@ -139,10 +135,6 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) WARN_ON_ONCE(address != regs->ip); - /* This should be unreachable in NATIVE mode. */ - if (WARN_ON(vsyscall_mode == NATIVE)) - return false; - if (vsyscall_mode == NONE) { warn_bad_vsyscall(KERN_INFO, regs, "vsyscall attempted with vsyscall=none"); @@ -370,9 +362,7 @@ void __init map_vsyscall(void) if (vsyscall_mode != NONE) { __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall, - vsyscall_mode == NATIVE - ? PAGE_KERNEL_VSYSCALL - : PAGE_KERNEL_VVAR); + PAGE_KERNEL_VVAR); set_vsyscall_pgtable_user_bits(swapper_pg_dir); } diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h index 246f15b4e64c..acfe755562a6 100644 --- a/arch/x86/include/asm/pgtable_types.h +++ b/arch/x86/include/asm/pgtable_types.h @@ -174,7 +174,6 @@ enum page_cache_mode { #define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW) #define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW) #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_NOCACHE) -#define __PAGE_KERNEL_VSYSCALL (__PAGE_KERNEL_RX | _PAGE_USER) #define __PAGE_KERNEL_VVAR (__PAGE_KERNEL_RO | _PAGE_USER) #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) @@ -206,7 +205,6 @@ enum page_cache_mode { #define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE | _PAGE_ENC) #define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE | _PAGE_ENC) #define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC | _PAGE_ENC) -#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL | _PAGE_ENC) #define PAGE_KERNEL_VVAR __pgprot(__PAGE_KERNEL_VVAR | _PAGE_ENC) #define PAGE_KERNEL_IO __pgprot(__PAGE_KERNEL_IO) diff --git a/tools/testing/selftests/x86/test_vsyscall.c b/tools/testing/selftests/x86/test_vsyscall.c index be81621446f0..0b4f1cc2291c 100644 --- a/tools/testing/selftests/x86/test_vsyscall.c +++ b/tools/testing/selftests/x86/test_vsyscall.c @@ -450,7 +450,7 @@ static void sigtrap(int sig, siginfo_t *info, void *ctx_void) num_vsyscall_traps++; } -static int test_native_vsyscall(void) +static int test_emulation(void) { time_t tmp; bool is_native; @@ -458,7 +458,7 @@ static int test_native_vsyscall(void) if (!vtime) return 0; - printf("[RUN]\tchecking for native vsyscall\n"); + printf("[RUN]\tchecking that vsyscalls are emulated\n"); sethandler(SIGTRAP, sigtrap, 0); set_eflags(get_eflags() | X86_EFLAGS_TF); vtime(&tmp); @@ -474,11 +474,12 @@ static int test_native_vsyscall(void) */ is_native = (num_vsyscall_traps > 1); - printf("\tvsyscalls are %s (%d instructions in vsyscall page)\n", + printf("[%s]\tvsyscalls are %s (%d instructions in vsyscall page)\n", + (is_native ? "FAIL" : "OK"), (is_native ? "native" : "emulated"), (int)num_vsyscall_traps); - return 0; + return is_native; } #endif @@ -498,7 +499,7 @@ int main(int argc, char **argv) nerrs += test_vsys_r(); #ifdef __x86_64__ - nerrs += test_native_vsyscall(); + nerrs += test_emulation(); #endif return nerrs ? 1 : 0; -- cgit v1.3-14-g43fede From dcf1bcb6aed7785ccb098163cca5a2f9e4175663 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Thu, 8 Mar 2018 11:17:23 +0100 Subject: selftests/net: enable fragments for fib-onlink-tests We miss CONFIG_* fragments so test fib-onlink-tests.sh can do: ip li add lisa type vrf table 1101 ip li add veth1 type veth peer name veth2 And the follow message occurs if it isn't enabled: Configuring interfaces RTNETLINK answers: Operation not supported This enables for NET_NRF (and friends) and VETH so we can create a vrf table and veth. Fixes: 153e1b84f477 ("selftests: Add FIB onlink tests") Signed-off-by: Anders Roxell Signed-off-by: David S. Miller --- tools/testing/selftests/net/config | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config index 7177bea1fdfa..6a75a3ea44ad 100644 --- a/tools/testing/selftests/net/config +++ b/tools/testing/selftests/net/config @@ -2,3 +2,8 @@ CONFIG_USER_NS=y CONFIG_BPF_SYSCALL=y CONFIG_TEST_BPF=m CONFIG_NUMA=y +CONFIG_NET_VRF=y +CONFIG_NET_L3_MASTER_DEV=y +CONFIG_IPV6=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_VETH=y -- cgit v1.3-14-g43fede From 8edfaf7d33983309b30564e2abaede26163764f3 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Thu, 8 Mar 2018 14:56:43 -0500 Subject: tc-testing: add csum tests Signed-off-by: Roman Mashak Tested-by: Davide Caratti Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/csum.json | 410 +++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/actions/csum.json (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json b/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json new file mode 100644 index 000000000000..93cf8fea8ae7 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/csum.json @@ -0,0 +1,410 @@ +[ + { + "id": "6d84", + "name": "Add csum iph action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum iph index 800", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 800", + "matchPattern": "action order [0-9]*: csum \\(iph\\) action pass.*index 800 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "1862", + "name": "Add csum ip4h action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum ip4h index 7", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 7", + "matchPattern": "action order [0-9]*: csum \\(iph\\) action pass.*index 7 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "15c6", + "name": "Add csum ipv4h action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum ipv4h index 1122", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 1122", + "matchPattern": "action order [0-9]*: csum \\(iph\\) action pass.*index 1122 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "bf47", + "name": "Add csum icmp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum icmp index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 1", + "matchPattern": "action order [0-9]*: csum \\(icmp\\) action pass.*index 1 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "cc1d", + "name": "Add csum igmp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum igmp index 999", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 999", + "matchPattern": "action order [0-9]*: csum \\(igmp\\) action pass.*index 999 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "bccc", + "name": "Add csum foobar action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum foobar index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action csum", + "matchPattern": "action order [0-9]*: csum \\(foobar\\) action pass.*index 1 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "3bb4", + "name": "Add csum tcp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum tcp index 9999", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 9999", + "matchPattern": "action order [0-9]*: csum \\(tcp\\) action pass.*index 9999 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "759c", + "name": "Add csum udp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum udp index 334455", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 334455", + "matchPattern": "action order [0-9]*: csum \\(udp\\) action pass.*index 334455 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "bdb6", + "name": "Add csum udp xor iph action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum udp xor iph index 3", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action csum", + "matchPattern": "action order [0-9]*: csum \\(udp xor iph\\) action pass.*index 3 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "c220", + "name": "Add csum udplite action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum udplite continue index 3", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 3", + "matchPattern": "action order [0-9]*: csum \\(udplite\\) action continue.*index 3 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "8993", + "name": "Add csum sctp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum sctp index 777", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 777", + "matchPattern": "action order [0-9]*: csum \\(sctp\\) action pass.*index 777 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "b138", + "name": "Add csum ip & icmp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum ip and icmp pipe index 123", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 123", + "matchPattern": "action order [0-9]*: csum \\(iph, icmp\\) action pipe.*index 123 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "eeda", + "name": "Add csum ip & sctp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum ipv4h sctp continue index 2", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 2", + "matchPattern": "action order [0-9]*: csum \\(iph, sctp\\) action continue.*index 2 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "0017", + "name": "Add csum udp or tcp action", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum udp or tcp continue index 27", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 27", + "matchPattern": "action order [0-9]*: csum \\(tcp, udp\\) action continue.*index 27 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "ce92", + "name": "Add csum udp action with cookie", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum udp pipe index 7 cookie 12345678", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 7", + "matchPattern": "action order [0-9]*: csum \\(udp\\) action pipe.*index 7.*cookie 12345678", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "912f", + "name": "Add csum icmp action with large cookie", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action csum icmp pipe index 17 cookie aabbccddeeff1122", + "expExitCode": "0", + "verifyCmd": "$TC actions get action csum index 17", + "matchPattern": "action order [0-9]*: csum \\(icmp\\) action pipe.*index 17.*cookie aabbccddeeff1122", + "matchCount": "1", + "teardown": [ + "$TC actions flush action csum" + ] + }, + { + "id": "879b", + "name": "Add batch of 32 csum tcp actions", + "category": [ + "actions", + "csum" + ], + "setup": [ + [ + "$TC actions flush action csum", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action csum tcp continue index $i \"; args=\"$args$cmd\"; done && $TC actions add $args", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action csum", + "matchPattern": "^[ \t]+index [0-9]* ref", + "matchCount": "32", + "teardown": [ + "$TC actions flush action csum" + ] + } +] -- cgit v1.3-14-g43fede From 75291f3a6b86a53f2607658de3b8b267e306bf60 Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Thu, 8 Mar 2018 15:27:44 -0500 Subject: tools: tc-testing: Can refer to $TESTID in test spec When processing the commands in the test cases, substitute the test id for $TESTID. This helps to make more flexible tests. For example, the testid can be given as a command line argument. As an example, if we wish to save the test output to a file named for the test case, we can write in the test case: "cmdUnderTest": "some test command | tee -a $TESTID.out" Signed-off-by: Brenda J. Butler Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 241eea37e4a4..c05b9f0f3db2 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -177,6 +177,7 @@ def prepare_env(args, pm, stage, prefix, cmdlist, output = None): '"{}" did not complete successfully'.format(prefix)) def run_one_test(pm, args, index, tidx): + global NAMES result = True tresult = "" tap = "" @@ -184,6 +185,9 @@ def run_one_test(pm, args, index, tidx): print("\t====================\n=====> ", end="") print("Test " + tidx["id"] + ": " + tidx["name"]) + # populate NAMES with TESTID for this test + NAMES['TESTID'] = tidx['id'] + pm.call_pre_case(index, tidx['id']) prepare_env(args, pm, 'setup', "-----> prepare stage", tidx["setup"]) @@ -227,6 +231,8 @@ def run_one_test(pm, args, index, tidx): index += 1 + # remove TESTID from NAMES + del(NAMES['TESTID']) return tap def test_runner(pm, args, filtered_tests): -- cgit v1.3-14-g43fede From 2b3905de8b3d8511aee1d4acbf063197291cdd3f Mon Sep 17 00:00:00 2001 From: "Brenda J. Butler" Date: Thu, 8 Mar 2018 15:28:03 -0500 Subject: tools: tc-testing: Can pause just before post-suite With option -P, the test script will pause just before the post_suite functions are called. This allows the tester to inspect the system before it is torn down. Signed-off-by: Brenda J. Butler Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index c05b9f0f3db2..44de4a272a11 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -324,6 +324,12 @@ def test_runner(pm, args, filtered_tests): count += 1 tap += 'done flushing skipped test tap output\n' + + if args.pause: + print('Want to pause\nPress enter to continue ...') + if input(sys.stdin): + print('got something on stdin') + pm.call_post_suite(index) return tap @@ -406,6 +412,9 @@ def set_args(parser): help='Suppress tap results for command under test') parser.add_argument('-d', '--device', help='Execute the test case in flower category') + parser.add_argument( + '-P', '--pause', action='store_true', + help='Pause execution just before post-suite stage') return parser -- cgit v1.3-14-g43fede From 0627be7d3c871035364923559543c9b2ff5357f2 Mon Sep 17 00:00:00 2001 From: Li Zhijian Date: Fri, 9 Mar 2018 15:51:16 -0800 Subject: selftests/vm/run_vmtests: adjust hugetlb size according to nr_cpus Fix userfaultfd_hugetlb on hosts which have more than 64 cpus. --------------------------- running userfaultfd_hugetlb --------------------------- invalid MiB Usage: [FAIL] Via userfaultfd.c we can know, hugetlb_size needs to meet hugetlb_size >= nr_cpus * hugepage_size. hugepage_size is often 2M, so when host cpus > 64, it requires more than 128M. [zhijianx.li@intel.com: update changelog/comments and variable name] Link: http://lkml.kernel.org/r/20180302024356.83359-1-zhijianx.li@intel.com Link: http://lkml.kernel.org/r/20180303125027.81638-1-zhijianx.li@intel.com Link: http://lkml.kernel.org/r/20180302024356.83359-1-zhijianx.li@intel.com Signed-off-by: Li Zhijian Cc: Shuah Khan Cc: SeongJae Park Cc: Philippe Ombredanne Cc: Aneesh Kumar K.V Cc: Mike Kravetz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/vm/run_vmtests | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index d2561895a021..22d564673830 100755 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests @@ -2,25 +2,33 @@ # SPDX-License-Identifier: GPL-2.0 #please run as root -#we need 256M, below is the size in kB -needmem=262144 mnt=./huge exitcode=0 -#get pagesize and freepages from /proc/meminfo +#get huge pagesize and freepages from /proc/meminfo while read name size unit; do if [ "$name" = "HugePages_Free:" ]; then freepgs=$size fi if [ "$name" = "Hugepagesize:" ]; then - pgsize=$size + hpgsize_KB=$size fi done < /proc/meminfo +# Simple hugetlbfs tests have a hardcoded minimum requirement of +# huge pages totaling 256MB (262144KB) in size. The userfaultfd +# hugetlb test requires a minimum of 2 * nr_cpus huge pages. Take +# both of these requirements into account and attempt to increase +# number of huge pages available. +nr_cpus=$(nproc) +hpgsize_MB=$((hpgsize_KB / 1024)) +half_ufd_size_MB=$((((nr_cpus * hpgsize_MB + 127) / 128) * 128)) +needmem_KB=$((half_ufd_size_MB * 2 * 1024)) + #set proper nr_hugepages -if [ -n "$freepgs" ] && [ -n "$pgsize" ]; then +if [ -n "$freepgs" ] && [ -n "$hpgsize_KB" ]; then nr_hugepgs=`cat /proc/sys/vm/nr_hugepages` - needpgs=`expr $needmem / $pgsize` + needpgs=$((needmem_KB / hpgsize_KB)) tries=2 while [ $tries -gt 0 ] && [ $freepgs -lt $needpgs ]; do lackpgs=$(( $needpgs - $freepgs )) @@ -107,8 +115,9 @@ fi echo "---------------------------" echo "running userfaultfd_hugetlb" echo "---------------------------" -# 256MB total huge pages == 128MB src and 128MB dst -./userfaultfd hugetlb 128 32 $mnt/ufd_test_file +# Test requires source and destination huge pages. Size of source +# (half_ufd_size_MB) is passed as argument to test. +./userfaultfd hugetlb $half_ufd_size_MB 32 $mnt/ufd_test_file if [ $? -ne 0 ]; then echo "[FAIL]" exitcode=1 -- cgit v1.3-14-g43fede From f06eec4d0f2c784788ed2e9aa12c9227c2341771 Mon Sep 17 00:00:00 2001 From: Rajvi Jingar Date: Mon, 15 Jan 2018 20:52:11 -0600 Subject: selftests: ftrace: Add inter-event hist triggers testcases This adds inter-event hist triggers testcases which covers following: - create/remove synthetic event - disable histogram for synthetic event - extended error support - field variable support - histogram variables - histogram trigger onmatch action - histogram trigger onmax action - histogram trigger onmatch-onmax action - simple expression support - combined histogram Here is the test result. === Ftrace unit tests === [1] event trigger - test extended error support [PASS] [2] event trigger - test field variable support [PASS] [3] event trigger - test inter-event combined histogram trigger [PASS] [4] event trigger - test inter-event histogram trigger onmatch action [PASS] [5] event trigger - test inter-event histogram trigger onmatch-onmax action [PASS] [6] event trigger - test inter-event histogram trigger onmax action [PASS] [7] event trigger - test synthetic event create remove [PASS] Link: http://lkml.kernel.org/r/e07ef1e72f7bf0f84dc87c9b736d6dc91b4b0b49.1516069914.git.tom.zanussi@linux.intel.com Signed-off-by: Rajvi Jingar Signed-off-by: Tom Zanussi Signed-off-by: Steven Rostedt (VMware) --- tools/testing/selftests/ftrace/test.d/functions | 7 +++ .../inter-event/trigger-extended-error-support.tc | 39 +++++++++++++++ .../inter-event/trigger-field-variable-support.tc | 54 ++++++++++++++++++++ .../trigger-inter-event-combined-hist.tc | 58 ++++++++++++++++++++++ .../inter-event/trigger-onmatch-action-hist.tc | 50 +++++++++++++++++++ .../trigger-onmatch-onmax-action-hist.tc | 50 +++++++++++++++++++ .../inter-event/trigger-onmax-action-hist.tc | 48 ++++++++++++++++++ .../trigger-synthetic-event-createremove.tc | 54 ++++++++++++++++++++ 8 files changed, 360 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-extended-error-support.tc create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc create mode 100644 tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-createremove.tc (limited to 'tools/testing') diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions index df3dd7fe5f9b..2a4f16fc9819 100644 --- a/tools/testing/selftests/ftrace/test.d/functions +++ b/tools/testing/selftests/ftrace/test.d/functions @@ -59,6 +59,13 @@ disable_events() { echo 0 > events/enable } +clear_synthetic_events() { # reset all current synthetic events + grep -v ^# synthetic_events | + while read line; do + echo "!$line" >> synthetic_events + done +} + initialize_ftrace() { # Reset ftrace to initial-state # As the initial state, ftrace will be set to nop tracer, # no events, no triggers, no filters, no function filters, diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-extended-error-support.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-extended-error-support.tc new file mode 100644 index 000000000000..786dce7e48be --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-extended-error-support.tc @@ -0,0 +1,39 @@ +#!/bin/sh +# description: event trigger - test extended error support + + +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f synthetic_events ]; then + echo "synthetic event is not supported" + exit_unsupported +fi + +reset_tracer +do_reset + +echo "Test extended error support" +echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_wakeup/trigger +echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' >> events/sched/sched_wakeup/trigger &>/dev/null +if ! grep -q "ERROR:" events/sched/sched_wakeup/hist; then + fail "Failed to generate extended error in histogram" +fi + +do_reset + +exit 0 diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc new file mode 100644 index 000000000000..7fd5b4a8f060 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-field-variable-support.tc @@ -0,0 +1,54 @@ +#!/bin/sh +# description: event trigger - test field variable support + +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f synthetic_events ]; then + echo "synthetic event is not supported" + exit_unsupported +fi + +clear_synthetic_events +reset_tracer +do_reset + +echo "Test field variable support" + +echo 'wakeup_latency u64 lat; pid_t pid; int prio; char comm[16]' > synthetic_events +echo 'hist:keys=comm:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_waking/trigger +echo 'hist:keys=next_comm:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,sched.sched_waking.prio,next_comm) if next_comm=="ping"' > events/sched/sched_switch/trigger +echo 'hist:keys=pid,prio,comm:vals=lat:sort=pid,prio' > events/synthetic/wakeup_latency/trigger + +ping localhost -c 3 +if ! grep -q "ping" events/synthetic/wakeup_latency/hist; then + fail "Failed to create inter-event histogram" +fi + +if ! grep -q "synthetic_prio=prio" events/sched/sched_waking/hist; then + fail "Failed to create histogram with field variable" +fi + +echo '!hist:keys=next_comm:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).wakeup_latency($wakeup_lat,next_pid,sched.sched_waking.prio,next_comm) if next_comm=="ping"' >> events/sched/sched_switch/trigger + +if grep -q "synthetic_prio=prio" events/sched/sched_waking/hist; then + fail "Failed to remove histogram with field variable" +fi + +do_reset + +exit 0 diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc new file mode 100644 index 000000000000..c93dbe38b5df --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-inter-event-combined-hist.tc @@ -0,0 +1,58 @@ +#!/bin/sh +# description: event trigger - test inter-event combined histogram trigger + +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f synthetic_events ]; then + echo "synthetic event is not supported" + exit_unsupported +fi + +reset_tracer +do_reset +clear_synthetic_events + +echo "Test create synthetic event" + +echo 'waking_latency u64 lat pid_t pid' > synthetic_events +if [ ! -d events/synthetic/waking_latency ]; then + fail "Failed to create waking_latency synthetic event" +fi + +echo "Test combined histogram" + +echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_waking/trigger +echo 'hist:keys=pid:waking_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_waking).waking_latency($waking_lat,pid) if comm=="ping"' > events/sched/sched_wakeup/trigger +echo 'hist:keys=pid,lat:sort=pid,lat' > events/synthetic/waking_latency/trigger + +echo 'wakeup_latency u64 lat pid_t pid' >> synthetic_events +echo 'hist:keys=pid:ts1=common_timestamp.usecs if comm=="ping"' >> events/sched/sched_wakeup/trigger +echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts1:onmatch(sched.sched_wakeup).wakeup_latency($wakeup_lat,next_pid) if next_comm=="ping"' > events/sched/sched_switch/trigger + +echo 'waking+wakeup_latency u64 lat; pid_t pid' >> synthetic_events +echo 'hist:keys=pid,lat:sort=pid,lat:ww_lat=$waking_lat+$wakeup_lat:onmatch(synthetic.wakeup_latency).waking+wakeup_latency($ww_lat,pid)' >> events/synthetic/wakeup_latency/trigger +echo 'hist:keys=pid,lat:sort=pid,lat' >> events/synthetic/waking+wakeup_latency/trigger + +ping localhost -c 3 +if ! grep -q "pid:" events/synthetic/waking+wakeup_latency/hist; then + fail "Failed to create combined histogram" +fi + +do_reset + +exit 0 diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc new file mode 100644 index 000000000000..e84e7d048566 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-action-hist.tc @@ -0,0 +1,50 @@ +#!/bin/sh +# description: event trigger - test inter-event histogram trigger onmatch action + +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f synthetic_events ]; then + echo "synthetic event is not supported" + exit_unsupported +fi + +clear_synthetic_events +reset_tracer +do_reset + +echo "Test create synthetic event" + +echo 'wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events +if [ ! -d events/synthetic/wakeup_latency ]; then + fail "Failed to create wakeup_latency synthetic event" +fi + +echo "Test create histogram for synthetic event" +echo "Test histogram variables,simple expression support and onmatch action" + +echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_wakeup/trigger +echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_wakeup).wakeup_latency($wakeup_lat,next_pid,next_comm) if next_comm=="ping"' > events/sched/sched_switch/trigger +echo 'hist:keys=comm,pid,lat:wakeup_lat=lat:sort=lat' > events/synthetic/wakeup_latency/trigger +ping localhost -c 5 +if ! grep -q "ping" events/synthetic/wakeup_latency/hist; then + fail "Failed to create onmatch action inter-event histogram" +fi + +do_reset + +exit 0 diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc new file mode 100644 index 000000000000..7907d8aacde3 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmatch-onmax-action-hist.tc @@ -0,0 +1,50 @@ +#!/bin/sh +# description: event trigger - test inter-event histogram trigger onmatch-onmax action + +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f synthetic_events ]; then + echo "synthetic event is not supported" + exit_unsupported +fi + +clear_synthetic_events +reset_tracer +do_reset + +echo "Test create synthetic event" + +echo 'wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events +if [ ! -d events/synthetic/wakeup_latency ]; then + fail "Failed to create wakeup_latency synthetic event" +fi + +echo "Test create histogram for synthetic event" +echo "Test histogram variables,simple expression support and onmatch-onmax action" + +echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' > events/sched/sched_wakeup/trigger +echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmatch(sched.sched_wakeup).wakeup_latency($wakeup_lat,next_pid,next_comm):onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm) if next_comm=="ping"' >> events/sched/sched_switch/trigger +echo 'hist:keys=comm,pid,lat:wakeup_lat=lat:sort=lat' > events/synthetic/wakeup_latency/trigger +ping localhost -c 5 +if [ ! grep -q "ping" events/synthetic/wakeup_latency/hist -o ! grep -q "max:" events/sched/sched_switch/hist]; then + fail "Failed to create onmatch-onmax action inter-event histogram" +fi + +do_reset + +exit 0 diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc new file mode 100644 index 000000000000..38b7ed6242b2 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-onmax-action-hist.tc @@ -0,0 +1,48 @@ +#!/bin/sh +# description: event trigger - test inter-event histogram trigger onmax action + +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f synthetic_events ]; then + echo "synthetic event is not supported" + exit_unsupported +fi + +clear_synthetic_events +reset_tracer +do_reset + +echo "Test create synthetic event" + +echo 'wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events +if [ ! -d events/synthetic/wakeup_latency ]; then + fail "Failed to create wakeup_latency synthetic event" +fi + +echo "Test onmax action" + +echo 'hist:keys=pid:ts0=common_timestamp.usecs if comm=="ping"' >> events/sched/sched_waking/trigger +echo 'hist:keys=next_pid:wakeup_lat=common_timestamp.usecs-$ts0:onmax($wakeup_lat).save(next_comm,prev_pid,prev_prio,prev_comm) if next_comm=="ping"' >> events/sched/sched_switch/trigger +ping localhost -c 3 +if ! grep -q "max:" events/sched/sched_switch/hist; then + fail "Failed to create onmax action inter-event histogram" +fi + +do_reset + +exit 0 diff --git a/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-createremove.tc b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-createremove.tc new file mode 100644 index 000000000000..cef11377dcbd --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/trigger/inter-event/trigger-synthetic-event-createremove.tc @@ -0,0 +1,54 @@ +#!/bin/sh +# description: event trigger - test synthetic event create remove +do_reset() { + reset_trigger + echo > set_event + clear_trace +} + +fail() { #msg + do_reset + echo $1 + exit_fail +} + +if [ ! -f set_event ]; then + echo "event tracing is not supported" + exit_unsupported +fi + +if [ ! -f synthetic_events ]; then + echo "synthetic event is not supported" + exit_unsupported +fi + +clear_synthetic_events +reset_tracer +do_reset + +echo "Test create synthetic event" + +echo 'wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events +if [ ! -d events/synthetic/wakeup_latency ]; then + fail "Failed to create wakeup_latency synthetic event" +fi + +reset_trigger + +echo "Test create synthetic event with an error" +echo 'wakeup_latency u64 lat pid_t pid char' > synthetic_events > /dev/null +if [ -d events/synthetic/wakeup_latency ]; then + fail "Created wakeup_latency synthetic event with an invalid format" +fi + +reset_trigger + +echo "Test remove synthetic event" +echo '!wakeup_latency u64 lat pid_t pid char comm[16]' > synthetic_events +if [ -d events/synthetic/wakeup_latency ]; then + fail "Failed to delete wakeup_latency synthetic event" +fi + +do_reset + +exit 0 -- cgit v1.3-14-g43fede From 3a021ab56468db57868a9bc6721b7dfbec672a15 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 11 Mar 2018 09:57:22 +0200 Subject: selftests: forwarding: Add a test for VLAN-unaware bridge Similar to the VLAN-aware bridge test, test the VLAN-unaware bridge and make sure that ping, FDB learning and flooding work as expected. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Reviewed-by: David Ahern Signed-off-by: David S. Miller --- .../net/forwarding/bridge_vlan_unaware.sh | 86 ++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100755 tools/testing/selftests/net/forwarding/bridge_vlan_unaware.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/bridge_vlan_unaware.sh b/tools/testing/selftests/net/forwarding/bridge_vlan_unaware.sh new file mode 100755 index 000000000000..1cddf06f691d --- /dev/null +++ b/tools/testing/selftests/net/forwarding/bridge_vlan_unaware.sh @@ -0,0 +1,86 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +NUM_NETIFS=4 +source lib.sh + +h1_create() +{ + simple_if_init $h1 192.0.2.1/24 2001:db8:1::1/64 +} + +h1_destroy() +{ + simple_if_fini $h1 192.0.2.1/24 2001:db8:1::1/64 +} + +h2_create() +{ + simple_if_init $h2 192.0.2.2/24 2001:db8:1::2/64 +} + +h2_destroy() +{ + simple_if_fini $h2 192.0.2.2/24 2001:db8:1::2/64 +} + +switch_create() +{ + # 10 Seconds ageing time. + ip link add dev br0 type bridge ageing_time 1000 mcast_snooping 0 + + ip link set dev $swp1 master br0 + ip link set dev $swp2 master br0 + + ip link set dev br0 up + ip link set dev $swp1 up + ip link set dev $swp2 up +} + +switch_destroy() +{ + ip link set dev $swp2 down + ip link set dev $swp1 down + + ip link del dev br0 +} + +setup_prepare() +{ + h1=${NETIFS[p1]} + swp1=${NETIFS[p2]} + + swp2=${NETIFS[p3]} + h2=${NETIFS[p4]} + + vrf_prepare + + h1_create + h2_create + + switch_create +} + +cleanup() +{ + pre_cleanup + + switch_destroy + + h2_destroy + h1_destroy + + vrf_cleanup +} + +trap cleanup EXIT + +setup_prepare +setup_wait + +ping_test $h1 192.0.2.2 +ping6_test $h1 2001:db8:1::2 +learning_test "br0" $swp1 $h1 $h2 +flood_test $swp2 $h1 $h2 + +exit $EXIT_STATUS -- cgit v1.3-14-g43fede From ff0162af9e7b2e33d4d40f41130c65ba416ba059 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 11 Mar 2018 09:57:23 +0200 Subject: selftests: forwarding: Exit with error when missing dependencies We already return an error when some dependencies (e.g., 'jq') are missing so lets be consistent and do that for all. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 273511ef2b43..6ac8a98fa270 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -50,7 +50,7 @@ fi if [[ ! -x "$(command -v $MZ)" ]]; then echo "SKIP: $MZ not installed" - exit 0 + exit 1 fi if [[ ! -v NUM_NETIFS ]]; then -- cgit v1.3-14-g43fede From 231b85abaaeef119811a9f036245c94bd5483415 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 11 Mar 2018 09:57:24 +0200 Subject: selftests: forwarding: Exit with error when missing interfaces Returning 0 gives a false sense of success when the required modules did not even manage to be initialized and register the required net devices. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/lib.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index 6ac8a98fa270..e989d8a1d4fb 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -55,7 +55,7 @@ fi if [[ ! -v NUM_NETIFS ]]; then echo "SKIP: importer does not define \"NUM_NETIFS\"" - exit 0 + exit 1 fi ############################################################################## @@ -115,7 +115,7 @@ for i in $(eval echo {1..$NUM_NETIFS}); do ip link show dev ${NETIFS[p$i]} &> /dev/null if [[ $? -ne 0 ]]; then echo "SKIP: could not find all required interfaces" - exit 0 + exit 1 fi done -- cgit v1.3-14-g43fede From 59be45c375e6decce4216dc85fcc8ddf46d38c68 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Sun, 11 Mar 2018 09:57:25 +0200 Subject: selftests: forwarding: Allow creation of interfaces without a config file Some users want to be able to run the tests without a configuration file which is useful when one needs to test both virtual and physical interfaces on the same machine. Move the defines that set the type of interface to create and whether to create it away from the optional configuration file to the library like the rest of the defines. Signed-off-by: Ido Schimmel Reviewed-by: Jiri Pirko Reviewed-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/forwarding/forwarding.config.sample | 9 ++++----- tools/testing/selftests/net/forwarding/lib.sh | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/forwarding/forwarding.config.sample b/tools/testing/selftests/net/forwarding/forwarding.config.sample index df54c9eb5100..e819d049d9ce 100644 --- a/tools/testing/selftests/net/forwarding/forwarding.config.sample +++ b/tools/testing/selftests/net/forwarding/forwarding.config.sample @@ -14,11 +14,6 @@ NETIFS[p6]=veth5 NETIFS[p7]=veth6 NETIFS[p8]=veth7 -NETIF_TYPE=veth - -# only virtual interfaces (veth) can be created by test infra -#NETIF_CREATE=yes - ############################################################################## # Defines @@ -34,3 +29,7 @@ WAIT_TIME=5 PAUSE_ON_FAIL=no # Whether to pause on cleanup or not. PAUSE_ON_CLEANUP=no +# Type of network interface to create +NETIF_TYPE=veth +# Whether to create virtual interfaces (veth) or not +NETIF_CREATE=yes diff --git a/tools/testing/selftests/net/forwarding/lib.sh b/tools/testing/selftests/net/forwarding/lib.sh index e989d8a1d4fb..1ac6c62271f3 100644 --- a/tools/testing/selftests/net/forwarding/lib.sh +++ b/tools/testing/selftests/net/forwarding/lib.sh @@ -11,6 +11,8 @@ MZ=${MZ:=mausezahn} WAIT_TIME=${WAIT_TIME:=5} PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} PAUSE_ON_CLEANUP=${PAUSE_ON_CLEANUP:=no} +NETIF_TYPE=${NETIF_TYPE:=veth} +NETIF_CREATE=${NETIF_CREATE:=yes} if [[ -f forwarding.config ]]; then source forwarding.config -- cgit v1.3-14-g43fede From 08486add3a8d22cd3e41cb59028fc397abdcb279 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Mon, 12 Mar 2018 16:06:37 -0400 Subject: tc-testing: add TC vlan action tests Signed-off-by: Roman Mashak Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/vlan.json | 410 +++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json b/tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json new file mode 100644 index 000000000000..4510ddfa6e54 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/vlan.json @@ -0,0 +1,410 @@ +[ + { + "id": "6f5a", + "name": "Add vlan pop action", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan pop index 8", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*pop.*index 8 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "ee6f", + "name": "Add vlan pop action with large index", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan pop index 4294967295", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*pop.*index 4294967295 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "b6b9", + "name": "Add vlan pop action with jump opcode", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan pop jump 10 index 8", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*jump 10.*index 8 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "87c3", + "name": "Add vlan pop action with trap opcode", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan pop trap index 8", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*pop trap.*index 8 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "2b91", + "name": "Add vlan invalid action", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan bad_mode", + "expExitCode": "255", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*bad_mode", + "matchCount": "0", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "57fc", + "name": "Add vlan action with invalid protocol type", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push protocol ABCD", + "expExitCode": "255", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push", + "matchCount": "0", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "3989", + "name": "Add vlan push action with default protocol and priority", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 123 index 18", + "expExitCode": "0", + "verifyCmd": "$TC actions get action vlan index 18", + "matchPattern": "action order [0-9]+: vlan.*push id 123 protocol 802.1Q priority 0 pipe.*index 18 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "79dc", + "name": "Add vlan push action with protocol 802.1Q and priority 3", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 77 protocol 802.1Q priority 3 continue index 734", + "expExitCode": "0", + "verifyCmd": "$TC actions get action vlan index 734", + "matchPattern": "action order [0-9]+: vlan.*push id 77 protocol 802.1Q priority 3 continue.*index 734 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "4d73", + "name": "Add vlan push action with protocol 802.1AD", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 1024 protocol 802.1AD pass index 10000", + "expExitCode": "0", + "verifyCmd": "$TC actions get action vlan index 10000", + "matchPattern": "action order [0-9]+: vlan.*push id 1024 protocol 802.1ad priority 0 pass.*index 10000 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "1f7b", + "name": "Add vlan push action with invalid vlan ID", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 5678 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push id 5678.*index 1 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "5d02", + "name": "Add vlan push action with invalid IEEE 802.1p priority", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 5 priority 10 index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push id 5.*index 1 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "6812", + "name": "Add vlan modify action for protocol 802.1Q", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan modify protocol 802.1Q id 5 index 100", + "expExitCode": "0", + "verifyCmd": "$TC actions get action vlan index 100", + "matchPattern": "action order [0-9]+: vlan.*modify id 100 protocol 802.1Q priority 0 pipe.*index 100 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "5a31", + "name": "Add vlan modify action for protocol 802.1AD", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan modify protocol 802.1ad id 500 reclassify index 12", + "expExitCode": "0", + "verifyCmd": "$TC actions get action vlan index 12", + "matchPattern": "action order [0-9]+: vlan.*modify id 500 protocol 802.1ad priority 0 reclassify.*index 12 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + }, + { + "id": "83a4", + "name": "Delete vlan pop action", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ], + "$TC actions add action vlan pop index 44" + ], + "cmdUnderTest": "$TC actions del action vlan index 44", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*pop.*index 44 ref", + "matchCount": "0", + "teardown": [] + }, + { + "id": "ed1e", + "name": "Delete vlan push action for protocol 802.1Q", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ], + "$TC actions add action vlan push id 4094 protocol 802.1Q index 999" + ], + "cmdUnderTest": "$TC actions del action vlan index 999", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push id 4094 protocol 802.1Q priority 0 pipe.*index 999 ref", + "matchCount": "0", + "teardown": [] + }, + { + "id": "a2a3", + "name": "Flush vlan actions", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ], + "$TC actions add action vlan push id 4 protocol 802.1ad index 10", + "$TC actions add action vlan push id 4 protocol 802.1ad index 11", + "$TC actions add action vlan push id 4 protocol 802.1ad index 12", + "$TC actions add action vlan push id 4 protocol 802.1ad index 13" + ], + "cmdUnderTest": "$TC actions flush action vlan", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push id 4 protocol 802.1ad", + "matchCount": "0", + "teardown": [] + }, + { + "id": "1d78", + "name": "Add vlan action with cookie", + "category": [ + "actions", + "vlan" + ], + "setup": [ + [ + "$TC actions flush action vlan", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action vlan push id 4 cookie a0a0a0a0a0a0a0", + "expExitCode": "0", + "verifyCmd": "$TC actions list action vlan", + "matchPattern": "action order [0-9]+: vlan.*push id 4.*cookie a0a0a0a0a0a0a0", + "matchCount": "1", + "teardown": [ + "$TC actions flush action vlan" + ] + } +] -- cgit v1.3-14-g43fede From 9ba32046fc2d19697e1a208ce81663239e78e41f Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Mon, 12 Mar 2018 16:07:02 -0400 Subject: tc-testing: updated gact tests with batch test cases Signed-off-by: Roman Mashak Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/gact.json | 73 +++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json index e2187b6e0b7a..ae96d0350d7e 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json @@ -465,5 +465,76 @@ "teardown": [ "$TC actions flush action gact" ] + }, + { + "id": "1021", + "name": "Add batch of 32 gact pass actions", + "category": [ + "actions", + "gact" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action pass index $i \"; args=\"$args$cmd\"; done && $TC actions add $args", + "expExitCode": "0", + "verifyCmd": "$TC actions list action gact", + "matchPattern": "^[ \t]+index [0-9]+ ref", + "matchCount": "32", + "teardown": [ + "$TC actions flush action gact" + ] + }, + { + "id": "da7a", + "name": "Add batch of 32 gact continue actions with cookie", + "category": [ + "actions", + "gact" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action continue index $i cookie aabbccddeeff112233445566778800a1 \"; args=\"$args$cmd\"; done && $TC actions add $args", + "expExitCode": "0", + "verifyCmd": "$TC actions list action gact", + "matchPattern": "^[ \t]+index [0-9]+ ref", + "matchCount": "32", + "teardown": [ + "$TC actions flush action gact" + ] + }, + { + "id": "8aa3", + "name": "Delete batch of 32 gact continue actions", + "category": [ + "actions", + "gact" + ], + "setup": [ + [ + "$TC actions flush action gact", + 0, + 1, + 255 + ], + "for i in `seq 1 32`; do cmd=\"action continue index $i \"; args=\"$args$cmd\"; done && $TC actions add $args" + ], + "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action gact index $i \"; args=\"$args$cmd\"; done && $TC actions del $args", + "expExitCode": "0", + "verifyCmd": "$TC actions list action gact", + "matchPattern": "^[ \t]+index [0-9]+ ref", + "matchCount": "0", + "teardown": [] } -] +] \ No newline at end of file -- cgit v1.3-14-g43fede From 9c96c932871efeabe82fcfdc952f35810484b510 Mon Sep 17 00:00:00 2001 From: Laurent Dufour Date: Mon, 22 Aug 2016 18:53:02 +0200 Subject: selftest/powerpc: Add test for sigreturn in transaction Ensure that kernel is throwing away the suspended transaction when sigreturn() is called otherwise it if fails to restore the signal frame's TM SPRS. Signed-off-by: Laurent Dufour Reviewed-by: Cyril Bur [mpe: Add have_htm() check, minor formatting, add SPDX tag] Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/tm/Makefile | 2 +- tools/testing/selftests/powerpc/tm/tm-sigreturn.c | 92 +++++++++++++++++++++++ 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/tm/tm-sigreturn.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/powerpc/tm/Makefile b/tools/testing/selftests/powerpc/tm/Makefile index a23453943ad2..1c9e5d0a0491 100644 --- a/tools/testing/selftests/powerpc/tm/Makefile +++ b/tools/testing/selftests/powerpc/tm/Makefile @@ -4,7 +4,7 @@ SIGNAL_CONTEXT_CHK_TESTS := tm-signal-context-chk-gpr tm-signal-context-chk-fpu TEST_GEN_PROGS := tm-resched-dscr tm-syscall tm-signal-msr-resv tm-signal-stack \ tm-vmxcopy tm-fork tm-tar tm-tmspr tm-vmx-unavail tm-unavailable tm-trap \ - $(SIGNAL_CONTEXT_CHK_TESTS) + $(SIGNAL_CONTEXT_CHK_TESTS) tm-sigreturn include ../../lib.mk diff --git a/tools/testing/selftests/powerpc/tm/tm-sigreturn.c b/tools/testing/selftests/powerpc/tm/tm-sigreturn.c new file mode 100644 index 000000000000..85d63449243b --- /dev/null +++ b/tools/testing/selftests/powerpc/tm/tm-sigreturn.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright 2015, Laurent Dufour, IBM Corp. + * + * Test the kernel's signal returning code to check reclaim is done if the + * sigreturn() is called while in a transaction (suspended since active is + * already dropped trough the system call path). + * + * The kernel must discard the transaction when entering sigreturn, since + * restoring the potential TM SPRS from the signal frame is requiring to not be + * in a transaction. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "tm.h" +#include "utils.h" + + +void handler(int sig) +{ + uint64_t ret; + + asm __volatile__( + "li 3,1 ;" + "tbegin. ;" + "beq 1f ;" + "li 3,0 ;" + "tsuspend. ;" + "1: ;" + "std%X[ret] 3, %[ret] ;" + : [ret] "=m"(ret) + : + : "memory", "3", "cr0"); + + if (ret) + exit(1); + + /* + * We return from the signal handle while in a suspended transaction + */ +} + + +int tm_sigreturn(void) +{ + struct sigaction sa; + uint64_t ret = 0; + + SKIP_IF(!have_htm()); + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = handler; + sigemptyset(&sa.sa_mask); + + if (sigaction(SIGSEGV, &sa, NULL)) + exit(1); + + asm __volatile__( + "tbegin. ;" + "beq 1f ;" + "li 3,0 ;" + "std 3,0(3) ;" /* trigger SEGV */ + "li 3,1 ;" + "std%X[ret] 3,%[ret] ;" + "tend. ;" + "b 2f ;" + "1: ;" + "li 3,2 ;" + "std%X[ret] 3,%[ret] ;" + "2: ;" + : [ret] "=m"(ret) + : + : "memory", "3", "cr0"); + + if (ret != 2) + exit(1); + + exit(0); +} + +int main(void) +{ + return test_harness(tm_sigreturn, "tm_sigreturn"); +} -- cgit v1.3-14-g43fede From b395e55b49ecd56ea28dc629f4ca4c6239fc07c3 Mon Sep 17 00:00:00 2001 From: Gustavo Romero Date: Mon, 5 Mar 2018 15:48:55 -0500 Subject: selftests/powerpc: Skip tm-unavailable if TM is not enabled Some processor revisions do not support transactional memory, and additionally kernel support can be disabled. In either case the tm-unavailable test should be skipped, otherwise it will fail with a SIGILL. That commit also sets this selftest to be called through the test harness as it's done for other TM selftests. Finally, it avoids using "ping" as a thread name since it's ambiguous and can be confusing when shown, for instance, in a kernel backtrace log. Fixes: 77fad8bfb1d2 ("selftests/powerpc: Check FP/VEC on exception in TM") Signed-off-by: Gustavo Romero Reviewed-by: Cyril Bur Signed-off-by: Michael Ellerman --- .../testing/selftests/powerpc/tm/tm-unavailable.c | 24 ++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/powerpc/tm/tm-unavailable.c b/tools/testing/selftests/powerpc/tm/tm-unavailable.c index e6a0fad2bfd0..156c8e750259 100644 --- a/tools/testing/selftests/powerpc/tm/tm-unavailable.c +++ b/tools/testing/selftests/powerpc/tm/tm-unavailable.c @@ -80,7 +80,7 @@ bool is_failure(uint64_t condition_reg) return ((condition_reg >> 28) & 0xa) == 0xa; } -void *ping(void *input) +void *tm_una_ping(void *input) { /* @@ -280,7 +280,7 @@ void *ping(void *input) } /* Thread to force context switch */ -void *pong(void *not_used) +void *tm_una_pong(void *not_used) { /* Wait thread get its name "pong". */ if (DEBUG) @@ -311,11 +311,11 @@ void test_fp_vec(int fp, int vec, pthread_attr_t *attr) do { int rc; - /* Bind 'ping' to CPU 0, as specified in 'attr'. */ - rc = pthread_create(&t0, attr, ping, (void *) &flags); + /* Bind to CPU 0, as specified in 'attr'. */ + rc = pthread_create(&t0, attr, tm_una_ping, (void *) &flags); if (rc) pr_err(rc, "pthread_create()"); - rc = pthread_setname_np(t0, "ping"); + rc = pthread_setname_np(t0, "tm_una_ping"); if (rc) pr_warn(rc, "pthread_setname_np"); rc = pthread_join(t0, &ret_value); @@ -333,13 +333,15 @@ void test_fp_vec(int fp, int vec, pthread_attr_t *attr) } } -int main(int argc, char **argv) +int tm_unavailable_test(void) { int rc, exception; /* FP = 0, VEC = 1, VSX = 2 */ pthread_t t1; pthread_attr_t attr; cpu_set_t cpuset; + SKIP_IF(!have_htm()); + /* Set only CPU 0 in the mask. Both threads will be bound to CPU 0. */ CPU_ZERO(&cpuset); CPU_SET(0, &cpuset); @@ -354,12 +356,12 @@ int main(int argc, char **argv) if (rc) pr_err(rc, "pthread_attr_setaffinity_np()"); - rc = pthread_create(&t1, &attr /* Bind 'pong' to CPU 0 */, pong, NULL); + rc = pthread_create(&t1, &attr /* Bind to CPU 0 */, tm_una_pong, NULL); if (rc) pr_err(rc, "pthread_create()"); /* Name it for systemtap convenience */ - rc = pthread_setname_np(t1, "pong"); + rc = pthread_setname_np(t1, "tm_una_pong"); if (rc) pr_warn(rc, "pthread_create()"); @@ -394,3 +396,9 @@ int main(int argc, char **argv) exit(0); } } + +int main(int argc, char **argv) +{ + test_harness_set_timeout(220); + return test_harness(tm_unavailable_test, "tm_unavailable_test"); +} -- cgit v1.3-14-g43fede From 327d53d005ca47b10eae940616ed11c569f75a9b Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 13 Mar 2018 22:03:10 -0700 Subject: selftests/x86/entry_from_vm86: Exit with 1 if we fail Fix a logic error that caused the test to exit with 0 even if test cases failed. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stas Sergeev Cc: Thomas Gleixner Cc: bartoldeman@gmail.com Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/b1cc37144038958a469c8f70a5f47a6a5638636a.1521003603.git.luto@kernel.org Signed-off-by: Ingo Molnar --- tools/testing/selftests/x86/entry_from_vm86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index 361466a2eaef..6e85f0d0498d 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c @@ -318,7 +318,7 @@ int main(void) clearhandler(SIGSEGV); /* Make sure nothing explodes if we fork. */ - if (fork() > 0) + if (fork() == 0) return 0; return (nerrs == 0 ? 0 : 1); -- cgit v1.3-14-g43fede From 78393fdde2a456cafa414b171c90f26a3df98b20 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 13 Mar 2018 22:03:11 -0700 Subject: selftests/x86/entry_from_vm86: Add test cases for POPF POPF is currently broken -- add tests to catch the error. This results in: [RUN] POPF with VIP set and IF clear from vm86 mode [INFO] Exited vm86 mode due to STI [FAIL] Incorrect return reason (started at eip = 0xd, ended at eip = 0xf) because POPF currently fails to check IF before reporting a pending interrupt. This patch also makes the FAIL message a bit more informative. Reported-by: Bart Oldeman Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Josh Poimboeuf Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Stas Sergeev Cc: Thomas Gleixner Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/a16270b5cfe7832d6d00c479d0f871066cbdb52b.1521003603.git.luto@kernel.org Signed-off-by: Ingo Molnar --- tools/testing/selftests/x86/entry_from_vm86.c | 30 ++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c index 6e85f0d0498d..ade443a88421 100644 --- a/tools/testing/selftests/x86/entry_from_vm86.c +++ b/tools/testing/selftests/x86/entry_from_vm86.c @@ -95,6 +95,10 @@ asm ( "int3\n\t" "vmcode_int80:\n\t" "int $0x80\n\t" + "vmcode_popf_hlt:\n\t" + "push %ax\n\t" + "popf\n\t" + "hlt\n\t" "vmcode_umip:\n\t" /* addressing via displacements */ "smsw (2052)\n\t" @@ -124,8 +128,8 @@ asm ( extern unsigned char vmcode[], end_vmcode[]; extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], - vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[], - vmcode_umip_str[], vmcode_umip_sldt[]; + vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_popf_hlt[], + vmcode_umip[], vmcode_umip_str[], vmcode_umip_sldt[]; /* Returns false if the test was skipped. */ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, @@ -175,7 +179,7 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip, (VM86_TYPE(ret) == rettype && VM86_ARG(ret) == retarg)) { printf("[OK]\tReturned correctly\n"); } else { - printf("[FAIL]\tIncorrect return reason\n"); + printf("[FAIL]\tIncorrect return reason (started at eip = 0x%lx, ended at eip = 0x%lx)\n", eip, v86->regs.eip); nerrs++; } @@ -264,6 +268,9 @@ int main(void) v86.regs.ds = load_addr / 16; v86.regs.es = load_addr / 16; + /* Use the end of the page as our stack. */ + v86.regs.esp = 4096; + assert((v86.regs.cs & 3) == 0); /* Looks like RPL = 0 */ /* #BR -- should deliver SIG??? */ @@ -295,6 +302,23 @@ int main(void) v86.regs.eflags &= ~X86_EFLAGS_IF; do_test(&v86, vmcode_sti - vmcode, VM86_STI, 0, "STI with VIP set"); + /* POPF with VIP set but IF clear: should not trap */ + v86.regs.eflags = X86_EFLAGS_VIP; + v86.regs.eax = 0; + do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP set and IF clear"); + + /* POPF with VIP set and IF set: should trap */ + v86.regs.eflags = X86_EFLAGS_VIP; + v86.regs.eax = X86_EFLAGS_IF; + do_test(&v86, vmcode_popf_hlt - vmcode, VM86_STI, 0, "POPF with VIP and IF set"); + + /* POPF with VIP clear and IF set: should not trap */ + v86.regs.eflags = 0; + v86.regs.eax = X86_EFLAGS_IF; + do_test(&v86, vmcode_popf_hlt - vmcode, VM86_UNKNOWN, 0, "POPF with VIP clear and IF set"); + + v86.regs.eflags = 0; + /* INT3 -- should cause #BP */ do_test(&v86, vmcode_int3 - vmcode, VM86_TRAP, 3, "INT3"); -- cgit v1.3-14-g43fede From ce290a19609d5ecd4a240a4750e0ed9a476cf015 Mon Sep 17 00:00:00 2001 From: Christian Brauner Date: Tue, 13 Mar 2018 17:55:27 +0100 Subject: selftests: add devpts selftests This adds tests to check: - bind-mounts from /dev/pts/ptmx to /dev/ptmx work - non-standard mounts of devpts work - bind-mounts of /dev/pts/ptmx to locations that do not resolve to a valid slave pty path under the originating devpts mount fail Signed-off-by: Christian Brauner Acked-by: "Eric W. Biederman" Acked-by: Linus Torvalds Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/filesystems/.gitignore | 1 + tools/testing/selftests/filesystems/Makefile | 2 +- tools/testing/selftests/filesystems/devpts_pts.c | 313 +++++++++++++++++++++++ 4 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/filesystems/devpts_pts.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 7442dfb73b7f..dbda89c9d9b9 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -7,6 +7,7 @@ TARGETS += cpufreq TARGETS += cpu-hotplug TARGETS += efivarfs TARGETS += exec +TARGETS += filesystems TARGETS += firmware TARGETS += ftrace TARGETS += futex diff --git a/tools/testing/selftests/filesystems/.gitignore b/tools/testing/selftests/filesystems/.gitignore index 31d6e426b6d4..8449cf6716ce 100644 --- a/tools/testing/selftests/filesystems/.gitignore +++ b/tools/testing/selftests/filesystems/.gitignore @@ -1 +1,2 @@ dnotify_test +devpts_pts diff --git a/tools/testing/selftests/filesystems/Makefile b/tools/testing/selftests/filesystems/Makefile index 13a73bf725b5..4e6d09fb166f 100644 --- a/tools/testing/selftests/filesystems/Makefile +++ b/tools/testing/selftests/filesystems/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 -TEST_PROGS := dnotify_test +TEST_PROGS := dnotify_test devpts_pts all: $(TEST_PROGS) include ../lib.mk diff --git a/tools/testing/selftests/filesystems/devpts_pts.c b/tools/testing/selftests/filesystems/devpts_pts.c new file mode 100644 index 000000000000..b9055e974289 --- /dev/null +++ b/tools/testing/selftests/filesystems/devpts_pts.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static bool terminal_dup2(int duplicate, int original) +{ + int ret; + + ret = dup2(duplicate, original); + if (ret < 0) + return false; + + return true; +} + +static int terminal_set_stdfds(int fd) +{ + int i; + + if (fd < 0) + return 0; + + for (i = 0; i < 3; i++) + if (!terminal_dup2(fd, (int[]){STDIN_FILENO, STDOUT_FILENO, + STDERR_FILENO}[i])) + return -1; + + return 0; +} + +static int login_pty(int fd) +{ + int ret; + + setsid(); + + ret = ioctl(fd, TIOCSCTTY, NULL); + if (ret < 0) + return -1; + + ret = terminal_set_stdfds(fd); + if (ret < 0) + return -1; + + if (fd > STDERR_FILENO) + close(fd); + + return 0; +} + +static int wait_for_pid(pid_t pid) +{ + int status, ret; + +again: + ret = waitpid(pid, &status, 0); + if (ret == -1) { + if (errno == EINTR) + goto again; + return -1; + } + if (ret != pid) + goto again; + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + return -1; + + return 0; +} + +static int resolve_procfd_symlink(int fd, char *buf, size_t buflen) +{ + int ret; + char procfd[4096]; + + ret = snprintf(procfd, 4096, "/proc/self/fd/%d", fd); + if (ret < 0 || ret >= 4096) + return -1; + + ret = readlink(procfd, buf, buflen); + if (ret < 0 || (size_t)ret >= buflen) + return -1; + + buf[ret] = '\0'; + + return 0; +} + +static int do_tiocgptpeer(char *ptmx, char *expected_procfd_contents) +{ + int ret; + int master = -1, slave = -1, fret = -1; + + master = open(ptmx, O_RDWR | O_NOCTTY | O_CLOEXEC); + if (master < 0) { + fprintf(stderr, "Failed to open \"%s\": %s\n", ptmx, + strerror(errno)); + return -1; + } + + /* + * grantpt() makes assumptions about /dev/pts/ so ignore it. It's also + * not really needed. + */ + ret = unlockpt(master); + if (ret < 0) { + fprintf(stderr, "Failed to unlock terminal\n"); + goto do_cleanup; + } + +#ifdef TIOCGPTPEER + slave = ioctl(master, TIOCGPTPEER, O_RDWR | O_NOCTTY | O_CLOEXEC); +#endif + if (slave < 0) { + if (errno == EINVAL) { + fprintf(stderr, "TIOCGPTPEER is not supported. " + "Skipping test.\n"); + fret = EXIT_SUCCESS; + } + + fprintf(stderr, "Failed to perform TIOCGPTPEER ioctl\n"); + goto do_cleanup; + } + + pid_t pid = fork(); + if (pid < 0) + goto do_cleanup; + + if (pid == 0) { + char buf[4096]; + + ret = login_pty(slave); + if (ret < 0) { + fprintf(stderr, "Failed to setup terminal\n"); + _exit(EXIT_FAILURE); + } + + ret = resolve_procfd_symlink(STDIN_FILENO, buf, sizeof(buf)); + if (ret < 0) { + fprintf(stderr, "Failed to retrieve pathname of pts " + "slave file descriptor\n"); + _exit(EXIT_FAILURE); + } + + if (strncmp(expected_procfd_contents, buf, + strlen(expected_procfd_contents)) != 0) { + fprintf(stderr, "Received invalid contents for " + "\"/proc//fd/%d\" symlink: %s\n", + STDIN_FILENO, buf); + _exit(-1); + } + + fprintf(stderr, "Contents of \"/proc//fd/%d\" " + "symlink are valid: %s\n", STDIN_FILENO, buf); + + _exit(EXIT_SUCCESS); + } + + ret = wait_for_pid(pid); + if (ret < 0) + goto do_cleanup; + + fret = EXIT_SUCCESS; + +do_cleanup: + if (master >= 0) + close(master); + if (slave >= 0) + close(slave); + + return fret; +} + +static int verify_non_standard_devpts_mount(void) +{ + char *mntpoint; + int ret = -1; + char devpts[] = P_tmpdir "/devpts_fs_XXXXXX"; + char ptmx[] = P_tmpdir "/devpts_fs_XXXXXX/ptmx"; + + ret = umount("/dev/pts"); + if (ret < 0) { + fprintf(stderr, "Failed to unmount \"/dev/pts\": %s\n", + strerror(errno)); + return -1; + } + + (void)umount("/dev/ptmx"); + + mntpoint = mkdtemp(devpts); + if (!mntpoint) { + fprintf(stderr, "Failed to create temporary mountpoint: %s\n", + strerror(errno)); + return -1; + } + + ret = mount("devpts", mntpoint, "devpts", MS_NOSUID | MS_NOEXEC, + "newinstance,ptmxmode=0666,mode=0620,gid=5"); + if (ret < 0) { + fprintf(stderr, "Failed to mount devpts fs to \"%s\" in new " + "mount namespace: %s\n", mntpoint, + strerror(errno)); + unlink(mntpoint); + return -1; + } + + ret = snprintf(ptmx, sizeof(ptmx), "%s/ptmx", devpts); + if (ret < 0 || (size_t)ret >= sizeof(ptmx)) { + unlink(mntpoint); + return -1; + } + + ret = do_tiocgptpeer(ptmx, mntpoint); + unlink(mntpoint); + if (ret < 0) + return -1; + + return 0; +} + +static int verify_ptmx_bind_mount(void) +{ + int ret; + + ret = mount("/dev/pts/ptmx", "/dev/ptmx", NULL, MS_BIND, NULL); + if (ret < 0) { + fprintf(stderr, "Failed to bind mount \"/dev/pts/ptmx\" to " + "\"/dev/ptmx\" mount namespace\n"); + return -1; + } + + ret = do_tiocgptpeer("/dev/ptmx", "/dev/pts/"); + if (ret < 0) + return -1; + + return 0; +} + +static int verify_invalid_ptmx_bind_mount(void) +{ + int ret; + char mntpoint_fd; + char ptmx[] = P_tmpdir "/devpts_ptmx_XXXXXX"; + + mntpoint_fd = mkstemp(ptmx); + if (mntpoint_fd < 0) { + fprintf(stderr, "Failed to create temporary directory: %s\n", + strerror(errno)); + return -1; + } + + ret = mount("/dev/pts/ptmx", ptmx, NULL, MS_BIND, NULL); + close(mntpoint_fd); + if (ret < 0) { + fprintf(stderr, "Failed to bind mount \"/dev/pts/ptmx\" to " + "\"%s\" mount namespace\n", ptmx); + return -1; + } + + ret = do_tiocgptpeer(ptmx, "/dev/pts/"); + if (ret == 0) + return -1; + + return 0; +} + +int main(int argc, char *argv[]) +{ + int ret; + + if (!isatty(STDIN_FILENO)) { + fprintf(stderr, "Standard input file desciptor is not attached " + "to a terminal. Skipping test\n"); + exit(EXIT_FAILURE); + } + + ret = unshare(CLONE_NEWNS); + if (ret < 0) { + fprintf(stderr, "Failed to unshare mount namespace\n"); + exit(EXIT_FAILURE); + } + + ret = mount("", "/", NULL, MS_PRIVATE | MS_REC, 0); + if (ret < 0) { + fprintf(stderr, "Failed to make \"/\" MS_PRIVATE in new mount " + "namespace\n"); + exit(EXIT_FAILURE); + } + + ret = verify_ptmx_bind_mount(); + if (ret < 0) + exit(EXIT_FAILURE); + + ret = verify_invalid_ptmx_bind_mount(); + if (ret < 0) + exit(EXIT_FAILURE); + + ret = verify_non_standard_devpts_mount(); + if (ret < 0) + exit(EXIT_FAILURE); + + exit(EXIT_SUCCESS); +} -- cgit v1.3-14-g43fede From 29a1c00ce1df8a75bea6e6a86876a10c8dcc2c59 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 10 Mar 2018 06:14:42 -0800 Subject: test_firmware: add simple firmware firmware test library We'll expland on this later, for now just add basic module checker. While at it, move this all to use /bin/bash as we'll have much more flexibility with it. Signed-off-by: Luis R. Rodriguez Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/firmware/fw_fallback.sh | 7 ++-- tools/testing/selftests/firmware/fw_filesystem.sh | 20 ++--------- tools/testing/selftests/firmware/fw_lib.sh | 44 +++++++++++++++++++++++ 3 files changed, 51 insertions(+), 20 deletions(-) create mode 100755 tools/testing/selftests/firmware/fw_lib.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/firmware/fw_fallback.sh b/tools/testing/selftests/firmware/fw_fallback.sh index 722cad91df74..755147a8c967 100755 --- a/tools/testing/selftests/firmware/fw_fallback.sh +++ b/tools/testing/selftests/firmware/fw_fallback.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # This validates that the kernel will fall back to using the fallback mechanism # to load firmware it can't find on disk itself. We must request a firmware @@ -6,9 +6,10 @@ # won't find so that we can do the load ourself manually. set -e -modprobe test_firmware +TEST_DIR=$(dirname $0) +source $TEST_DIR/fw_lib.sh -DIR=/sys/devices/virtual/misc/test_firmware +check_mods # CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/ # These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh index f9508e1a4058..748f2f5737e9 100755 --- a/tools/testing/selftests/firmware/fw_filesystem.sh +++ b/tools/testing/selftests/firmware/fw_filesystem.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # SPDX-License-Identifier: GPL-2.0 # This validates that the kernel will load firmware out of its list of # firmware locations on disk. Since the user helper does similar work, @@ -6,24 +6,10 @@ # know so we can be sure we're not accidentally testing the user helper. set -e -DIR=/sys/devices/virtual/misc/test_firmware TEST_DIR=$(dirname $0) +source $TEST_DIR/fw_lib.sh -test_modprobe() -{ - if [ ! -d $DIR ]; then - echo "$0: $DIR not present" - echo "You must have the following enabled in your kernel:" - cat $TEST_DIR/config - exit 1 - fi -} - -trap "test_modprobe" EXIT - -if [ ! -d $DIR ]; then - modprobe test_firmware -fi +check_mods # CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/ # These days most distros enable CONFIG_FW_LOADER_USER_HELPER but disable diff --git a/tools/testing/selftests/firmware/fw_lib.sh b/tools/testing/selftests/firmware/fw_lib.sh new file mode 100755 index 000000000000..c14bbca7ecf9 --- /dev/null +++ b/tools/testing/selftests/firmware/fw_lib.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# Library of helpers for test scripts. +set -e + +DIR=/sys/devices/virtual/misc/test_firmware + +PROC_CONFIG="/proc/config.gz" +TEST_DIR=$(dirname $0) + +print_reqs_exit() +{ + echo "You must have the following enabled in your kernel:" >&2 + cat $TEST_DIR/config >&2 + exit 1 +} + +test_modprobe() +{ + if [ ! -d $DIR ]; then + print_reqs_exit + fi +} + +check_mods() +{ + trap "test_modprobe" EXIT + if [ ! -d $DIR ]; then + modprobe test_firmware + fi + if [ ! -f $PROC_CONFIG ]; then + if modprobe configs 2>/dev/null; then + echo "Loaded configs module" + if [ ! -f $PROC_CONFIG ]; then + echo "You must have the following enabled in your kernel:" >&2 + cat $TEST_DIR/config >&2 + echo "Resorting to old heuristics" >&2 + fi + else + echo "Failed to load configs module, using old heuristics" >&2 + fi + fi +} -- cgit v1.3-14-g43fede From ef557787f4f04b62d7a50101154ffe1614b88a7a Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 10 Mar 2018 06:14:43 -0800 Subject: test_firmware: enable custom fallback testing on limited kernel configs When a kernel is not built with: CONFIG_HAS_FW_LOADER_USER_HELPER_FALLBACK=y We don't currently enable testing fw_fallback.sh. For kernels that still enable the fallback mechanism, its possible to use the async request firmware API call request_firmware_nowait() using the custom interface to use the fallback mechanism, so we should be able to test this but we currently cannot. We can enable testing without CONFIG_HAS_FW_LOADER_USER_HELPER_FALLBACK=y by relying on /proc/config.gz (CONFIG_IKCONFIG_PROC), if present. If you don't have this we'll have no option but to rely on old heuristics for now. We stuff the new kconfig_has() helper into our shared library as we'll later expando on its use elsewhere. Acked-by: Kees Cook Signed-off-by: Luis R. Rodriguez Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/firmware/config | 4 ++++ tools/testing/selftests/firmware/fw_fallback.sh | 6 +++++- tools/testing/selftests/firmware/fw_lib.sh | 24 ++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/firmware/config b/tools/testing/selftests/firmware/config index c8137f70e291..bf634dda0720 100644 --- a/tools/testing/selftests/firmware/config +++ b/tools/testing/selftests/firmware/config @@ -1 +1,5 @@ CONFIG_TEST_FIRMWARE=y +CONFIG_FW_LOADER=y +CONFIG_FW_LOADER_USER_HELPER=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y diff --git a/tools/testing/selftests/firmware/fw_fallback.sh b/tools/testing/selftests/firmware/fw_fallback.sh index 755147a8c967..bf850050e5e9 100755 --- a/tools/testing/selftests/firmware/fw_fallback.sh +++ b/tools/testing/selftests/firmware/fw_fallback.sh @@ -15,6 +15,7 @@ check_mods # These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that # as an indicator for CONFIG_FW_LOADER_USER_HELPER. HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi) +HAS_FW_LOADER_USER_HELPER_FALLBACK=$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y) if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) @@ -287,7 +288,10 @@ run_sysfs_custom_load_tests() fi } -run_sysfs_main_tests +if [ "$HAS_FW_LOADER_USER_HELPER_FALLBACK" = "yes" ]; then + run_sysfs_main_tests +fi + run_sysfs_custom_load_tests exit 0 diff --git a/tools/testing/selftests/firmware/fw_lib.sh b/tools/testing/selftests/firmware/fw_lib.sh index c14bbca7ecf9..467567c758b9 100755 --- a/tools/testing/selftests/firmware/fw_lib.sh +++ b/tools/testing/selftests/firmware/fw_lib.sh @@ -42,3 +42,27 @@ check_mods() fi fi } + +kconfig_has() +{ + if [ -f $PROC_CONFIG ]; then + if zgrep -q $1 $PROC_CONFIG 2>/dev/null; then + echo "yes" + else + echo "no" + fi + else + # We currently don't have easy heuristics to infer this + # so best we can do is just try to use the kernel assuming + # you had enabled it. This matches the old behaviour. + if [ "$1" = "CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y" ]; then + echo "yes" + elif [ "$1" = "CONFIG_FW_LOADER_USER_HELPER=y" ]; then + if [ -d /sys/class/firmware/ ]; then + echo yes + else + echo no + fi + fi + fi +} -- cgit v1.3-14-g43fede From 9cc853203c3bf4d3b0c466c5525750c071624b05 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 10 Mar 2018 06:14:44 -0800 Subject: test_firmware: replace syfs fallback check with kconfig_has helper Now that we have a kconfig checker just use that instead of relying on testing a sysfs directory being present, since our requirements are spelled out. Acked-by: Kees Cook Signed-off-by: Luis R. Rodriguez Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/firmware/fw_fallback.sh | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/firmware/fw_fallback.sh b/tools/testing/selftests/firmware/fw_fallback.sh index bf850050e5e9..323c921a2469 100755 --- a/tools/testing/selftests/firmware/fw_fallback.sh +++ b/tools/testing/selftests/firmware/fw_fallback.sh @@ -11,10 +11,7 @@ source $TEST_DIR/fw_lib.sh check_mods -# CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/ -# These days no one enables CONFIG_FW_LOADER_USER_HELPER so check for that -# as an indicator for CONFIG_FW_LOADER_USER_HELPER. -HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi) +HAS_FW_LOADER_USER_HELPER=$(kconfig_has CONFIG_FW_LOADER_USER_HELPER=y) HAS_FW_LOADER_USER_HELPER_FALLBACK=$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y) if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then -- cgit v1.3-14-g43fede From 81f77fd0deeb866d65ccc79733df8d2af5217c82 Mon Sep 17 00:00:00 2001 From: Song Liu Date: Wed, 14 Mar 2018 10:23:22 -0700 Subject: bpf: add selftest for stackmap with BPF_F_STACK_BUILD_ID test_stacktrace_build_id() is added. It accesses tracepoint urandom_read with "dd" and "urandom_read" and gathers stack traces. Then it reads the stack traces from the stackmap. urandom_read is a statically link binary that reads from /dev/urandom. test_stacktrace_build_id() calls readelf to read build ID of urandom_read and compares it with build ID from the stackmap. Signed-off-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 22 +++ tools/testing/selftests/bpf/Makefile | 12 +- tools/testing/selftests/bpf/test_progs.c | 164 ++++++++++++++++++++- .../selftests/bpf/test_stacktrace_build_id.c | 60 ++++++++ tools/testing/selftests/bpf/urandom_read.c | 22 +++ 5 files changed, 278 insertions(+), 2 deletions(-) create mode 100644 tools/testing/selftests/bpf/test_stacktrace_build_id.c create mode 100644 tools/testing/selftests/bpf/urandom_read.c (limited to 'tools/testing') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index db6bdc375126..1944d0aee7e8 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -231,6 +231,28 @@ enum bpf_attach_type { #define BPF_F_RDONLY (1U << 3) #define BPF_F_WRONLY (1U << 4) +/* Flag for stack_map, store build_id+offset instead of pointer */ +#define BPF_F_STACK_BUILD_ID (1U << 5) + +enum bpf_stack_build_id_status { + /* user space need an empty entry to identify end of a trace */ + BPF_STACK_BUILD_ID_EMPTY = 0, + /* with valid build_id and offset */ + BPF_STACK_BUILD_ID_VALID = 1, + /* couldn't get build_id, fallback to ip */ + BPF_STACK_BUILD_ID_IP = 2, +}; + +#define BPF_BUILD_ID_SIZE 20 +struct bpf_stack_build_id { + __s32 status; + unsigned char build_id[BPF_BUILD_ID_SIZE]; + union { + __u64 offset; + __u64 ip; + }; +}; + union bpf_attr { struct { /* anonymous struct used by BPF_MAP_CREATE command */ __u32 map_type; /* one of enum bpf_map_type */ diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 8567a858b789..b0d29fd5e51c 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -13,6 +13,14 @@ endif CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include LDLIBS += -lcap -lelf -lrt -lpthread +TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read +all: $(TEST_CUSTOM_PROGS) + +$(TEST_CUSTOM_PROGS): urandom_read + +urandom_read: urandom_read.c + $(CC) -o $(TEST_CUSTOM_PROGS) -static $< + # Order correspond to 'make run_tests' order TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ test_align test_verifier_log test_dev_cgroup test_tcpbpf_user @@ -21,7 +29,7 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ - sample_map_ret0.o test_tcpbpf_kern.o + sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ @@ -74,3 +82,5 @@ $(OUTPUT)/%.o: %.c $(CLANG) $(CLANG_FLAGS) \ -O2 -target bpf -emit-llvm -c $< -o - | \ $(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@ + +EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index 27ad5404389e..e9df48b306df 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -841,7 +841,8 @@ static void test_tp_attach_query(void) static int compare_map_keys(int map1_fd, int map2_fd) { __u32 key, next_key; - char val_buf[PERF_MAX_STACK_DEPTH * sizeof(__u64)]; + char val_buf[PERF_MAX_STACK_DEPTH * + sizeof(struct bpf_stack_build_id)]; int err; err = bpf_map_get_next_key(map1_fd, NULL, &key); @@ -964,6 +965,166 @@ out: return; } +static int extract_build_id(char *build_id, size_t size) +{ + FILE *fp; + char *line = NULL; + size_t len = 0; + + fp = popen("readelf -n ./urandom_read | grep 'Build ID'", "r"); + if (fp == NULL) + return -1; + + if (getline(&line, &len, fp) == -1) + goto err; + fclose(fp); + + if (len > size) + len = size; + memcpy(build_id, line, len); + build_id[len] = '\0'; + return 0; +err: + fclose(fp); + return -1; +} + +static void test_stacktrace_build_id(void) +{ + int control_map_fd, stackid_hmap_fd, stackmap_fd; + const char *file = "./test_stacktrace_build_id.o"; + int bytes, efd, err, pmu_fd, prog_fd; + struct perf_event_attr attr = {}; + __u32 key, previous_key, val, duration = 0; + struct bpf_object *obj; + char buf[256]; + int i, j; + struct bpf_stack_build_id id_offs[PERF_MAX_STACK_DEPTH]; + int build_id_matches = 0; + + err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd); + if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno)) + goto out; + + /* Get the ID for the sched/sched_switch tracepoint */ + snprintf(buf, sizeof(buf), + "/sys/kernel/debug/tracing/events/random/urandom_read/id"); + efd = open(buf, O_RDONLY, 0); + if (CHECK(efd < 0, "open", "err %d errno %d\n", efd, errno)) + goto close_prog; + + bytes = read(efd, buf, sizeof(buf)); + close(efd); + if (CHECK(bytes <= 0 || bytes >= sizeof(buf), + "read", "bytes %d errno %d\n", bytes, errno)) + goto close_prog; + + /* Open the perf event and attach bpf progrram */ + attr.config = strtol(buf, NULL, 0); + attr.type = PERF_TYPE_TRACEPOINT; + attr.sample_type = PERF_SAMPLE_RAW | PERF_SAMPLE_CALLCHAIN; + attr.sample_period = 1; + attr.wakeup_events = 1; + pmu_fd = syscall(__NR_perf_event_open, &attr, -1 /* pid */, + 0 /* cpu 0 */, -1 /* group id */, + 0 /* flags */); + if (CHECK(pmu_fd < 0, "perf_event_open", "err %d errno %d\n", + pmu_fd, errno)) + goto close_prog; + + err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0); + if (CHECK(err, "perf_event_ioc_enable", "err %d errno %d\n", + err, errno)) + goto close_pmu; + + err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd); + if (CHECK(err, "perf_event_ioc_set_bpf", "err %d errno %d\n", + err, errno)) + goto disable_pmu; + + /* find map fds */ + control_map_fd = bpf_find_map(__func__, obj, "control_map"); + if (CHECK(control_map_fd < 0, "bpf_find_map control_map", + "err %d errno %d\n", err, errno)) + goto disable_pmu; + + stackid_hmap_fd = bpf_find_map(__func__, obj, "stackid_hmap"); + if (CHECK(stackid_hmap_fd < 0, "bpf_find_map stackid_hmap", + "err %d errno %d\n", err, errno)) + goto disable_pmu; + + stackmap_fd = bpf_find_map(__func__, obj, "stackmap"); + if (CHECK(stackmap_fd < 0, "bpf_find_map stackmap", "err %d errno %d\n", + err, errno)) + goto disable_pmu; + + assert(system("dd if=/dev/urandom of=/dev/zero count=4 2> /dev/null") + == 0); + assert(system("./urandom_read if=/dev/urandom of=/dev/zero count=4 2> /dev/null") == 0); + /* disable stack trace collection */ + key = 0; + val = 1; + bpf_map_update_elem(control_map_fd, &key, &val, 0); + + /* for every element in stackid_hmap, we can find a corresponding one + * in stackmap, and vise versa. + */ + err = compare_map_keys(stackid_hmap_fd, stackmap_fd); + if (CHECK(err, "compare_map_keys stackid_hmap vs. stackmap", + "err %d errno %d\n", err, errno)) + goto disable_pmu; + + err = compare_map_keys(stackmap_fd, stackid_hmap_fd); + if (CHECK(err, "compare_map_keys stackmap vs. stackid_hmap", + "err %d errno %d\n", err, errno)) + goto disable_pmu; + + err = extract_build_id(buf, 256); + + if (CHECK(err, "get build_id with readelf", + "err %d errno %d\n", err, errno)) + goto disable_pmu; + + err = bpf_map_get_next_key(stackmap_fd, NULL, &key); + if (CHECK(err, "get_next_key from stackmap", + "err %d, errno %d\n", err, errno)) + goto disable_pmu; + + do { + char build_id[64]; + + err = bpf_map_lookup_elem(stackmap_fd, &key, id_offs); + if (CHECK(err, "lookup_elem from stackmap", + "err %d, errno %d\n", err, errno)) + goto disable_pmu; + for (i = 0; i < PERF_MAX_STACK_DEPTH; ++i) + if (id_offs[i].status == BPF_STACK_BUILD_ID_VALID && + id_offs[i].offset != 0) { + for (j = 0; j < 20; ++j) + sprintf(build_id + 2 * j, "%02x", + id_offs[i].build_id[j] & 0xff); + if (strstr(buf, build_id) != NULL) + build_id_matches = 1; + } + previous_key = key; + } while (bpf_map_get_next_key(stackmap_fd, &previous_key, &key) == 0); + + CHECK(build_id_matches < 1, "build id match", + "Didn't find expected build ID from the map"); + +disable_pmu: + ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); + +close_pmu: + close(pmu_fd); + +close_prog: + bpf_object__close(obj); + +out: + return; +} + int main(void) { test_pkt_access(); @@ -976,6 +1137,7 @@ int main(void) test_obj_name(); test_tp_attach_query(); test_stacktrace_map(); + test_stacktrace_build_id(); printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/tools/testing/selftests/bpf/test_stacktrace_build_id.c b/tools/testing/selftests/bpf/test_stacktrace_build_id.c new file mode 100644 index 000000000000..b755bd783ce5 --- /dev/null +++ b/tools/testing/selftests/bpf/test_stacktrace_build_id.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include "bpf_helpers.h" + +#ifndef PERF_MAX_STACK_DEPTH +#define PERF_MAX_STACK_DEPTH 127 +#endif + +struct bpf_map_def SEC("maps") control_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + +struct bpf_map_def SEC("maps") stackid_hmap = { + .type = BPF_MAP_TYPE_HASH, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 10000, +}; + +struct bpf_map_def SEC("maps") stackmap = { + .type = BPF_MAP_TYPE_STACK_TRACE, + .key_size = sizeof(__u32), + .value_size = sizeof(struct bpf_stack_build_id) + * PERF_MAX_STACK_DEPTH, + .max_entries = 128, + .map_flags = BPF_F_STACK_BUILD_ID, +}; + +/* taken from /sys/kernel/debug/tracing/events/random/urandom_read/format */ +struct random_urandom_args { + unsigned long long pad; + int got_bits; + int pool_left; + int input_left; +}; + +SEC("tracepoint/random/urandom_read") +int oncpu(struct random_urandom_args *args) +{ + __u32 key = 0, val = 0, *value_p; + + value_p = bpf_map_lookup_elem(&control_map, &key); + if (value_p && *value_p) + return 0; /* skip if non-zero *value_p */ + + /* The size of stackmap and stackid_hmap should be the same */ + key = bpf_get_stackid(args, &stackmap, BPF_F_USER_STACK); + if ((int)key >= 0) + bpf_map_update_elem(&stackid_hmap, &key, &val, 0); + + return 0; +} + +char _license[] SEC("license") = "GPL"; +__u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */ diff --git a/tools/testing/selftests/bpf/urandom_read.c b/tools/testing/selftests/bpf/urandom_read.c new file mode 100644 index 000000000000..4acfdebf36fa --- /dev/null +++ b/tools/testing/selftests/bpf/urandom_read.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include +#include + +#define BUF_SIZE 256 +int main(void) +{ + int fd = open("/dev/urandom", O_RDONLY); + int i; + char buf[BUF_SIZE]; + + if (fd < 0) + return 1; + for (i = 0; i < 4; ++i) + read(fd, buf, BUF_SIZE); + + close(fd); + return 0; +} -- cgit v1.3-14-g43fede From bb9d812643d8a121df7d614a2b9c60193a92deb0 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Mar 2018 14:13:42 +0100 Subject: arch: remove tile port The Tile architecture port was added by Chris Metcalf in 2010, and maintained until early 2018 when he orphaned it due to his departure from Mellanox, and nobody else stepped up to maintain it. The product line is still around in the form of the BlueField SoC, but no longer uses the Tile architecture. There are also still products for sale with Tile-GX SoCs, notably the Mikrotik CCR router family. The products all use old (linux-3.3) kernels with lots of patches and won't be upgraded by their manufacturers. There have been efforts to port both OpenWRT and Debian to these, but both projects have stalled and are very unlikely to be continued in the future. Given that we are reasonably sure that nobody is still using the port with an upstream kernel any more, it seems better to remove it now while the port is in a good shape than to let it bitrot for a few years first. Cc: Chris Metcalf Cc: John Paul Adrian Glaubitz Link: http://www.mellanox.com/page/npu_multicore_overview Link: https://jenkins.debian.net/view/rebootstrap/job/rebootstrap_tilegx_gcc7/ Signed-off-by: Arnd Bergmann --- Documentation/ioctl/ioctl-number.txt | 1 - MAINTAINERS | 13 - Makefile | 8 - arch/tile/Kbuild | 3 - arch/tile/Kconfig | 481 ---- arch/tile/Kconfig.debug | 26 - arch/tile/Makefile | 77 - arch/tile/configs/tilegx_defconfig | 411 ---- arch/tile/configs/tilepro_defconfig | 524 ----- arch/tile/gxio/Kconfig | 34 - arch/tile/gxio/Makefile | 11 - arch/tile/gxio/dma_queue.c | 176 -- arch/tile/gxio/iorpc_globals.c | 89 - arch/tile/gxio/iorpc_mpipe.c | 593 ----- arch/tile/gxio/iorpc_mpipe_info.c | 102 - arch/tile/gxio/iorpc_trio.c | 350 --- arch/tile/gxio/iorpc_uart.c | 77 - arch/tile/gxio/iorpc_usb_host.c | 99 - arch/tile/gxio/kiorpc.c | 61 - arch/tile/gxio/mpipe.c | 584 ----- arch/tile/gxio/trio.c | 49 - arch/tile/gxio/uart.c | 87 - arch/tile/gxio/usb_host.c | 91 - arch/tile/include/arch/mpipe.h | 371 --- arch/tile/include/arch/mpipe_constants.h | 42 - arch/tile/include/arch/mpipe_def.h | 39 - arch/tile/include/arch/mpipe_shm.h | 521 ----- arch/tile/include/arch/mpipe_shm_def.h | 23 - arch/tile/include/arch/spr_def.h | 109 - arch/tile/include/arch/trio.h | 111 - arch/tile/include/arch/trio_constants.h | 36 - arch/tile/include/arch/trio_def.h | 41 - arch/tile/include/arch/trio_pcie_intfc.h | 229 -- arch/tile/include/arch/trio_pcie_intfc_def.h | 32 - arch/tile/include/arch/trio_pcie_rc.h | 156 -- arch/tile/include/arch/trio_pcie_rc_def.h | 24 - arch/tile/include/arch/trio_shm.h | 125 - arch/tile/include/arch/trio_shm_def.h | 19 - arch/tile/include/arch/uart.h | 300 --- arch/tile/include/arch/uart_def.h | 120 - arch/tile/include/arch/usb_host.h | 26 - arch/tile/include/arch/usb_host_def.h | 19 - arch/tile/include/asm/Kbuild | 18 - arch/tile/include/asm/asm-offsets.h | 1 - arch/tile/include/asm/atomic.h | 210 -- arch/tile/include/asm/atomic_32.h | 297 --- arch/tile/include/asm/atomic_64.h | 200 -- arch/tile/include/asm/backtrace.h | 162 -- arch/tile/include/asm/barrier.h | 100 - arch/tile/include/asm/bitops.h | 94 - arch/tile/include/asm/bitops_32.h | 126 - arch/tile/include/asm/bitops_64.h | 95 - arch/tile/include/asm/cache.h | 64 - arch/tile/include/asm/cacheflush.h | 160 -- arch/tile/include/asm/checksum.h | 42 - arch/tile/include/asm/cmpxchg.h | 132 -- arch/tile/include/asm/compat.h | 233 -- arch/tile/include/asm/current.h | 31 - arch/tile/include/asm/delay.h | 34 - arch/tile/include/asm/device.h | 33 - arch/tile/include/asm/div64.h | 17 - arch/tile/include/asm/dma-mapping.h | 50 - arch/tile/include/asm/dma.h | 25 - arch/tile/include/asm/elf.h | 182 -- arch/tile/include/asm/fixmap.h | 87 - arch/tile/include/asm/ftrace.h | 42 - arch/tile/include/asm/futex.h | 166 -- arch/tile/include/asm/hardirq.h | 45 - arch/tile/include/asm/hardwall.h | 30 - arch/tile/include/asm/highmem.h | 71 - arch/tile/include/asm/homecache.h | 123 - arch/tile/include/asm/hugetlb.h | 122 - arch/tile/include/asm/hv_driver.h | 60 - arch/tile/include/asm/ide.h | 25 - arch/tile/include/asm/insn.h | 59 - arch/tile/include/asm/io.h | 509 ---- arch/tile/include/asm/irq.h | 87 - arch/tile/include/asm/irq_work.h | 15 - arch/tile/include/asm/irqflags.h | 311 --- arch/tile/include/asm/jump_label.h | 58 - arch/tile/include/asm/kdebug.h | 28 - arch/tile/include/asm/kexec.h | 65 - arch/tile/include/asm/kgdb.h | 71 - arch/tile/include/asm/kmap_types.h | 28 - arch/tile/include/asm/kprobes.h | 83 - arch/tile/include/asm/linkage.h | 51 - arch/tile/include/asm/mmu.h | 32 - arch/tile/include/asm/mmu_context.h | 137 -- arch/tile/include/asm/mmzone.h | 70 - arch/tile/include/asm/module.h | 40 - arch/tile/include/asm/page.h | 345 --- arch/tile/include/asm/pci.h | 229 -- arch/tile/include/asm/percpu.h | 52 - arch/tile/include/asm/perf_event.h | 22 - arch/tile/include/asm/pgalloc.h | 164 -- arch/tile/include/asm/pgtable.h | 518 ----- arch/tile/include/asm/pgtable_32.h | 122 - arch/tile/include/asm/pgtable_64.h | 172 -- arch/tile/include/asm/pmc.h | 64 - arch/tile/include/asm/processor.h | 368 --- arch/tile/include/asm/ptrace.h | 97 - arch/tile/include/asm/sections.h | 44 - arch/tile/include/asm/setup.h | 57 - arch/tile/include/asm/sigframe.h | 33 - arch/tile/include/asm/signal.h | 29 - arch/tile/include/asm/smp.h | 139 -- arch/tile/include/asm/spinlock.h | 24 - arch/tile/include/asm/spinlock_32.h | 109 - arch/tile/include/asm/spinlock_64.h | 138 -- arch/tile/include/asm/spinlock_types.h | 60 - arch/tile/include/asm/stack.h | 73 - arch/tile/include/asm/string.h | 34 - arch/tile/include/asm/switch_to.h | 77 - arch/tile/include/asm/syscall.h | 111 - arch/tile/include/asm/syscalls.h | 70 - arch/tile/include/asm/thread_info.h | 167 -- arch/tile/include/asm/tile-desc.h | 19 - arch/tile/include/asm/tile-desc_32.h | 553 ----- arch/tile/include/asm/tile-desc_64.h | 483 ---- arch/tile/include/asm/timex.h | 52 - arch/tile/include/asm/tlb.h | 25 - arch/tile/include/asm/tlbflush.h | 123 - arch/tile/include/asm/topology.h | 52 - arch/tile/include/asm/traps.h | 93 - arch/tile/include/asm/uaccess.h | 411 ---- arch/tile/include/asm/unaligned.h | 43 - arch/tile/include/asm/unistd.h | 20 - arch/tile/include/asm/user.h | 21 - arch/tile/include/asm/vdso.h | 55 - arch/tile/include/asm/vga.h | 39 - arch/tile/include/asm/word-at-a-time.h | 43 - arch/tile/include/gxio/common.h | 40 - arch/tile/include/gxio/dma_queue.h | 161 -- arch/tile/include/gxio/iorpc_globals.h | 38 - arch/tile/include/gxio/iorpc_mpipe.h | 144 -- arch/tile/include/gxio/iorpc_mpipe_info.h | 50 - arch/tile/include/gxio/iorpc_trio.h | 104 - arch/tile/include/gxio/iorpc_uart.h | 40 - arch/tile/include/gxio/iorpc_usb_host.h | 46 - arch/tile/include/gxio/kiorpc.h | 29 - arch/tile/include/gxio/mpipe.h | 1871 --------------- arch/tile/include/gxio/trio.h | 298 --- arch/tile/include/gxio/uart.h | 105 - arch/tile/include/gxio/usb_host.h | 87 - arch/tile/include/hv/drv_mpipe_intf.h | 605 ----- arch/tile/include/hv/drv_mshim_intf.h | 50 - arch/tile/include/hv/drv_pcie_rc_intf.h | 38 - arch/tile/include/hv/drv_srom_intf.h | 41 - arch/tile/include/hv/drv_trio_intf.h | 199 -- arch/tile/include/hv/drv_uart_intf.h | 33 - arch/tile/include/hv/drv_usb_host_intf.h | 39 - arch/tile/include/hv/drv_xgbe_impl.h | 300 --- arch/tile/include/hv/drv_xgbe_intf.h | 615 ----- arch/tile/include/hv/hypervisor.h | 2656 --------------------- arch/tile/include/hv/iorpc.h | 714 ------ arch/tile/include/hv/netio_errors.h | 122 - arch/tile/include/hv/netio_intf.h | 2975 ------------------------ arch/tile/include/hv/syscall_public.h | 42 - arch/tile/include/uapi/arch/abi.h | 101 - arch/tile/include/uapi/arch/chip.h | 22 - arch/tile/include/uapi/arch/chip_tilegx.h | 259 --- arch/tile/include/uapi/arch/chip_tilepro.h | 259 --- arch/tile/include/uapi/arch/icache.h | 94 - arch/tile/include/uapi/arch/interrupts.h | 20 - arch/tile/include/uapi/arch/interrupts_32.h | 310 --- arch/tile/include/uapi/arch/interrupts_64.h | 279 --- arch/tile/include/uapi/arch/intreg.h | 71 - arch/tile/include/uapi/arch/opcode.h | 22 - arch/tile/include/uapi/arch/opcode_tilegx.h | 1407 ----------- arch/tile/include/uapi/arch/opcode_tilepro.h | 1473 ------------ arch/tile/include/uapi/arch/sim.h | 644 ----- arch/tile/include/uapi/arch/sim_def.h | 506 ---- arch/tile/include/uapi/arch/spr_def.h | 27 - arch/tile/include/uapi/arch/spr_def_32.h | 256 -- arch/tile/include/uapi/arch/spr_def_64.h | 217 -- arch/tile/include/uapi/asm/Kbuild | 24 - arch/tile/include/uapi/asm/auxvec.h | 24 - arch/tile/include/uapi/asm/bitsperlong.h | 27 - arch/tile/include/uapi/asm/byteorder.h | 20 - arch/tile/include/uapi/asm/cachectl.h | 43 - arch/tile/include/uapi/asm/hardwall.h | 52 - arch/tile/include/uapi/asm/kvm_para.h | 2 - arch/tile/include/uapi/asm/mman.h | 43 - arch/tile/include/uapi/asm/ptrace.h | 99 - arch/tile/include/uapi/asm/setup.h | 22 - arch/tile/include/uapi/asm/sigcontext.h | 44 - arch/tile/include/uapi/asm/siginfo.h | 27 - arch/tile/include/uapi/asm/signal.h | 28 - arch/tile/include/uapi/asm/stat.h | 5 - arch/tile/include/uapi/asm/swab.h | 24 - arch/tile/include/uapi/asm/unistd.h | 38 - arch/tile/kernel/Makefile | 38 - arch/tile/kernel/asm-offsets.c | 84 - arch/tile/kernel/backtrace.c | 683 ------ arch/tile/kernel/compat.c | 117 - arch/tile/kernel/compat_signal.c | 172 -- arch/tile/kernel/early_printk.c | 75 - arch/tile/kernel/entry.S | 64 - arch/tile/kernel/ftrace.c | 239 -- arch/tile/kernel/hardwall.c | 1096 --------- arch/tile/kernel/head_32.S | 183 -- arch/tile/kernel/head_64.S | 279 --- arch/tile/kernel/hvglue.S | 76 - arch/tile/kernel/hvglue_trace.c | 270 --- arch/tile/kernel/intvec_32.S | 1906 --------------- arch/tile/kernel/intvec_64.S | 1564 ------------- arch/tile/kernel/irq.c | 280 --- arch/tile/kernel/jump_label.c | 62 - arch/tile/kernel/kgdb.c | 497 ---- arch/tile/kernel/kprobes.c | 527 ----- arch/tile/kernel/machine_kexec.c | 298 --- arch/tile/kernel/mcount_64.S | 211 -- arch/tile/kernel/messaging.c | 115 - arch/tile/kernel/module.c | 231 -- arch/tile/kernel/pci-dma.c | 607 ----- arch/tile/kernel/pci.c | 592 ----- arch/tile/kernel/pci_gx.c | 1592 ------------- arch/tile/kernel/perf_event.c | 1005 -------- arch/tile/kernel/pmc.c | 118 - arch/tile/kernel/proc.c | 160 -- arch/tile/kernel/process.c | 659 ------ arch/tile/kernel/ptrace.c | 316 --- arch/tile/kernel/reboot.c | 51 - arch/tile/kernel/regs_32.S | 145 -- arch/tile/kernel/regs_64.S | 145 -- arch/tile/kernel/relocate_kernel_32.S | 269 --- arch/tile/kernel/relocate_kernel_64.S | 263 --- arch/tile/kernel/setup.c | 1743 -------------- arch/tile/kernel/signal.c | 411 ---- arch/tile/kernel/single_step.c | 786 ------- arch/tile/kernel/smp.c | 287 --- arch/tile/kernel/smpboot.c | 269 --- arch/tile/kernel/stack.c | 539 ----- arch/tile/kernel/sys.c | 130 -- arch/tile/kernel/sysfs.c | 266 --- arch/tile/kernel/tile-desc_32.c | 2605 --------------------- arch/tile/kernel/tile-desc_64.c | 2218 ------------------ arch/tile/kernel/time.c | 306 --- arch/tile/kernel/tlb.c | 104 - arch/tile/kernel/traps.c | 421 ---- arch/tile/kernel/unaligned.c | 1603 ------------- arch/tile/kernel/usb.c | 71 - arch/tile/kernel/vdso.c | 197 -- arch/tile/kernel/vdso/Makefile | 117 - arch/tile/kernel/vdso/vdso.S | 28 - arch/tile/kernel/vdso/vdso.lds.S | 89 - arch/tile/kernel/vdso/vdso32.S | 28 - arch/tile/kernel/vdso/vgettimeofday.c | 198 -- arch/tile/kernel/vdso/vrt_sigreturn.S | 30 - arch/tile/kernel/vmlinux.lds.S | 105 - arch/tile/kvm/Kconfig | 39 - arch/tile/lib/Makefile | 19 - arch/tile/lib/atomic_32.c | 206 -- arch/tile/lib/atomic_asm_32.S | 205 -- arch/tile/lib/cacheflush.c | 167 -- arch/tile/lib/checksum.c | 89 - arch/tile/lib/cpumask.c | 54 - arch/tile/lib/delay.c | 45 - arch/tile/lib/exports.c | 94 - arch/tile/lib/memchr_32.c | 71 - arch/tile/lib/memchr_64.c | 69 - arch/tile/lib/memcpy_32.S | 544 ----- arch/tile/lib/memcpy_64.c | 367 --- arch/tile/lib/memcpy_user_64.c | 85 - arch/tile/lib/memmove.c | 63 - arch/tile/lib/memset_32.c | 143 -- arch/tile/lib/memset_64.c | 142 -- arch/tile/lib/spinlock_32.c | 251 -- arch/tile/lib/spinlock_64.c | 97 - arch/tile/lib/spinlock_common.h | 64 - arch/tile/lib/strchr_32.c | 64 - arch/tile/lib/strchr_64.c | 62 - arch/tile/lib/string-endian.h | 44 - arch/tile/lib/strlen_32.c | 36 - arch/tile/lib/strlen_64.c | 35 - arch/tile/lib/strnlen_32.c | 47 - arch/tile/lib/strnlen_64.c | 48 - arch/tile/lib/uaccess.c | 24 - arch/tile/lib/usercopy_32.S | 89 - arch/tile/lib/usercopy_64.S | 89 - arch/tile/mm/Makefile | 9 - arch/tile/mm/elf.c | 165 -- arch/tile/mm/extable.c | 30 - arch/tile/mm/fault.c | 924 -------- arch/tile/mm/highmem.c | 277 --- arch/tile/mm/homecache.c | 428 ---- arch/tile/mm/hugetlbpage.c | 348 --- arch/tile/mm/init.c | 956 -------- arch/tile/mm/migrate.h | 56 - arch/tile/mm/migrate_32.S | 192 -- arch/tile/mm/migrate_64.S | 167 -- arch/tile/mm/mmap.c | 93 - arch/tile/mm/pgtable.c | 550 ----- drivers/pci/quirks.c | 19 - samples/kprobes/kprobe_example.c | 8 - tools/arch/tile/include/asm/barrier.h | 16 - tools/arch/tile/include/uapi/asm/bitsperlong.h | 27 - tools/arch/tile/include/uapi/asm/mman.h | 16 - tools/scripts/Makefile.arch | 11 +- tools/testing/ktest/ktest.pl | 2 - 300 files changed, 1 insertion(+), 69477 deletions(-) delete mode 100644 arch/tile/Kbuild delete mode 100644 arch/tile/Kconfig delete mode 100644 arch/tile/Kconfig.debug delete mode 100644 arch/tile/Makefile delete mode 100644 arch/tile/configs/tilegx_defconfig delete mode 100644 arch/tile/configs/tilepro_defconfig delete mode 100644 arch/tile/gxio/Kconfig delete mode 100644 arch/tile/gxio/Makefile delete mode 100644 arch/tile/gxio/dma_queue.c delete mode 100644 arch/tile/gxio/iorpc_globals.c delete mode 100644 arch/tile/gxio/iorpc_mpipe.c delete mode 100644 arch/tile/gxio/iorpc_mpipe_info.c delete mode 100644 arch/tile/gxio/iorpc_trio.c delete mode 100644 arch/tile/gxio/iorpc_uart.c delete mode 100644 arch/tile/gxio/iorpc_usb_host.c delete mode 100644 arch/tile/gxio/kiorpc.c delete mode 100644 arch/tile/gxio/mpipe.c delete mode 100644 arch/tile/gxio/trio.c delete mode 100644 arch/tile/gxio/uart.c delete mode 100644 arch/tile/gxio/usb_host.c delete mode 100644 arch/tile/include/arch/mpipe.h delete mode 100644 arch/tile/include/arch/mpipe_constants.h delete mode 100644 arch/tile/include/arch/mpipe_def.h delete mode 100644 arch/tile/include/arch/mpipe_shm.h delete mode 100644 arch/tile/include/arch/mpipe_shm_def.h delete mode 100644 arch/tile/include/arch/spr_def.h delete mode 100644 arch/tile/include/arch/trio.h delete mode 100644 arch/tile/include/arch/trio_constants.h delete mode 100644 arch/tile/include/arch/trio_def.h delete mode 100644 arch/tile/include/arch/trio_pcie_intfc.h delete mode 100644 arch/tile/include/arch/trio_pcie_intfc_def.h delete mode 100644 arch/tile/include/arch/trio_pcie_rc.h delete mode 100644 arch/tile/include/arch/trio_pcie_rc_def.h delete mode 100644 arch/tile/include/arch/trio_shm.h delete mode 100644 arch/tile/include/arch/trio_shm_def.h delete mode 100644 arch/tile/include/arch/uart.h delete mode 100644 arch/tile/include/arch/uart_def.h delete mode 100644 arch/tile/include/arch/usb_host.h delete mode 100644 arch/tile/include/arch/usb_host_def.h delete mode 100644 arch/tile/include/asm/Kbuild delete mode 100644 arch/tile/include/asm/asm-offsets.h delete mode 100644 arch/tile/include/asm/atomic.h delete mode 100644 arch/tile/include/asm/atomic_32.h delete mode 100644 arch/tile/include/asm/atomic_64.h delete mode 100644 arch/tile/include/asm/backtrace.h delete mode 100644 arch/tile/include/asm/barrier.h delete mode 100644 arch/tile/include/asm/bitops.h delete mode 100644 arch/tile/include/asm/bitops_32.h delete mode 100644 arch/tile/include/asm/bitops_64.h delete mode 100644 arch/tile/include/asm/cache.h delete mode 100644 arch/tile/include/asm/cacheflush.h delete mode 100644 arch/tile/include/asm/checksum.h delete mode 100644 arch/tile/include/asm/cmpxchg.h delete mode 100644 arch/tile/include/asm/compat.h delete mode 100644 arch/tile/include/asm/current.h delete mode 100644 arch/tile/include/asm/delay.h delete mode 100644 arch/tile/include/asm/device.h delete mode 100644 arch/tile/include/asm/div64.h delete mode 100644 arch/tile/include/asm/dma-mapping.h delete mode 100644 arch/tile/include/asm/dma.h delete mode 100644 arch/tile/include/asm/elf.h delete mode 100644 arch/tile/include/asm/fixmap.h delete mode 100644 arch/tile/include/asm/ftrace.h delete mode 100644 arch/tile/include/asm/futex.h delete mode 100644 arch/tile/include/asm/hardirq.h delete mode 100644 arch/tile/include/asm/hardwall.h delete mode 100644 arch/tile/include/asm/highmem.h delete mode 100644 arch/tile/include/asm/homecache.h delete mode 100644 arch/tile/include/asm/hugetlb.h delete mode 100644 arch/tile/include/asm/hv_driver.h delete mode 100644 arch/tile/include/asm/ide.h delete mode 100644 arch/tile/include/asm/insn.h delete mode 100644 arch/tile/include/asm/io.h delete mode 100644 arch/tile/include/asm/irq.h delete mode 100644 arch/tile/include/asm/irq_work.h delete mode 100644 arch/tile/include/asm/irqflags.h delete mode 100644 arch/tile/include/asm/jump_label.h delete mode 100644 arch/tile/include/asm/kdebug.h delete mode 100644 arch/tile/include/asm/kexec.h delete mode 100644 arch/tile/include/asm/kgdb.h delete mode 100644 arch/tile/include/asm/kmap_types.h delete mode 100644 arch/tile/include/asm/kprobes.h delete mode 100644 arch/tile/include/asm/linkage.h delete mode 100644 arch/tile/include/asm/mmu.h delete mode 100644 arch/tile/include/asm/mmu_context.h delete mode 100644 arch/tile/include/asm/mmzone.h delete mode 100644 arch/tile/include/asm/module.h delete mode 100644 arch/tile/include/asm/page.h delete mode 100644 arch/tile/include/asm/pci.h delete mode 100644 arch/tile/include/asm/percpu.h delete mode 100644 arch/tile/include/asm/perf_event.h delete mode 100644 arch/tile/include/asm/pgalloc.h delete mode 100644 arch/tile/include/asm/pgtable.h delete mode 100644 arch/tile/include/asm/pgtable_32.h delete mode 100644 arch/tile/include/asm/pgtable_64.h delete mode 100644 arch/tile/include/asm/pmc.h delete mode 100644 arch/tile/include/asm/processor.h delete mode 100644 arch/tile/include/asm/ptrace.h delete mode 100644 arch/tile/include/asm/sections.h delete mode 100644 arch/tile/include/asm/setup.h delete mode 100644 arch/tile/include/asm/sigframe.h delete mode 100644 arch/tile/include/asm/signal.h delete mode 100644 arch/tile/include/asm/smp.h delete mode 100644 arch/tile/include/asm/spinlock.h delete mode 100644 arch/tile/include/asm/spinlock_32.h delete mode 100644 arch/tile/include/asm/spinlock_64.h delete mode 100644 arch/tile/include/asm/spinlock_types.h delete mode 100644 arch/tile/include/asm/stack.h delete mode 100644 arch/tile/include/asm/string.h delete mode 100644 arch/tile/include/asm/switch_to.h delete mode 100644 arch/tile/include/asm/syscall.h delete mode 100644 arch/tile/include/asm/syscalls.h delete mode 100644 arch/tile/include/asm/thread_info.h delete mode 100644 arch/tile/include/asm/tile-desc.h delete mode 100644 arch/tile/include/asm/tile-desc_32.h delete mode 100644 arch/tile/include/asm/tile-desc_64.h delete mode 100644 arch/tile/include/asm/timex.h delete mode 100644 arch/tile/include/asm/tlb.h delete mode 100644 arch/tile/include/asm/tlbflush.h delete mode 100644 arch/tile/include/asm/topology.h delete mode 100644 arch/tile/include/asm/traps.h delete mode 100644 arch/tile/include/asm/uaccess.h delete mode 100644 arch/tile/include/asm/unaligned.h delete mode 100644 arch/tile/include/asm/unistd.h delete mode 100644 arch/tile/include/asm/user.h delete mode 100644 arch/tile/include/asm/vdso.h delete mode 100644 arch/tile/include/asm/vga.h delete mode 100644 arch/tile/include/asm/word-at-a-time.h delete mode 100644 arch/tile/include/gxio/common.h delete mode 100644 arch/tile/include/gxio/dma_queue.h delete mode 100644 arch/tile/include/gxio/iorpc_globals.h delete mode 100644 arch/tile/include/gxio/iorpc_mpipe.h delete mode 100644 arch/tile/include/gxio/iorpc_mpipe_info.h delete mode 100644 arch/tile/include/gxio/iorpc_trio.h delete mode 100644 arch/tile/include/gxio/iorpc_uart.h delete mode 100644 arch/tile/include/gxio/iorpc_usb_host.h delete mode 100644 arch/tile/include/gxio/kiorpc.h delete mode 100644 arch/tile/include/gxio/mpipe.h delete mode 100644 arch/tile/include/gxio/trio.h delete mode 100644 arch/tile/include/gxio/uart.h delete mode 100644 arch/tile/include/gxio/usb_host.h delete mode 100644 arch/tile/include/hv/drv_mpipe_intf.h delete mode 100644 arch/tile/include/hv/drv_mshim_intf.h delete mode 100644 arch/tile/include/hv/drv_pcie_rc_intf.h delete mode 100644 arch/tile/include/hv/drv_srom_intf.h delete mode 100644 arch/tile/include/hv/drv_trio_intf.h delete mode 100644 arch/tile/include/hv/drv_uart_intf.h delete mode 100644 arch/tile/include/hv/drv_usb_host_intf.h delete mode 100644 arch/tile/include/hv/drv_xgbe_impl.h delete mode 100644 arch/tile/include/hv/drv_xgbe_intf.h delete mode 100644 arch/tile/include/hv/hypervisor.h delete mode 100644 arch/tile/include/hv/iorpc.h delete mode 100644 arch/tile/include/hv/netio_errors.h delete mode 100644 arch/tile/include/hv/netio_intf.h delete mode 100644 arch/tile/include/hv/syscall_public.h delete mode 100644 arch/tile/include/uapi/arch/abi.h delete mode 100644 arch/tile/include/uapi/arch/chip.h delete mode 100644 arch/tile/include/uapi/arch/chip_tilegx.h delete mode 100644 arch/tile/include/uapi/arch/chip_tilepro.h delete mode 100644 arch/tile/include/uapi/arch/icache.h delete mode 100644 arch/tile/include/uapi/arch/interrupts.h delete mode 100644 arch/tile/include/uapi/arch/interrupts_32.h delete mode 100644 arch/tile/include/uapi/arch/interrupts_64.h delete mode 100644 arch/tile/include/uapi/arch/intreg.h delete mode 100644 arch/tile/include/uapi/arch/opcode.h delete mode 100644 arch/tile/include/uapi/arch/opcode_tilegx.h delete mode 100644 arch/tile/include/uapi/arch/opcode_tilepro.h delete mode 100644 arch/tile/include/uapi/arch/sim.h delete mode 100644 arch/tile/include/uapi/arch/sim_def.h delete mode 100644 arch/tile/include/uapi/arch/spr_def.h delete mode 100644 arch/tile/include/uapi/arch/spr_def_32.h delete mode 100644 arch/tile/include/uapi/arch/spr_def_64.h delete mode 100644 arch/tile/include/uapi/asm/Kbuild delete mode 100644 arch/tile/include/uapi/asm/auxvec.h delete mode 100644 arch/tile/include/uapi/asm/bitsperlong.h delete mode 100644 arch/tile/include/uapi/asm/byteorder.h delete mode 100644 arch/tile/include/uapi/asm/cachectl.h delete mode 100644 arch/tile/include/uapi/asm/hardwall.h delete mode 100644 arch/tile/include/uapi/asm/kvm_para.h delete mode 100644 arch/tile/include/uapi/asm/mman.h delete mode 100644 arch/tile/include/uapi/asm/ptrace.h delete mode 100644 arch/tile/include/uapi/asm/setup.h delete mode 100644 arch/tile/include/uapi/asm/sigcontext.h delete mode 100644 arch/tile/include/uapi/asm/siginfo.h delete mode 100644 arch/tile/include/uapi/asm/signal.h delete mode 100644 arch/tile/include/uapi/asm/stat.h delete mode 100644 arch/tile/include/uapi/asm/swab.h delete mode 100644 arch/tile/include/uapi/asm/unistd.h delete mode 100644 arch/tile/kernel/Makefile delete mode 100644 arch/tile/kernel/asm-offsets.c delete mode 100644 arch/tile/kernel/backtrace.c delete mode 100644 arch/tile/kernel/compat.c delete mode 100644 arch/tile/kernel/compat_signal.c delete mode 100644 arch/tile/kernel/early_printk.c delete mode 100644 arch/tile/kernel/entry.S delete mode 100644 arch/tile/kernel/ftrace.c delete mode 100644 arch/tile/kernel/hardwall.c delete mode 100644 arch/tile/kernel/head_32.S delete mode 100644 arch/tile/kernel/head_64.S delete mode 100644 arch/tile/kernel/hvglue.S delete mode 100644 arch/tile/kernel/hvglue_trace.c delete mode 100644 arch/tile/kernel/intvec_32.S delete mode 100644 arch/tile/kernel/intvec_64.S delete mode 100644 arch/tile/kernel/irq.c delete mode 100644 arch/tile/kernel/jump_label.c delete mode 100644 arch/tile/kernel/kgdb.c delete mode 100644 arch/tile/kernel/kprobes.c delete mode 100644 arch/tile/kernel/machine_kexec.c delete mode 100644 arch/tile/kernel/mcount_64.S delete mode 100644 arch/tile/kernel/messaging.c delete mode 100644 arch/tile/kernel/module.c delete mode 100644 arch/tile/kernel/pci-dma.c delete mode 100644 arch/tile/kernel/pci.c delete mode 100644 arch/tile/kernel/pci_gx.c delete mode 100644 arch/tile/kernel/perf_event.c delete mode 100644 arch/tile/kernel/pmc.c delete mode 100644 arch/tile/kernel/proc.c delete mode 100644 arch/tile/kernel/process.c delete mode 100644 arch/tile/kernel/ptrace.c delete mode 100644 arch/tile/kernel/reboot.c delete mode 100644 arch/tile/kernel/regs_32.S delete mode 100644 arch/tile/kernel/regs_64.S delete mode 100644 arch/tile/kernel/relocate_kernel_32.S delete mode 100644 arch/tile/kernel/relocate_kernel_64.S delete mode 100644 arch/tile/kernel/setup.c delete mode 100644 arch/tile/kernel/signal.c delete mode 100644 arch/tile/kernel/single_step.c delete mode 100644 arch/tile/kernel/smp.c delete mode 100644 arch/tile/kernel/smpboot.c delete mode 100644 arch/tile/kernel/stack.c delete mode 100644 arch/tile/kernel/sys.c delete mode 100644 arch/tile/kernel/sysfs.c delete mode 100644 arch/tile/kernel/tile-desc_32.c delete mode 100644 arch/tile/kernel/tile-desc_64.c delete mode 100644 arch/tile/kernel/time.c delete mode 100644 arch/tile/kernel/tlb.c delete mode 100644 arch/tile/kernel/traps.c delete mode 100644 arch/tile/kernel/unaligned.c delete mode 100644 arch/tile/kernel/usb.c delete mode 100644 arch/tile/kernel/vdso.c delete mode 100644 arch/tile/kernel/vdso/Makefile delete mode 100644 arch/tile/kernel/vdso/vdso.S delete mode 100644 arch/tile/kernel/vdso/vdso.lds.S delete mode 100644 arch/tile/kernel/vdso/vdso32.S delete mode 100644 arch/tile/kernel/vdso/vgettimeofday.c delete mode 100644 arch/tile/kernel/vdso/vrt_sigreturn.S delete mode 100644 arch/tile/kernel/vmlinux.lds.S delete mode 100644 arch/tile/kvm/Kconfig delete mode 100644 arch/tile/lib/Makefile delete mode 100644 arch/tile/lib/atomic_32.c delete mode 100644 arch/tile/lib/atomic_asm_32.S delete mode 100644 arch/tile/lib/cacheflush.c delete mode 100644 arch/tile/lib/checksum.c delete mode 100644 arch/tile/lib/cpumask.c delete mode 100644 arch/tile/lib/delay.c delete mode 100644 arch/tile/lib/exports.c delete mode 100644 arch/tile/lib/memchr_32.c delete mode 100644 arch/tile/lib/memchr_64.c delete mode 100644 arch/tile/lib/memcpy_32.S delete mode 100644 arch/tile/lib/memcpy_64.c delete mode 100644 arch/tile/lib/memcpy_user_64.c delete mode 100644 arch/tile/lib/memmove.c delete mode 100644 arch/tile/lib/memset_32.c delete mode 100644 arch/tile/lib/memset_64.c delete mode 100644 arch/tile/lib/spinlock_32.c delete mode 100644 arch/tile/lib/spinlock_64.c delete mode 100644 arch/tile/lib/spinlock_common.h delete mode 100644 arch/tile/lib/strchr_32.c delete mode 100644 arch/tile/lib/strchr_64.c delete mode 100644 arch/tile/lib/string-endian.h delete mode 100644 arch/tile/lib/strlen_32.c delete mode 100644 arch/tile/lib/strlen_64.c delete mode 100644 arch/tile/lib/strnlen_32.c delete mode 100644 arch/tile/lib/strnlen_64.c delete mode 100644 arch/tile/lib/uaccess.c delete mode 100644 arch/tile/lib/usercopy_32.S delete mode 100644 arch/tile/lib/usercopy_64.S delete mode 100644 arch/tile/mm/Makefile delete mode 100644 arch/tile/mm/elf.c delete mode 100644 arch/tile/mm/extable.c delete mode 100644 arch/tile/mm/fault.c delete mode 100644 arch/tile/mm/highmem.c delete mode 100644 arch/tile/mm/homecache.c delete mode 100644 arch/tile/mm/hugetlbpage.c delete mode 100644 arch/tile/mm/init.c delete mode 100644 arch/tile/mm/migrate.h delete mode 100644 arch/tile/mm/migrate_32.S delete mode 100644 arch/tile/mm/migrate_64.S delete mode 100644 arch/tile/mm/mmap.c delete mode 100644 arch/tile/mm/pgtable.c delete mode 100644 tools/arch/tile/include/asm/barrier.h delete mode 100644 tools/arch/tile/include/uapi/asm/bitsperlong.h delete mode 100644 tools/arch/tile/include/uapi/asm/mman.h (limited to 'tools/testing') diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 6501389d55b9..84bb74dcae12 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -305,7 +305,6 @@ Code Seq#(hex) Include File Comments 0xA0 all linux/sdp/sdp.h Industrial Device Project 0xA1 0 linux/vtpm_proxy.h TPM Emulator Proxy Driver -0xA2 00-0F arch/tile/include/asm/hardwall.h 0xA3 80-8F Port ACL in development: 0xA3 90-9F linux/dtlk.h diff --git a/MAINTAINERS b/MAINTAINERS index 9e0c097824f5..ac6083ae4f94 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13840,19 +13840,6 @@ S: Orphan F: drivers/net/wireless/ti/ F: include/linux/wl12xx.h -TILE ARCHITECTURE -W: http://www.mellanox.com/repository/solutions/tile-scm/ -S: Orphan -F: arch/tile/ -F: drivers/char/tile-srom.c -F: drivers/edac/tile_edac.c -F: drivers/net/ethernet/tile/ -F: drivers/rtc/rtc-tile.c -F: drivers/tty/hvc/hvc_tile.c -F: drivers/tty/serial/tilegx.c -F: drivers/usb/host/*-tilegx.c -F: include/linux/usb/tilegx.h - TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER M: John Stultz M: Thomas Gleixner diff --git a/Makefile b/Makefile index c4322dea3ca2..4114da991ae3 100644 --- a/Makefile +++ b/Makefile @@ -339,14 +339,6 @@ ifeq ($(ARCH),sh64) SRCARCH := sh endif -# Additional ARCH settings for tile -ifeq ($(ARCH),tilepro) - SRCARCH := tile -endif -ifeq ($(ARCH),tilegx) - SRCARCH := tile -endif - KCONFIG_CONFIG ?= .config export KCONFIG_CONFIG diff --git a/arch/tile/Kbuild b/arch/tile/Kbuild deleted file mode 100644 index a9b922716092..000000000000 --- a/arch/tile/Kbuild +++ /dev/null @@ -1,3 +0,0 @@ - -obj-y += kernel/ -obj-y += mm/ diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig deleted file mode 100644 index ef9d403cbbe4..000000000000 --- a/arch/tile/Kconfig +++ /dev/null @@ -1,481 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. - -config TILE - def_bool y - select ARCH_HAS_DEVMEM_IS_ALLOWED - select ARCH_HAVE_NMI_SAFE_CMPXCHG - select ARCH_WANT_FRAME_POINTERS - select CC_OPTIMIZE_FOR_SIZE - select EDAC_SUPPORT - select GENERIC_CLOCKEVENTS - select GENERIC_FIND_FIRST_BIT - select GENERIC_IRQ_PROBE - select GENERIC_IRQ_SHOW - select GENERIC_PENDING_IRQ if SMP - select GENERIC_STRNCPY_FROM_USER - select GENERIC_STRNLEN_USER - select HAVE_ARCH_SECCOMP_FILTER - select HAVE_ARCH_TRACEHOOK - select HAVE_CONTEXT_TRACKING - select HAVE_DEBUG_BUGVERBOSE - select HAVE_DEBUG_KMEMLEAK - select HAVE_DEBUG_STACKOVERFLOW - select HAVE_DMA_API_DEBUG - select HAVE_EXIT_THREAD - select HAVE_KVM if !TILEGX - select HAVE_NMI if USE_PMC - select HAVE_PERF_EVENTS - select HAVE_SYSCALL_TRACEPOINTS - select MODULES_USE_ELF_RELA - select SYSCTL_EXCEPTION_TRACE - select SYS_HYPERVISOR - select USER_STACKTRACE_SUPPORT - select USE_PMC if PERF_EVENTS - select VIRT_TO_BUS - -config MMU - def_bool y - -config GENERIC_CSUM - def_bool y - -config HAVE_ARCH_ALLOC_REMAP - def_bool y - -config HAVE_SETUP_PER_CPU_AREA - def_bool y - -config NEED_PER_CPU_PAGE_FIRST_CHUNK - def_bool y - -config SYS_SUPPORTS_HUGETLBFS - def_bool y - -# Support for additional huge page sizes besides HPAGE_SIZE. -# The software support is currently only present in the TILE-Gx -# hypervisor. TILEPro in any case does not support page sizes -# larger than the default HPAGE_SIZE. -config HUGETLB_SUPER_PAGES - depends on HUGETLB_PAGE && TILEGX - def_bool y - -config GENERIC_TIME_VSYSCALL - def_bool y - -# Enable PMC if PERF_EVENTS, OPROFILE, or WATCHPOINTS are enabled. -config USE_PMC - bool - -# FIXME: tilegx can implement a more efficient rwsem. -config RWSEM_GENERIC_SPINLOCK - def_bool y - -# We only support gcc 4.4 and above, so this should work. -config ARCH_SUPPORTS_OPTIMIZED_INLINING - def_bool y - -config ARCH_PHYS_ADDR_T_64BIT - def_bool y - -config ARCH_DMA_ADDR_T_64BIT - def_bool y - -config NEED_DMA_MAP_STATE - def_bool y - -config ARCH_HAS_DMA_SET_COHERENT_MASK - bool - -config LOCKDEP_SUPPORT - def_bool y - -config STACKTRACE_SUPPORT - def_bool y - select STACKTRACE - -# We use discontigmem for now; at some point we may want to switch -# to sparsemem (Tilera bug 7996). -config ARCH_DISCONTIGMEM_ENABLE - def_bool y - -config ARCH_DISCONTIGMEM_DEFAULT - def_bool y - -config TRACE_IRQFLAGS_SUPPORT - def_bool y - -# SMP is required for Tilera Linux. -config SMP - def_bool y - -config HVC_TILE - depends on TTY - select HVC_DRIVER - select HVC_IRQ if TILEGX - def_bool y - -# Building with ARCH=tilegx (or ARCH=tile) implies using the -# 64-bit TILE-Gx toolchain, so force CONFIG_TILEGX on. -config TILEGX - def_bool ARCH != "tilepro" - select ARCH_SUPPORTS_ATOMIC_RMW - select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ - select HAVE_ARCH_JUMP_LABEL - select HAVE_ARCH_KGDB - select HAVE_DYNAMIC_FTRACE - select HAVE_FTRACE_MCOUNT_RECORD - select HAVE_FUNCTION_GRAPH_TRACER - select HAVE_FUNCTION_TRACER - select HAVE_KPROBES - select HAVE_KRETPROBES - select SPARSE_IRQ - -config TILEPRO - def_bool !TILEGX - -config 64BIT - def_bool TILEGX - -config ARCH_DEFCONFIG - string - default "arch/tile/configs/tilepro_defconfig" if !TILEGX - default "arch/tile/configs/tilegx_defconfig" if TILEGX - -config PGTABLE_LEVELS - int - default 3 if 64BIT - default 2 - -source "init/Kconfig" - -source "kernel/Kconfig.freezer" - -menu "Tilera-specific configuration" - -config NR_CPUS - int "Maximum number of tiles (2-255)" - range 2 255 - depends on SMP - default "64" - ---help--- - Building with 64 is the recommended value, but a slightly - smaller kernel memory footprint results from using a smaller - value on chips with fewer tiles. - -choice - prompt "Kernel page size" - default PAGE_SIZE_64KB - help - This lets you select the page size of the kernel. For best - performance on memory-intensive applications, a page size of 64KB - is recommended. For workloads involving many small files, many - connections, etc., it may be better to select 16KB, which uses - memory more efficiently at some cost in TLB performance. - - Note that for TILEPro, you must also rebuild the hypervisor - with a matching page size. - -config PAGE_SIZE_4KB - bool "4KB" if TILEPRO - -config PAGE_SIZE_16KB - bool "16KB" - -config PAGE_SIZE_64KB - bool "64KB" - -endchoice - -source "kernel/Kconfig.hz" - -config KEXEC - bool "kexec system call" - select KEXEC_CORE - ---help--- - kexec is a system call that implements the ability to shutdown your - current kernel, and to start another kernel. It is like a reboot - but it is independent of the system firmware. It is used - to implement the "mboot" Tilera booter. - - The name comes from the similarity to the exec system call. - -config COMPAT - bool "Support 32-bit TILE-Gx binaries in addition to 64-bit" - depends on TILEGX - select COMPAT_BINFMT_ELF - default y - ---help--- - If enabled, the kernel will support running TILE-Gx binaries - that were built with the -m32 option. - -config SECCOMP - bool "Enable seccomp to safely compute untrusted bytecode" - depends on PROC_FS - help - This kernel feature is useful for number crunching applications - that may need to compute untrusted bytecode during their - execution. By using pipes or other transports made available to - the process as file descriptors supporting the read/write - syscalls, it's possible to isolate those applications in - their own address space using seccomp. Once seccomp is - enabled via prctl, it cannot be disabled and the task is only - allowed to execute a few safe syscalls defined by each seccomp - mode. - - If unsure, say N. - -config SYSVIPC_COMPAT - def_bool y - depends on COMPAT && SYSVIPC - -# We do not currently support disabling HIGHMEM on tilepro. -config HIGHMEM - bool # "Support for more than 512 MB of RAM" - default !TILEGX - ---help--- - Linux can use the full amount of RAM in the system by - default. However, the address space of TILE processors is - only 4 Gigabytes large. That means that, if you have a large - amount of physical memory, not all of it can be "permanently - mapped" by the kernel. The physical memory that's not - permanently mapped is called "high memory". - - If you are compiling a kernel which will never run on a - machine with more than 512 MB total physical RAM, answer - "false" here. This will result in the kernel mapping all of - physical memory into the top 1 GB of virtual memory space. - - If unsure, say "true". - -config ZONE_DMA32 - def_bool y - -config IOMMU_HELPER - bool - -config NEED_SG_DMA_LENGTH - bool - -config SWIOTLB - bool - default TILEGX - select DMA_DIRECT_OPS - select IOMMU_HELPER - select NEED_SG_DMA_LENGTH - select ARCH_HAS_DMA_SET_COHERENT_MASK - -# We do not currently support disabling NUMA. -config NUMA - bool # "NUMA Memory Allocation and Scheduler Support" - depends on SMP && DISCONTIGMEM - default y - ---help--- - NUMA memory allocation is required for TILE processors - unless booting with memory striping enabled in the - hypervisor, or with only a single memory controller. - It is recommended that this option always be enabled. - -config NODES_SHIFT - int "Log base 2 of the max number of memory controllers" - default 2 - depends on NEED_MULTIPLE_NODES - ---help--- - By default, 2, i.e. 2^2 == 4 DDR2 controllers. - In a system with more controllers, this value should be raised. - -choice - depends on !TILEGX - prompt "Memory split" if EXPERT - default VMSPLIT_3G - ---help--- - Select the desired split between kernel and user memory. - - If the address range available to the kernel is less than the - physical memory installed, the remaining memory will be available - as "high memory". Accessing high memory is a little more costly - than low memory, as it needs to be mapped into the kernel first. - Note that increasing the kernel address space limits the range - available to user programs, making the address space there - tighter. Selecting anything other than the default 3G/1G split - will also likely make your kernel incompatible with binary-only - kernel modules. - - If you are not absolutely sure what you are doing, leave this - option alone! - - config VMSPLIT_3_75G - bool "3.75G/0.25G user/kernel split (no kernel networking)" - config VMSPLIT_3_5G - bool "3.5G/0.5G user/kernel split" - config VMSPLIT_3G - bool "3G/1G user/kernel split" - config VMSPLIT_2_75G - bool "2.75G/1.25G user/kernel split (for full 1G low memory)" - config VMSPLIT_2_5G - bool "2.5G/1.5G user/kernel split" - config VMSPLIT_2_25G - bool "2.25G/1.75G user/kernel split" - config VMSPLIT_2G - bool "2G/2G user/kernel split" - config VMSPLIT_1G - bool "1G/3G user/kernel split" -endchoice - -config PAGE_OFFSET - hex - depends on !64BIT - default 0xF0000000 if VMSPLIT_3_75G - default 0xE0000000 if VMSPLIT_3_5G - default 0xB0000000 if VMSPLIT_2_75G - default 0xA0000000 if VMSPLIT_2_5G - default 0x90000000 if VMSPLIT_2_25G - default 0x80000000 if VMSPLIT_2G - default 0x40000000 if VMSPLIT_1G - default 0xC0000000 - -source "mm/Kconfig" - -source "kernel/Kconfig.preempt" - -config CMDLINE_BOOL - bool "Built-in kernel command line" - default n - ---help--- - Allow for specifying boot arguments to the kernel at - build time. On some systems (e.g. embedded ones), it is - necessary or convenient to provide some or all of the - kernel boot arguments with the kernel itself (that is, - to not rely on the boot loader to provide them.) - - To compile command line arguments into the kernel, - set this option to 'Y', then fill in the - the boot arguments in CONFIG_CMDLINE. - - Systems with fully functional boot loaders (e.g. mboot, or - if booting over PCI) should leave this option set to 'N'. - -config CMDLINE - string "Built-in kernel command string" - depends on CMDLINE_BOOL - default "" - ---help--- - Enter arguments here that should be compiled into the kernel - image and used at boot time. If the boot loader provides a - command line at boot time, it is appended to this string to - form the full kernel command line, when the system boots. - - However, you can use the CONFIG_CMDLINE_OVERRIDE option to - change this behavior. - - In most cases, the command line (whether built-in or provided - by the boot loader) should specify the device for the root - file system. - -config CMDLINE_OVERRIDE - bool "Built-in command line overrides boot loader arguments" - default n - depends on CMDLINE_BOOL - ---help--- - Set this option to 'Y' to have the kernel ignore the boot loader - command line, and use ONLY the built-in command line. - - This is used to work around broken boot loaders. This should - be set to 'N' under normal conditions. - -config VMALLOC_RESERVE - hex - default 0x2000000 - -config HARDWALL - bool "Hardwall support to allow access to user dynamic network" - default y - -config KERNEL_PL - int "Processor protection level for kernel" - range 1 2 - default 2 if TILEGX - default 1 if !TILEGX - ---help--- - Since MDE 4.2, the Tilera hypervisor runs the kernel - at PL2 by default. If running under an older hypervisor, - or as a KVM guest, you must run at PL1. (The current - hypervisor may also be recompiled with "make HV_PL=2" to - allow it to run a kernel at PL1, but clients running at PL1 - are not expected to be supported indefinitely.) - - If you're not sure, don't change the default. - -source "arch/tile/gxio/Kconfig" - -endmenu # Tilera-specific configuration - -menu "Bus options" - -config PCI - bool "PCI support" - default y - select PCI_DOMAINS - select GENERIC_PCI_IOMAP - select TILE_GXIO_TRIO if TILEGX - select PCI_MSI if TILEGX - ---help--- - Enable PCI root complex support, so PCIe endpoint devices can - be attached to the Tile chip. Many, but not all, PCI devices - are supported under Tilera's root complex driver. - -config PCI_DOMAINS - bool - -config NO_IOMEM - def_bool !PCI - -config NO_IOPORT_MAP - def_bool !PCI - -config TILE_PCI_IO - bool "PCI I/O space support" - default n - depends on PCI - depends on TILEGX - ---help--- - Enable PCI I/O space support on TILEGx. Since the PCI I/O space - is used by few modern PCIe endpoint devices, its support is disabled - by default to save the TRIO PIO Region resource for other purposes. - -source "drivers/pci/Kconfig" - -config TILE_USB - tristate "Tilera USB host adapter support" - default y - depends on USB - depends on TILEGX - select TILE_GXIO_USB_HOST - ---help--- - Provides USB host adapter support for the built-in EHCI and OHCI - interfaces on TILE-Gx chips. - -endmenu - -menu "Executable file formats" - -source "fs/Kconfig.binfmt" - -endmenu - -source "net/Kconfig" - -source "drivers/Kconfig" - -source "fs/Kconfig" - -source "arch/tile/Kconfig.debug" - -source "security/Kconfig" - -source "crypto/Kconfig" - -source "lib/Kconfig" - -source "arch/tile/kvm/Kconfig" diff --git a/arch/tile/Kconfig.debug b/arch/tile/Kconfig.debug deleted file mode 100644 index 9f665d1a805f..000000000000 --- a/arch/tile/Kconfig.debug +++ /dev/null @@ -1,26 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -menu "Kernel hacking" - -source "lib/Kconfig.debug" - -config EARLY_PRINTK - bool "Early printk" if EXPERT && DEBUG_KERNEL - default y - help - Write kernel log output directly via the hypervisor console. - - This is useful for kernel debugging when your machine crashes very - early before the console code is initialized. For normal operation - it is not recommended because it looks ugly and doesn't cooperate - with klogd/syslogd. You should normally N here, - unless you want to debug such a crash. - -config TILE_HVGLUE_TRACE - bool "Provide wrapper functions for hypervisor ABI calls" - default n - help - Provide wrapper functions for the hypervisor ABI calls - defined in arch/tile/kernel/hvglue.S. This allows tracing - mechanisms, etc., to have visibility into those calls. - -endmenu diff --git a/arch/tile/Makefile b/arch/tile/Makefile deleted file mode 100644 index 8fa0befba32b..000000000000 --- a/arch/tile/Makefile +++ /dev/null @@ -1,77 +0,0 @@ -# -# This file is subject to the terms and conditions of the GNU General Public -# License. See the file "COPYING" in the main directory of this archive -# for more details. -# -# This file is included by the global makefile so that you can add your own -# architecture-specific flags and dependencies. Remember to do have actions -# for "archclean" and "archdep" for cleaning up and making dependencies for -# this architecture - -# If building with TILERA_ROOT set (i.e. using the Tilera Multicore -# Development Environment) we can set CROSS_COMPILE based on that. -# If we're not cross-compiling, make sure we're on the right architecture. -# Only bother to test for a few common targets, to avoid useless errors. -ifeq ($(CROSS_COMPILE),) - ifdef TILERA_ROOT - CROSS_COMPILE := $(TILERA_ROOT)/bin/tile- - else - goals := $(if $(MAKECMDGOALS), $(MAKECMDGOALS), all) - ifneq ($(strip $(filter vmlinux modules all,$(goals))),) - HOST_ARCH := $(shell uname -m) - ifneq ($(HOST_ARCH),$(ARCH)) -$(error Set TILERA_ROOT or CROSS_COMPILE when building $(ARCH) on $(HOST_ARCH)) - endif - endif - endif -endif - -# The tile compiler may emit .eh_frame information for backtracing. -# In kernel modules, this causes load failures due to unsupported relocations. -KBUILD_CFLAGS += -fno-asynchronous-unwind-tables - -LIBGCC_PATH := \ - $(shell $(CC) $(KBUILD_CFLAGS) $(KCFLAGS) -print-libgcc-file-name) - -# Provide the path to use for "make defconfig". -# We default to the newer TILE-Gx architecture if only "tile" is given. -ifeq ($(ARCH),tile) - KBUILD_DEFCONFIG := tilegx_defconfig -else - KBUILD_DEFCONFIG := $(ARCH)_defconfig -endif - -# Used as a file extension when useful, e.g. head_$(BITS).o -# Not needed for (e.g.) "$(CC) -m32" since the compiler automatically -# uses the right default anyway. -export BITS -ifeq ($(CONFIG_TILEGX),y) -BITS := 64 -else -BITS := 32 -endif - -CHECKFLAGS += -m$(BITS) - -head-y := arch/tile/kernel/head_$(BITS).o - -libs-y += arch/tile/lib/ -libs-y += $(LIBGCC_PATH) - -# See arch/tile/Kbuild for content of core part of the kernel -core-y += arch/tile/ - -core-$(CONFIG_TILE_GXIO) += arch/tile/gxio/ - -ifdef TILERA_ROOT -INSTALL_PATH ?= $(TILERA_ROOT)/tile/boot -endif - -install: - install -D -m 755 vmlinux $(INSTALL_PATH)/vmlinux-$(KERNELRELEASE) - install -D -m 644 .config $(INSTALL_PATH)/config-$(KERNELRELEASE) - install -D -m 644 System.map $(INSTALL_PATH)/System.map-$(KERNELRELEASE) - -define archhelp - echo ' install - install kernel into $(INSTALL_PATH)' -endef diff --git a/arch/tile/configs/tilegx_defconfig b/arch/tile/configs/tilegx_defconfig deleted file mode 100644 index 357a4c271ad4..000000000000 --- a/arch/tile/configs/tilegx_defconfig +++ /dev/null @@ -1,411 +0,0 @@ -CONFIG_TILEGX=y -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_FHANDLE=y -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_LOG_BUF_SHIFT=19 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_DEVICE=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_SCHED=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_BLK_CGROUP=y -CONFIG_NAMESPACES=y -CONFIG_RELAY=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_XZ=y -CONFIG_SYSCTL_SYSCALL=y -CONFIG_EMBEDDED=y -# CONFIG_COMPAT_BRK is not set -CONFIG_PROFILING=y -CONFIG_KPROBES=y -CONFIG_MODULES=y -CONFIG_MODULE_FORCE_LOAD=y -CONFIG_MODULE_UNLOAD=y -CONFIG_BLK_DEV_INTEGRITY=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_OSF_PARTITION=y -CONFIG_AMIGA_PARTITION=y -CONFIG_MAC_PARTITION=y -CONFIG_BSD_DISKLABEL=y -CONFIG_MINIX_SUBPARTITION=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_UNIXWARE_DISKLABEL=y -CONFIG_SGI_PARTITION=y -CONFIG_SUN_PARTITION=y -CONFIG_KARMA_PARTITION=y -CONFIG_CFQ_GROUP_IOSCHED=y -CONFIG_NR_CPUS=100 -CONFIG_HZ_100=y -# CONFIG_COMPACTION is not set -CONFIG_PREEMPT_VOLUNTARY=y -CONFIG_TILE_PCI_IO=y -CONFIG_PCI_DEBUG=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_BINFMT_MISC=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_SUB_POLICY=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=m -CONFIG_NET_KEY_MIGRATE=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_NET_IPIP=m -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_SYN_COOKIES=y -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -CONFIG_INET_XFRM_MODE_TRANSPORT=m -CONFIG_INET_XFRM_MODE_TUNNEL=m -CONFIG_INET_XFRM_MODE_BEET=m -CONFIG_INET_DIAG=m -CONFIG_TCP_CONG_ADVANCED=y -CONFIG_TCP_CONG_HSTCP=m -CONFIG_TCP_CONG_HYBLA=m -CONFIG_TCP_CONG_SCALABLE=m -CONFIG_TCP_CONG_LP=m -CONFIG_TCP_CONG_VENO=m -CONFIG_TCP_CONG_YEAH=m -CONFIG_TCP_CONG_ILLINOIS=m -CONFIG_TCP_MD5SIG=y -CONFIG_IPV6=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=m -CONFIG_INET6_ESP=m -CONFIG_INET6_IPCOMP=m -CONFIG_IPV6_MIP6=m -CONFIG_INET6_XFRM_MODE_TRANSPORT=m -CONFIG_INET6_XFRM_MODE_TUNNEL=m -CONFIG_INET6_XFRM_MODE_BEET=m -CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m -CONFIG_IPV6_SIT=m -CONFIG_IPV6_TUNNEL=m -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_MROUTE=y -CONFIG_IPV6_PIMSM_V2=y -CONFIG_NETLABEL=y -CONFIG_RDS=m -CONFIG_RDS_TCP=m -CONFIG_BRIDGE=m -CONFIG_VLAN_8021Q=m -CONFIG_VLAN_8021Q_GVRP=y -CONFIG_PHONET=m -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_HTB=m -CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_PRIO=m -CONFIG_NET_SCH_MULTIQ=m -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFQ=m -CONFIG_NET_SCH_TEQL=m -CONFIG_NET_SCH_TBF=m -CONFIG_NET_SCH_GRED=m -CONFIG_NET_SCH_DSMARK=m -CONFIG_NET_SCH_NETEM=m -CONFIG_NET_SCH_DRR=m -CONFIG_NET_SCH_INGRESS=m -CONFIG_NET_CLS_BASIC=m -CONFIG_NET_CLS_TCINDEX=m -CONFIG_NET_CLS_ROUTE4=m -CONFIG_NET_CLS_FW=m -CONFIG_NET_CLS_U32=m -CONFIG_CLS_U32_PERF=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_RSVP=m -CONFIG_NET_CLS_RSVP6=m -CONFIG_NET_CLS_FLOW=m -CONFIG_NET_CLS_CGROUP=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_CMP=m -CONFIG_NET_EMATCH_NBYTE=m -CONFIG_NET_EMATCH_U32=m -CONFIG_NET_EMATCH_META=m -CONFIG_NET_EMATCH_TEXT=m -CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_POLICE=m -CONFIG_NET_ACT_GACT=m -CONFIG_GACT_PROB=y -CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_NAT=m -CONFIG_NET_ACT_PEDIT=m -CONFIG_NET_ACT_SIMP=m -CONFIG_NET_ACT_SKBEDIT=m -CONFIG_NET_CLS_IND=y -CONFIG_DCB=y -CONFIG_DNS_RESOLVER=y -# CONFIG_WIRELESS is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_CONNECTOR=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_CRYPTOLOOP=m -CONFIG_BLK_DEV_SX8=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_ATA_OVER_ETH=m -CONFIG_RAID_ATTRS=m -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_SCSI_SAS_ATA=y -CONFIG_ISCSI_TCP=m -CONFIG_SCSI_MVSAS=y -# CONFIG_SCSI_MVSAS_DEBUG is not set -CONFIG_SCSI_MVSAS_TASKLET=y -CONFIG_ATA=y -CONFIG_SATA_AHCI=y -CONFIG_SATA_SIL24=y -# CONFIG_ATA_SFF is not set -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=m -CONFIG_MD_RAID0=m -CONFIG_MD_RAID1=m -CONFIG_MD_RAID10=m -CONFIG_MD_RAID456=m -CONFIG_MD_FAULTY=m -CONFIG_BLK_DEV_DM=m -CONFIG_DM_DEBUG=y -CONFIG_DM_CRYPT=m -CONFIG_DM_SNAPSHOT=m -CONFIG_DM_MIRROR=m -CONFIG_DM_LOG_USERSPACE=m -CONFIG_DM_ZERO=m -CONFIG_DM_MULTIPATH=m -CONFIG_DM_MULTIPATH_QL=m -CONFIG_DM_MULTIPATH_ST=m -CONFIG_DM_DELAY=m -CONFIG_DM_UEVENT=y -CONFIG_TARGET_CORE=m -CONFIG_TCM_IBLOCK=m -CONFIG_TCM_FILEIO=m -CONFIG_TCM_PSCSI=m -CONFIG_LOOPBACK_TARGET=m -CONFIG_ISCSI_TARGET=m -CONFIG_FUSION=y -CONFIG_FUSION_SAS=y -CONFIG_NETDEVICES=y -CONFIG_BONDING=m -CONFIG_DUMMY=m -CONFIG_IFB=m -CONFIG_MACVLAN=m -CONFIG_MACVTAP=m -CONFIG_NETCONSOLE=m -CONFIG_NETCONSOLE_DYNAMIC=y -CONFIG_TUN=y -CONFIG_VETH=m -CONFIG_NET_DSA_MV88E6060=y -CONFIG_NET_DSA_MV88E6XXX=y -CONFIG_SKY2=y -CONFIG_PTP_1588_CLOCK_TILEGX=y -# CONFIG_WLAN is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -CONFIG_SERIAL_TILEGX=y -CONFIG_HW_RANDOM=y -CONFIG_HW_RANDOM_TIMERIOMEM=m -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -# CONFIG_VGA_ARB is not set -CONFIG_DRM=m -CONFIG_DRM_TDFX=m -CONFIG_DRM_R128=m -CONFIG_DRM_MGA=m -CONFIG_DRM_VIA=m -CONFIG_DRM_SAVAGE=m -CONFIG_USB=y -CONFIG_USB_EHCI_HCD=y -CONFIG_USB_OHCI_HCD=y -CONFIG_USB_STORAGE=y -CONFIG_EDAC=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_TILE=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -CONFIG_EXT2_FS_XIP=y -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -CONFIG_XFS_POSIX_ACL=y -CONFIG_GFS2_FS=m -CONFIG_GFS2_FS_LOCKING_DLM=y -CONFIG_BTRFS_FS=m -CONFIG_BTRFS_FS_POSIX_ACL=y -CONFIG_QUOTA=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -# CONFIG_PRINT_QUOTA_WARNING is not set -CONFIG_QFMT_V2=y -CONFIG_AUTOFS4_FS=m -CONFIG_FUSE_FS=y -CONFIG_CUSE=m -CONFIG_FSCACHE=m -CONFIG_FSCACHE_STATS=y -CONFIG_CACHEFILES=m -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_FAT_DEFAULT_IOCHARSET="ascii" -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_HUGETLBFS=y -CONFIG_ECRYPT_FS=m -CONFIG_CRAMFS=m -CONFIG_SQUASHFS=m -CONFIG_NFS_FS=m -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=m -CONFIG_NFS_V4_1=y -CONFIG_NFS_FSCACHE=y -CONFIG_NFSD=m -CONFIG_NFSD_V3_ACL=y -CONFIG_NFSD_V4=y -CONFIG_CIFS=m -CONFIG_CIFS_STATS=y -CONFIG_CIFS_WEAK_PW_HASH=y -CONFIG_CIFS_UPCALL=y -CONFIG_CIFS_XATTR=y -CONFIG_CIFS_POSIX=y -CONFIG_CIFS_DFS_UPCALL=y -CONFIG_CIFS_FSCACHE=y -CONFIG_NLS_DEFAULT="utf8" -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_NLS_UTF8=m -CONFIG_DLM=m -CONFIG_DLM_DEBUG=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_INFO_REDUCED=y -# CONFIG_ENABLE_WARN_DEPRECATED is not set -CONFIG_STRIP_ASM_SYMS=y -CONFIG_DEBUG_FS=y -CONFIG_HEADERS_CHECK=y -# CONFIG_FRAME_POINTER is not set -CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y -CONFIG_DEBUG_VM=y -CONFIG_DEBUG_MEMORY_INIT=y -CONFIG_DEBUG_STACKOVERFLOW=y -CONFIG_LOCKUP_DETECTOR=y -CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y -CONFIG_DEBUG_LIST=y -CONFIG_DEBUG_CREDENTIALS=y -CONFIG_RCU_CPU_STALL_TIMEOUT=60 -CONFIG_ASYNC_RAID6_TEST=m -CONFIG_KGDB=y -CONFIG_SECURITY=y -CONFIG_SECURITYFS=y -CONFIG_SECURITY_NETWORK=y -CONFIG_SECURITY_NETWORK_XFRM=y -CONFIG_SECURITY_SELINUX=y -CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_SECURITY_SELINUX_DISABLE=y -CONFIG_CRYPTO_PCRYPT=m -CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_CCM=m -CONFIG_CRYPTO_GCM=m -CONFIG_CRYPTO_CTS=m -CONFIG_CRYPTO_LRW=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_XTS=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_XCBC=m -CONFIG_CRYPTO_VMAC=m -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m -CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m -CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_CAMELLIA=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_FCRYPT=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SEED=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_LZO=m diff --git a/arch/tile/configs/tilepro_defconfig b/arch/tile/configs/tilepro_defconfig deleted file mode 100644 index da2858755fa1..000000000000 --- a/arch/tile/configs/tilepro_defconfig +++ /dev/null @@ -1,524 +0,0 @@ -CONFIG_SYSVIPC=y -CONFIG_POSIX_MQUEUE=y -CONFIG_AUDIT=y -CONFIG_NO_HZ=y -CONFIG_HIGH_RES_TIMERS=y -CONFIG_BSD_PROCESS_ACCT=y -CONFIG_BSD_PROCESS_ACCT_V3=y -CONFIG_TASKSTATS=y -CONFIG_TASK_DELAY_ACCT=y -CONFIG_TASK_XACCT=y -CONFIG_TASK_IO_ACCOUNTING=y -CONFIG_LOG_BUF_SHIFT=19 -CONFIG_CGROUPS=y -CONFIG_CGROUP_DEBUG=y -CONFIG_CGROUP_DEVICE=y -CONFIG_CPUSETS=y -CONFIG_CGROUP_CPUACCT=y -CONFIG_CGROUP_SCHED=y -CONFIG_RT_GROUP_SCHED=y -CONFIG_BLK_CGROUP=y -CONFIG_NAMESPACES=y -CONFIG_RELAY=y -CONFIG_BLK_DEV_INITRD=y -CONFIG_RD_XZ=y -CONFIG_SYSCTL_SYSCALL=y -CONFIG_EMBEDDED=y -# CONFIG_COMPAT_BRK is not set -CONFIG_PROFILING=y -CONFIG_MODULES=y -CONFIG_MODULE_FORCE_LOAD=y -CONFIG_MODULE_UNLOAD=y -CONFIG_BLK_DEV_INTEGRITY=y -CONFIG_PARTITION_ADVANCED=y -CONFIG_OSF_PARTITION=y -CONFIG_AMIGA_PARTITION=y -CONFIG_MAC_PARTITION=y -CONFIG_BSD_DISKLABEL=y -CONFIG_MINIX_SUBPARTITION=y -CONFIG_SOLARIS_X86_PARTITION=y -CONFIG_UNIXWARE_DISKLABEL=y -CONFIG_SGI_PARTITION=y -CONFIG_SUN_PARTITION=y -CONFIG_KARMA_PARTITION=y -CONFIG_CFQ_GROUP_IOSCHED=y -CONFIG_HZ_100=y -# CONFIG_COMPACTION is not set -CONFIG_PREEMPT_VOLUNTARY=y -CONFIG_PCI_DEBUG=y -# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set -CONFIG_BINFMT_MISC=y -CONFIG_NET=y -CONFIG_PACKET=y -CONFIG_UNIX=y -CONFIG_XFRM_USER=y -CONFIG_XFRM_SUB_POLICY=y -CONFIG_XFRM_STATISTICS=y -CONFIG_NET_KEY=m -CONFIG_NET_KEY_MIGRATE=y -CONFIG_INET=y -CONFIG_IP_MULTICAST=y -CONFIG_IP_ADVANCED_ROUTER=y -CONFIG_IP_MULTIPLE_TABLES=y -CONFIG_IP_ROUTE_MULTIPATH=y -CONFIG_IP_ROUTE_VERBOSE=y -CONFIG_NET_IPIP=m -CONFIG_IP_MROUTE=y -CONFIG_IP_PIMSM_V1=y -CONFIG_IP_PIMSM_V2=y -CONFIG_SYN_COOKIES=y -CONFIG_INET_AH=m -CONFIG_INET_ESP=m -CONFIG_INET_IPCOMP=m -CONFIG_INET_XFRM_MODE_TRANSPORT=m -CONFIG_INET_XFRM_MODE_TUNNEL=m -CONFIG_INET_XFRM_MODE_BEET=m -CONFIG_INET_DIAG=m -CONFIG_TCP_CONG_ADVANCED=y -CONFIG_TCP_CONG_HSTCP=m -CONFIG_TCP_CONG_HYBLA=m -CONFIG_TCP_CONG_SCALABLE=m -CONFIG_TCP_CONG_LP=m -CONFIG_TCP_CONG_VENO=m -CONFIG_TCP_CONG_YEAH=m -CONFIG_TCP_CONG_ILLINOIS=m -CONFIG_TCP_MD5SIG=y -CONFIG_IPV6=y -CONFIG_IPV6_ROUTER_PREF=y -CONFIG_IPV6_ROUTE_INFO=y -CONFIG_IPV6_OPTIMISTIC_DAD=y -CONFIG_INET6_AH=m -CONFIG_INET6_ESP=m -CONFIG_INET6_IPCOMP=m -CONFIG_IPV6_MIP6=m -CONFIG_INET6_XFRM_MODE_TRANSPORT=m -CONFIG_INET6_XFRM_MODE_TUNNEL=m -CONFIG_INET6_XFRM_MODE_BEET=m -CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m -CONFIG_IPV6_SIT=m -CONFIG_IPV6_TUNNEL=m -CONFIG_IPV6_MULTIPLE_TABLES=y -CONFIG_IPV6_MROUTE=y -CONFIG_IPV6_PIMSM_V2=y -CONFIG_NETLABEL=y -CONFIG_NETFILTER=y -CONFIG_NF_CONNTRACK=m -CONFIG_NF_CONNTRACK_SECMARK=y -CONFIG_NF_CONNTRACK_ZONES=y -CONFIG_NF_CONNTRACK_EVENTS=y -CONFIG_NF_CT_PROTO_DCCP=m -CONFIG_NF_CT_PROTO_UDPLITE=m -CONFIG_NF_CONNTRACK_AMANDA=m -CONFIG_NF_CONNTRACK_FTP=m -CONFIG_NF_CONNTRACK_H323=m -CONFIG_NF_CONNTRACK_IRC=m -CONFIG_NF_CONNTRACK_NETBIOS_NS=m -CONFIG_NF_CONNTRACK_PPTP=m -CONFIG_NF_CONNTRACK_SANE=m -CONFIG_NF_CONNTRACK_SIP=m -CONFIG_NF_CONNTRACK_TFTP=m -CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m -CONFIG_NETFILTER_XT_TARGET_CONNMARK=m -CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m -CONFIG_NETFILTER_XT_TARGET_DSCP=m -CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m -CONFIG_NETFILTER_XT_TARGET_MARK=m -CONFIG_NETFILTER_XT_TARGET_NFLOG=m -CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m -CONFIG_NETFILTER_XT_TARGET_NOTRACK=m -CONFIG_NETFILTER_XT_TARGET_TEE=m -CONFIG_NETFILTER_XT_TARGET_TPROXY=m -CONFIG_NETFILTER_XT_TARGET_TRACE=m -CONFIG_NETFILTER_XT_TARGET_SECMARK=m -CONFIG_NETFILTER_XT_TARGET_TCPMSS=m -CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP=m -CONFIG_NETFILTER_XT_MATCH_CLUSTER=m -CONFIG_NETFILTER_XT_MATCH_COMMENT=m -CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m -CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m -CONFIG_NETFILTER_XT_MATCH_CONNMARK=m -CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m -CONFIG_NETFILTER_XT_MATCH_DCCP=m -CONFIG_NETFILTER_XT_MATCH_DSCP=m -CONFIG_NETFILTER_XT_MATCH_ESP=m -CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m -CONFIG_NETFILTER_XT_MATCH_HELPER=m -CONFIG_NETFILTER_XT_MATCH_IPRANGE=m -CONFIG_NETFILTER_XT_MATCH_IPVS=m -CONFIG_NETFILTER_XT_MATCH_LENGTH=m -CONFIG_NETFILTER_XT_MATCH_LIMIT=m -CONFIG_NETFILTER_XT_MATCH_MAC=m -CONFIG_NETFILTER_XT_MATCH_MARK=m -CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m -CONFIG_NETFILTER_XT_MATCH_OSF=m -CONFIG_NETFILTER_XT_MATCH_OWNER=m -CONFIG_NETFILTER_XT_MATCH_POLICY=m -CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m -CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m -CONFIG_NETFILTER_XT_MATCH_QUOTA=m -CONFIG_NETFILTER_XT_MATCH_RATEEST=m -CONFIG_NETFILTER_XT_MATCH_REALM=m -CONFIG_NETFILTER_XT_MATCH_RECENT=m -CONFIG_NETFILTER_XT_MATCH_SOCKET=m -CONFIG_NETFILTER_XT_MATCH_STATE=m -CONFIG_NETFILTER_XT_MATCH_STATISTIC=m -CONFIG_NETFILTER_XT_MATCH_STRING=m -CONFIG_NETFILTER_XT_MATCH_TCPMSS=m -CONFIG_NETFILTER_XT_MATCH_TIME=m -CONFIG_NETFILTER_XT_MATCH_U32=m -CONFIG_IP_VS=m -CONFIG_IP_VS_IPV6=y -CONFIG_IP_VS_PROTO_TCP=y -CONFIG_IP_VS_PROTO_UDP=y -CONFIG_IP_VS_PROTO_ESP=y -CONFIG_IP_VS_PROTO_AH=y -CONFIG_IP_VS_PROTO_SCTP=y -CONFIG_IP_VS_RR=m -CONFIG_IP_VS_WRR=m -CONFIG_IP_VS_LC=m -CONFIG_IP_VS_WLC=m -CONFIG_IP_VS_LBLC=m -CONFIG_IP_VS_LBLCR=m -CONFIG_IP_VS_SED=m -CONFIG_IP_VS_NQ=m -CONFIG_NF_CONNTRACK_IPV4=m -# CONFIG_NF_CONNTRACK_PROC_COMPAT is not set -CONFIG_IP_NF_IPTABLES=y -CONFIG_IP_NF_MATCH_AH=m -CONFIG_IP_NF_MATCH_ECN=m -CONFIG_IP_NF_MATCH_TTL=m -CONFIG_IP_NF_FILTER=y -CONFIG_IP_NF_TARGET_REJECT=y -CONFIG_IP_NF_MANGLE=m -CONFIG_IP_NF_TARGET_ECN=m -CONFIG_IP_NF_TARGET_TTL=m -CONFIG_IP_NF_RAW=m -CONFIG_IP_NF_SECURITY=m -CONFIG_IP_NF_ARPTABLES=m -CONFIG_IP_NF_ARPFILTER=m -CONFIG_IP_NF_ARP_MANGLE=m -CONFIG_NF_CONNTRACK_IPV6=m -CONFIG_IP6_NF_MATCH_AH=m -CONFIG_IP6_NF_MATCH_EUI64=m -CONFIG_IP6_NF_MATCH_FRAG=m -CONFIG_IP6_NF_MATCH_OPTS=m -CONFIG_IP6_NF_MATCH_HL=m -CONFIG_IP6_NF_MATCH_IPV6HEADER=m -CONFIG_IP6_NF_MATCH_MH=m -CONFIG_IP6_NF_MATCH_RT=m -CONFIG_IP6_NF_TARGET_HL=m -CONFIG_IP6_NF_FILTER=m -CONFIG_IP6_NF_TARGET_REJECT=m -CONFIG_IP6_NF_MANGLE=m -CONFIG_IP6_NF_RAW=m -CONFIG_IP6_NF_SECURITY=m -CONFIG_BRIDGE_NF_EBTABLES=m -CONFIG_BRIDGE_EBT_BROUTE=m -CONFIG_BRIDGE_EBT_T_FILTER=m -CONFIG_BRIDGE_EBT_T_NAT=m -CONFIG_BRIDGE_EBT_802_3=m -CONFIG_BRIDGE_EBT_AMONG=m -CONFIG_BRIDGE_EBT_ARP=m -CONFIG_BRIDGE_EBT_IP=m -CONFIG_BRIDGE_EBT_IP6=m -CONFIG_BRIDGE_EBT_LIMIT=m -CONFIG_BRIDGE_EBT_MARK=m -CONFIG_BRIDGE_EBT_PKTTYPE=m -CONFIG_BRIDGE_EBT_STP=m -CONFIG_BRIDGE_EBT_VLAN=m -CONFIG_BRIDGE_EBT_ARPREPLY=m -CONFIG_BRIDGE_EBT_DNAT=m -CONFIG_BRIDGE_EBT_MARK_T=m -CONFIG_BRIDGE_EBT_REDIRECT=m -CONFIG_BRIDGE_EBT_SNAT=m -CONFIG_BRIDGE_EBT_LOG=m -CONFIG_BRIDGE_EBT_ULOG=m -CONFIG_BRIDGE_EBT_NFLOG=m -CONFIG_RDS=m -CONFIG_RDS_TCP=m -CONFIG_BRIDGE=m -CONFIG_VLAN_8021Q=m -CONFIG_VLAN_8021Q_GVRP=y -CONFIG_PHONET=m -CONFIG_NET_SCHED=y -CONFIG_NET_SCH_CBQ=m -CONFIG_NET_SCH_HTB=m -CONFIG_NET_SCH_HFSC=m -CONFIG_NET_SCH_PRIO=m -CONFIG_NET_SCH_MULTIQ=m -CONFIG_NET_SCH_RED=m -CONFIG_NET_SCH_SFQ=m -CONFIG_NET_SCH_TEQL=m -CONFIG_NET_SCH_TBF=m -CONFIG_NET_SCH_GRED=m -CONFIG_NET_SCH_DSMARK=m -CONFIG_NET_SCH_NETEM=m -CONFIG_NET_SCH_DRR=m -CONFIG_NET_SCH_INGRESS=m -CONFIG_NET_CLS_BASIC=m -CONFIG_NET_CLS_TCINDEX=m -CONFIG_NET_CLS_ROUTE4=m -CONFIG_NET_CLS_FW=m -CONFIG_NET_CLS_U32=m -CONFIG_CLS_U32_PERF=y -CONFIG_CLS_U32_MARK=y -CONFIG_NET_CLS_RSVP=m -CONFIG_NET_CLS_RSVP6=m -CONFIG_NET_CLS_FLOW=m -CONFIG_NET_CLS_CGROUP=y -CONFIG_NET_EMATCH=y -CONFIG_NET_EMATCH_CMP=m -CONFIG_NET_EMATCH_NBYTE=m -CONFIG_NET_EMATCH_U32=m -CONFIG_NET_EMATCH_META=m -CONFIG_NET_EMATCH_TEXT=m -CONFIG_NET_CLS_ACT=y -CONFIG_NET_ACT_POLICE=m -CONFIG_NET_ACT_GACT=m -CONFIG_GACT_PROB=y -CONFIG_NET_ACT_MIRRED=m -CONFIG_NET_ACT_IPT=m -CONFIG_NET_ACT_NAT=m -CONFIG_NET_ACT_PEDIT=m -CONFIG_NET_ACT_SIMP=m -CONFIG_NET_ACT_SKBEDIT=m -CONFIG_NET_CLS_IND=y -CONFIG_DCB=y -CONFIG_DNS_RESOLVER=y -# CONFIG_WIRELESS is not set -CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" -CONFIG_DEVTMPFS=y -CONFIG_DEVTMPFS_MOUNT=y -CONFIG_CONNECTOR=y -CONFIG_BLK_DEV_LOOP=y -CONFIG_BLK_DEV_CRYPTOLOOP=m -CONFIG_BLK_DEV_SX8=m -CONFIG_BLK_DEV_RAM=y -CONFIG_BLK_DEV_RAM_SIZE=16384 -CONFIG_ATA_OVER_ETH=m -CONFIG_RAID_ATTRS=m -CONFIG_BLK_DEV_SD=y -CONFIG_SCSI_CONSTANTS=y -CONFIG_SCSI_LOGGING=y -CONFIG_ATA=y -CONFIG_SATA_SIL24=y -# CONFIG_ATA_SFF is not set -CONFIG_MD=y -CONFIG_BLK_DEV_MD=y -CONFIG_MD_LINEAR=m -CONFIG_MD_RAID0=m -CONFIG_MD_RAID1=m -CONFIG_MD_RAID10=m -CONFIG_MD_RAID456=m -CONFIG_MD_FAULTY=m -CONFIG_BLK_DEV_DM=m -CONFIG_DM_DEBUG=y -CONFIG_DM_CRYPT=m -CONFIG_DM_SNAPSHOT=m -CONFIG_DM_MIRROR=m -CONFIG_DM_LOG_USERSPACE=m -CONFIG_DM_ZERO=m -CONFIG_DM_MULTIPATH=m -CONFIG_DM_MULTIPATH_QL=m -CONFIG_DM_MULTIPATH_ST=m -CONFIG_DM_DELAY=m -CONFIG_DM_UEVENT=y -CONFIG_FUSION=y -CONFIG_FUSION_SAS=y -CONFIG_NETDEVICES=y -CONFIG_BONDING=m -CONFIG_DUMMY=m -CONFIG_IFB=m -CONFIG_MACVLAN=m -CONFIG_MACVTAP=m -CONFIG_NETCONSOLE=m -CONFIG_NETCONSOLE_DYNAMIC=y -CONFIG_TUN=y -CONFIG_VETH=m -CONFIG_NET_DSA_MV88E6060=y -CONFIG_NET_DSA_MV88E6XXX=y -# CONFIG_NET_VENDOR_3COM is not set -CONFIG_E1000E=y -# CONFIG_WLAN is not set -# CONFIG_INPUT_MOUSEDEV is not set -# CONFIG_INPUT_KEYBOARD is not set -# CONFIG_INPUT_MOUSE is not set -# CONFIG_SERIO is not set -# CONFIG_VT is not set -# CONFIG_LEGACY_PTYS is not set -CONFIG_HW_RANDOM=y -CONFIG_HW_RANDOM_TIMERIOMEM=m -CONFIG_I2C=y -CONFIG_I2C_CHARDEV=y -# CONFIG_HWMON is not set -CONFIG_WATCHDOG=y -CONFIG_WATCHDOG_NOWAYOUT=y -# CONFIG_VGA_ARB is not set -# CONFIG_USB_SUPPORT is not set -CONFIG_EDAC=y -CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_TILE=y -CONFIG_EXT2_FS=y -CONFIG_EXT2_FS_XATTR=y -CONFIG_EXT2_FS_POSIX_ACL=y -CONFIG_EXT2_FS_SECURITY=y -CONFIG_EXT2_FS_XIP=y -CONFIG_EXT3_FS=y -CONFIG_EXT3_FS_POSIX_ACL=y -CONFIG_EXT3_FS_SECURITY=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_XFS_FS=y -CONFIG_XFS_QUOTA=y -CONFIG_XFS_POSIX_ACL=y -CONFIG_GFS2_FS=m -CONFIG_GFS2_FS_LOCKING_DLM=y -CONFIG_BTRFS_FS=m -CONFIG_BTRFS_FS_POSIX_ACL=y -CONFIG_QUOTA=y -CONFIG_QUOTA_NETLINK_INTERFACE=y -# CONFIG_PRINT_QUOTA_WARNING is not set -CONFIG_QFMT_V2=y -CONFIG_AUTOFS4_FS=m -CONFIG_FUSE_FS=y -CONFIG_CUSE=m -CONFIG_FSCACHE=m -CONFIG_FSCACHE_STATS=y -CONFIG_CACHEFILES=m -CONFIG_ISO9660_FS=m -CONFIG_JOLIET=y -CONFIG_ZISOFS=y -CONFIG_UDF_FS=m -CONFIG_MSDOS_FS=m -CONFIG_VFAT_FS=m -CONFIG_FAT_DEFAULT_IOCHARSET="ascii" -CONFIG_PROC_KCORE=y -CONFIG_TMPFS=y -CONFIG_TMPFS_POSIX_ACL=y -CONFIG_HUGETLBFS=y -CONFIG_CONFIGFS_FS=m -CONFIG_ECRYPT_FS=m -CONFIG_CRAMFS=m -CONFIG_SQUASHFS=m -CONFIG_NFS_FS=m -CONFIG_NFS_V3_ACL=y -CONFIG_NFS_V4=m -CONFIG_NFS_V4_1=y -CONFIG_NFS_FSCACHE=y -CONFIG_NFSD=m -CONFIG_NFSD_V3_ACL=y -CONFIG_NFSD_V4=y -CONFIG_CIFS=m -CONFIG_CIFS_STATS=y -CONFIG_CIFS_WEAK_PW_HASH=y -CONFIG_CIFS_UPCALL=y -CONFIG_CIFS_XATTR=y -CONFIG_CIFS_POSIX=y -CONFIG_CIFS_DFS_UPCALL=y -CONFIG_CIFS_FSCACHE=y -CONFIG_NLS=y -CONFIG_NLS_DEFAULT="utf8" -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_737=m -CONFIG_NLS_CODEPAGE_775=m -CONFIG_NLS_CODEPAGE_850=m -CONFIG_NLS_CODEPAGE_852=m -CONFIG_NLS_CODEPAGE_855=m -CONFIG_NLS_CODEPAGE_857=m -CONFIG_NLS_CODEPAGE_860=m -CONFIG_NLS_CODEPAGE_861=m -CONFIG_NLS_CODEPAGE_862=m -CONFIG_NLS_CODEPAGE_863=m -CONFIG_NLS_CODEPAGE_864=m -CONFIG_NLS_CODEPAGE_865=m -CONFIG_NLS_CODEPAGE_866=m -CONFIG_NLS_CODEPAGE_869=m -CONFIG_NLS_CODEPAGE_936=m -CONFIG_NLS_CODEPAGE_950=m -CONFIG_NLS_CODEPAGE_932=m -CONFIG_NLS_CODEPAGE_949=m -CONFIG_NLS_CODEPAGE_874=m -CONFIG_NLS_ISO8859_8=m -CONFIG_NLS_CODEPAGE_1250=m -CONFIG_NLS_CODEPAGE_1251=m -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=m -CONFIG_NLS_ISO8859_2=m -CONFIG_NLS_ISO8859_3=m -CONFIG_NLS_ISO8859_4=m -CONFIG_NLS_ISO8859_5=m -CONFIG_NLS_ISO8859_6=m -CONFIG_NLS_ISO8859_7=m -CONFIG_NLS_ISO8859_9=m -CONFIG_NLS_ISO8859_13=m -CONFIG_NLS_ISO8859_14=m -CONFIG_NLS_ISO8859_15=m -CONFIG_NLS_KOI8_R=m -CONFIG_NLS_KOI8_U=m -CONFIG_NLS_UTF8=m -CONFIG_DLM=m -CONFIG_DLM_DEBUG=y -CONFIG_DYNAMIC_DEBUG=y -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_INFO_REDUCED=y -# CONFIG_ENABLE_WARN_DEPRECATED is not set -CONFIG_FRAME_WARN=2048 -CONFIG_STRIP_ASM_SYMS=y -CONFIG_DEBUG_FS=y -CONFIG_HEADERS_CHECK=y -# CONFIG_FRAME_POINTER is not set -CONFIG_DEBUG_FORCE_WEAK_PER_CPU=y -CONFIG_MAGIC_SYSRQ=y -CONFIG_DEBUG_VM=y -CONFIG_DEBUG_MEMORY_INIT=y -CONFIG_DEBUG_STACKOVERFLOW=y -CONFIG_LOCKUP_DETECTOR=y -CONFIG_SCHEDSTATS=y -CONFIG_TIMER_STATS=y -CONFIG_DEBUG_LIST=y -CONFIG_DEBUG_CREDENTIALS=y -CONFIG_RCU_CPU_STALL_TIMEOUT=60 -CONFIG_ASYNC_RAID6_TEST=m -CONFIG_SECURITY=y -CONFIG_SECURITYFS=y -CONFIG_SECURITY_NETWORK=y -CONFIG_SECURITY_NETWORK_XFRM=y -CONFIG_SECURITY_SELINUX=y -CONFIG_SECURITY_SELINUX_BOOTPARAM=y -CONFIG_SECURITY_SELINUX_DISABLE=y -CONFIG_CRYPTO_PCRYPT=m -CONFIG_CRYPTO_CRYPTD=m -CONFIG_CRYPTO_TEST=m -CONFIG_CRYPTO_CCM=m -CONFIG_CRYPTO_GCM=m -CONFIG_CRYPTO_CTS=m -CONFIG_CRYPTO_LRW=m -CONFIG_CRYPTO_PCBC=m -CONFIG_CRYPTO_XTS=m -CONFIG_CRYPTO_HMAC=y -CONFIG_CRYPTO_XCBC=m -CONFIG_CRYPTO_VMAC=m -CONFIG_CRYPTO_MICHAEL_MIC=m -CONFIG_CRYPTO_RMD128=m -CONFIG_CRYPTO_RMD160=m -CONFIG_CRYPTO_RMD256=m -CONFIG_CRYPTO_RMD320=m -CONFIG_CRYPTO_SHA1=y -CONFIG_CRYPTO_SHA512=m -CONFIG_CRYPTO_TGR192=m -CONFIG_CRYPTO_WP512=m -CONFIG_CRYPTO_ANUBIS=m -CONFIG_CRYPTO_BLOWFISH=m -CONFIG_CRYPTO_CAMELLIA=m -CONFIG_CRYPTO_CAST5=m -CONFIG_CRYPTO_CAST6=m -CONFIG_CRYPTO_FCRYPT=m -CONFIG_CRYPTO_KHAZAD=m -CONFIG_CRYPTO_SEED=m -CONFIG_CRYPTO_SERPENT=m -CONFIG_CRYPTO_TEA=m -CONFIG_CRYPTO_TWOFISH=m -CONFIG_CRYPTO_LZO=m -CONFIG_CRC_CCITT=m -CONFIG_CRC7=m diff --git a/arch/tile/gxio/Kconfig b/arch/tile/gxio/Kconfig deleted file mode 100644 index 903c8646bdd7..000000000000 --- a/arch/tile/gxio/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Support direct access to TILE-Gx hardware from user space, via the -# gxio library, or from kernel space, via kernel IORPC support. -config TILE_GXIO - bool - depends on TILEGX - -# Support direct access to the common I/O DMA facility within the -# TILE-Gx mPIPE and Trio hardware from kernel space. -config TILE_GXIO_DMA - bool - select TILE_GXIO - -# Support direct access to the TILE-Gx mPIPE hardware from kernel space. -config TILE_GXIO_MPIPE - bool - select TILE_GXIO - select TILE_GXIO_DMA - -# Support direct access to the TILE-Gx TRIO hardware from kernel space. -config TILE_GXIO_TRIO - bool - select TILE_GXIO - select TILE_GXIO_DMA - -# Support direct access to the TILE-Gx USB hardware from kernel space. -config TILE_GXIO_USB_HOST - bool - select TILE_GXIO - -# Support direct access to the TILE-Gx UART hardware from kernel space. -config TILE_GXIO_UART - bool - select TILE_GXIO diff --git a/arch/tile/gxio/Makefile b/arch/tile/gxio/Makefile deleted file mode 100644 index fcc903c4cf87..000000000000 --- a/arch/tile/gxio/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the Tile-Gx device access support. -# - -obj-$(CONFIG_TILE_GXIO) += iorpc_globals.o kiorpc.o -obj-$(CONFIG_TILE_GXIO_DMA) += dma_queue.o -obj-$(CONFIG_TILE_GXIO_MPIPE) += mpipe.o iorpc_mpipe.o iorpc_mpipe_info.o -obj-$(CONFIG_TILE_GXIO_TRIO) += trio.o iorpc_trio.o -obj-$(CONFIG_TILE_GXIO_UART) += uart.o iorpc_uart.o -obj-$(CONFIG_TILE_GXIO_USB_HOST) += usb_host.o iorpc_usb_host.o diff --git a/arch/tile/gxio/dma_queue.c b/arch/tile/gxio/dma_queue.c deleted file mode 100644 index b7ba577d82ca..000000000000 --- a/arch/tile/gxio/dma_queue.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include - -/* Wait for a memory read to complete. */ -#define wait_for_value(val) \ - __asm__ __volatile__("move %0, %0" :: "r"(val)) - -/* The index is in the low 16. */ -#define DMA_QUEUE_INDEX_MASK ((1 << 16) - 1) - -/* - * The hardware descriptor-ring type. - * This matches the types used by mpipe (MPIPE_EDMA_POST_REGION_VAL_t) - * and trio (TRIO_PUSH_DMA_REGION_VAL_t or TRIO_PULL_DMA_REGION_VAL_t). - * See those types for more documentation on the individual fields. - */ -typedef union { - struct { -#ifndef __BIG_ENDIAN__ - uint64_t ring_idx:16; - uint64_t count:16; - uint64_t gen:1; - uint64_t __reserved:31; -#else - uint64_t __reserved:31; - uint64_t gen:1; - uint64_t count:16; - uint64_t ring_idx:16; -#endif - }; - uint64_t word; -} __gxio_ring_t; - -void __gxio_dma_queue_init(__gxio_dma_queue_t *dma_queue, - void *post_region_addr, unsigned int num_entries) -{ - /* - * Limit 65536 entry rings to 65535 credits because we only have a - * 16 bit completion counter. - */ - int64_t credits = (num_entries < 65536) ? num_entries : 65535; - - memset(dma_queue, 0, sizeof(*dma_queue)); - - dma_queue->post_region_addr = post_region_addr; - dma_queue->hw_complete_count = 0; - dma_queue->credits_and_next_index = credits << DMA_QUEUE_CREDIT_SHIFT; -} - -EXPORT_SYMBOL_GPL(__gxio_dma_queue_init); - -void __gxio_dma_queue_update_credits(__gxio_dma_queue_t *dma_queue) -{ - __gxio_ring_t val; - uint64_t count; - uint64_t delta; - uint64_t new_count; - - /* - * Read the 64-bit completion count without touching the cache, so - * we later avoid having to evict any sharers of this cache line - * when we update it below. - */ - uint64_t orig_hw_complete_count = - cmpxchg(&dma_queue->hw_complete_count, - -1, -1); - - /* Make sure the load completes before we access the hardware. */ - wait_for_value(orig_hw_complete_count); - - /* Read the 16-bit count of how many packets it has completed. */ - val.word = __gxio_mmio_read(dma_queue->post_region_addr); - count = val.count; - - /* - * Calculate the number of completions since we last updated the - * 64-bit counter. It's safe to ignore the high bits because the - * maximum credit value is 65535. - */ - delta = (count - orig_hw_complete_count) & 0xffff; - if (delta == 0) - return; - - /* - * Try to write back the count, advanced by delta. If we race with - * another thread, this might fail, in which case we return - * immediately on the assumption that some credits are (or at least - * were) available. - */ - new_count = orig_hw_complete_count + delta; - if (cmpxchg(&dma_queue->hw_complete_count, - orig_hw_complete_count, - new_count) != orig_hw_complete_count) - return; - - /* - * We succeeded in advancing the completion count; add back the - * corresponding number of egress credits. - */ - __insn_fetchadd(&dma_queue->credits_and_next_index, - (delta << DMA_QUEUE_CREDIT_SHIFT)); -} - -EXPORT_SYMBOL_GPL(__gxio_dma_queue_update_credits); - -/* - * A separate 'blocked' method for put() so that backtraces and - * profiles will clearly indicate that we're wasting time spinning on - * egress availability rather than actually posting commands. - */ -int64_t __gxio_dma_queue_wait_for_credits(__gxio_dma_queue_t *dma_queue, - int64_t modifier) -{ - int backoff = 16; - int64_t old; - - do { - int i; - /* Back off to avoid spamming memory networks. */ - for (i = backoff; i > 0; i--) - __insn_mfspr(SPR_PASS); - - /* Check credits again. */ - __gxio_dma_queue_update_credits(dma_queue); - old = __insn_fetchaddgez(&dma_queue->credits_and_next_index, - modifier); - - /* Calculate bounded exponential backoff for next iteration. */ - if (backoff < 256) - backoff *= 2; - } while (old + modifier < 0); - - return old; -} - -EXPORT_SYMBOL_GPL(__gxio_dma_queue_wait_for_credits); - -int64_t __gxio_dma_queue_reserve_aux(__gxio_dma_queue_t *dma_queue, - unsigned int num, int wait) -{ - return __gxio_dma_queue_reserve(dma_queue, num, wait != 0, true); -} - -EXPORT_SYMBOL_GPL(__gxio_dma_queue_reserve_aux); - -int __gxio_dma_queue_is_complete(__gxio_dma_queue_t *dma_queue, - int64_t completion_slot, int update) -{ - if (update) { - if (READ_ONCE(dma_queue->hw_complete_count) > - completion_slot) - return 1; - - __gxio_dma_queue_update_credits(dma_queue); - } - - return READ_ONCE(dma_queue->hw_complete_count) > completion_slot; -} - -EXPORT_SYMBOL_GPL(__gxio_dma_queue_is_complete); diff --git a/arch/tile/gxio/iorpc_globals.c b/arch/tile/gxio/iorpc_globals.c deleted file mode 100644 index e178e90805a2..000000000000 --- a/arch/tile/gxio/iorpc_globals.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#include "gxio/iorpc_globals.h" - -struct arm_pollfd_param { - union iorpc_pollfd pollfd; -}; - -int __iorpc_arm_pollfd(int fd, int pollfd_cookie) -{ - struct arm_pollfd_param temp; - struct arm_pollfd_param *params = &temp; - - params->pollfd.kernel.cookie = pollfd_cookie; - - return hv_dev_pwrite(fd, 0, (HV_VirtAddr) params, sizeof(*params), - IORPC_OP_ARM_POLLFD); -} - -EXPORT_SYMBOL(__iorpc_arm_pollfd); - -struct close_pollfd_param { - union iorpc_pollfd pollfd; -}; - -int __iorpc_close_pollfd(int fd, int pollfd_cookie) -{ - struct close_pollfd_param temp; - struct close_pollfd_param *params = &temp; - - params->pollfd.kernel.cookie = pollfd_cookie; - - return hv_dev_pwrite(fd, 0, (HV_VirtAddr) params, sizeof(*params), - IORPC_OP_CLOSE_POLLFD); -} - -EXPORT_SYMBOL(__iorpc_close_pollfd); - -struct get_mmio_base_param { - HV_PTE base; -}; - -int __iorpc_get_mmio_base(int fd, HV_PTE *base) -{ - int __result; - struct get_mmio_base_param temp; - struct get_mmio_base_param *params = &temp; - - __result = - hv_dev_pread(fd, 0, (HV_VirtAddr) params, sizeof(*params), - IORPC_OP_GET_MMIO_BASE); - *base = params->base; - - return __result; -} - -EXPORT_SYMBOL(__iorpc_get_mmio_base); - -struct check_mmio_offset_param { - unsigned long offset; - unsigned long size; -}; - -int __iorpc_check_mmio_offset(int fd, unsigned long offset, unsigned long size) -{ - struct check_mmio_offset_param temp; - struct check_mmio_offset_param *params = &temp; - - params->offset = offset; - params->size = size; - - return hv_dev_pwrite(fd, 0, (HV_VirtAddr) params, sizeof(*params), - IORPC_OP_CHECK_MMIO_OFFSET); -} - -EXPORT_SYMBOL(__iorpc_check_mmio_offset); diff --git a/arch/tile/gxio/iorpc_mpipe.c b/arch/tile/gxio/iorpc_mpipe.c deleted file mode 100644 index e19325c4c431..000000000000 --- a/arch/tile/gxio/iorpc_mpipe.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#include "gxio/iorpc_mpipe.h" - -struct alloc_buffer_stacks_param { - unsigned int count; - unsigned int first; - unsigned int flags; -}; - -int gxio_mpipe_alloc_buffer_stacks(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags) -{ - struct alloc_buffer_stacks_param temp; - struct alloc_buffer_stacks_param *params = &temp; - - params->count = count; - params->first = first; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_MPIPE_OP_ALLOC_BUFFER_STACKS); -} - -EXPORT_SYMBOL(gxio_mpipe_alloc_buffer_stacks); - -struct init_buffer_stack_aux_param { - union iorpc_mem_buffer buffer; - unsigned int stack; - unsigned int buffer_size_enum; -}; - -int gxio_mpipe_init_buffer_stack_aux(gxio_mpipe_context_t *context, - void *mem_va, size_t mem_size, - unsigned int mem_flags, unsigned int stack, - unsigned int buffer_size_enum) -{ - int __result; - unsigned long long __cpa; - pte_t __pte; - struct init_buffer_stack_aux_param temp; - struct init_buffer_stack_aux_param *params = &temp; - - __result = va_to_cpa_and_pte(mem_va, &__cpa, &__pte); - if (__result != 0) - return __result; - params->buffer.kernel.cpa = __cpa; - params->buffer.kernel.size = mem_size; - params->buffer.kernel.pte = __pte; - params->buffer.kernel.flags = mem_flags; - params->stack = stack; - params->buffer_size_enum = buffer_size_enum; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_MPIPE_OP_INIT_BUFFER_STACK_AUX); -} - -EXPORT_SYMBOL(gxio_mpipe_init_buffer_stack_aux); - - -struct alloc_notif_rings_param { - unsigned int count; - unsigned int first; - unsigned int flags; -}; - -int gxio_mpipe_alloc_notif_rings(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags) -{ - struct alloc_notif_rings_param temp; - struct alloc_notif_rings_param *params = &temp; - - params->count = count; - params->first = first; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_ALLOC_NOTIF_RINGS); -} - -EXPORT_SYMBOL(gxio_mpipe_alloc_notif_rings); - -struct init_notif_ring_aux_param { - union iorpc_mem_buffer buffer; - unsigned int ring; -}; - -int gxio_mpipe_init_notif_ring_aux(gxio_mpipe_context_t *context, void *mem_va, - size_t mem_size, unsigned int mem_flags, - unsigned int ring) -{ - int __result; - unsigned long long __cpa; - pte_t __pte; - struct init_notif_ring_aux_param temp; - struct init_notif_ring_aux_param *params = &temp; - - __result = va_to_cpa_and_pte(mem_va, &__cpa, &__pte); - if (__result != 0) - return __result; - params->buffer.kernel.cpa = __cpa; - params->buffer.kernel.size = mem_size; - params->buffer.kernel.pte = __pte; - params->buffer.kernel.flags = mem_flags; - params->ring = ring; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_MPIPE_OP_INIT_NOTIF_RING_AUX); -} - -EXPORT_SYMBOL(gxio_mpipe_init_notif_ring_aux); - -struct request_notif_ring_interrupt_param { - union iorpc_interrupt interrupt; - unsigned int ring; -}; - -int gxio_mpipe_request_notif_ring_interrupt(gxio_mpipe_context_t *context, - int inter_x, int inter_y, - int inter_ipi, int inter_event, - unsigned int ring) -{ - struct request_notif_ring_interrupt_param temp; - struct request_notif_ring_interrupt_param *params = &temp; - - params->interrupt.kernel.x = inter_x; - params->interrupt.kernel.y = inter_y; - params->interrupt.kernel.ipi = inter_ipi; - params->interrupt.kernel.event = inter_event; - params->ring = ring; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_MPIPE_OP_REQUEST_NOTIF_RING_INTERRUPT); -} - -EXPORT_SYMBOL(gxio_mpipe_request_notif_ring_interrupt); - -struct enable_notif_ring_interrupt_param { - unsigned int ring; -}; - -int gxio_mpipe_enable_notif_ring_interrupt(gxio_mpipe_context_t *context, - unsigned int ring) -{ - struct enable_notif_ring_interrupt_param temp; - struct enable_notif_ring_interrupt_param *params = &temp; - - params->ring = ring; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_MPIPE_OP_ENABLE_NOTIF_RING_INTERRUPT); -} - -EXPORT_SYMBOL(gxio_mpipe_enable_notif_ring_interrupt); - -struct alloc_notif_groups_param { - unsigned int count; - unsigned int first; - unsigned int flags; -}; - -int gxio_mpipe_alloc_notif_groups(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags) -{ - struct alloc_notif_groups_param temp; - struct alloc_notif_groups_param *params = &temp; - - params->count = count; - params->first = first; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_ALLOC_NOTIF_GROUPS); -} - -EXPORT_SYMBOL(gxio_mpipe_alloc_notif_groups); - -struct init_notif_group_param { - unsigned int group; - gxio_mpipe_notif_group_bits_t bits; -}; - -int gxio_mpipe_init_notif_group(gxio_mpipe_context_t *context, - unsigned int group, - gxio_mpipe_notif_group_bits_t bits) -{ - struct init_notif_group_param temp; - struct init_notif_group_param *params = &temp; - - params->group = group; - params->bits = bits; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_INIT_NOTIF_GROUP); -} - -EXPORT_SYMBOL(gxio_mpipe_init_notif_group); - -struct alloc_buckets_param { - unsigned int count; - unsigned int first; - unsigned int flags; -}; - -int gxio_mpipe_alloc_buckets(gxio_mpipe_context_t *context, unsigned int count, - unsigned int first, unsigned int flags) -{ - struct alloc_buckets_param temp; - struct alloc_buckets_param *params = &temp; - - params->count = count; - params->first = first; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_ALLOC_BUCKETS); -} - -EXPORT_SYMBOL(gxio_mpipe_alloc_buckets); - -struct init_bucket_param { - unsigned int bucket; - MPIPE_LBL_INIT_DAT_BSTS_TBL_t bucket_info; -}; - -int gxio_mpipe_init_bucket(gxio_mpipe_context_t *context, unsigned int bucket, - MPIPE_LBL_INIT_DAT_BSTS_TBL_t bucket_info) -{ - struct init_bucket_param temp; - struct init_bucket_param *params = &temp; - - params->bucket = bucket; - params->bucket_info = bucket_info; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_INIT_BUCKET); -} - -EXPORT_SYMBOL(gxio_mpipe_init_bucket); - -struct alloc_edma_rings_param { - unsigned int count; - unsigned int first; - unsigned int flags; -}; - -int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags) -{ - struct alloc_edma_rings_param temp; - struct alloc_edma_rings_param *params = &temp; - - params->count = count; - params->first = first; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_ALLOC_EDMA_RINGS); -} - -EXPORT_SYMBOL(gxio_mpipe_alloc_edma_rings); - -struct init_edma_ring_aux_param { - union iorpc_mem_buffer buffer; - unsigned int ring; - unsigned int channel; -}; - -int gxio_mpipe_init_edma_ring_aux(gxio_mpipe_context_t *context, void *mem_va, - size_t mem_size, unsigned int mem_flags, - unsigned int ring, unsigned int channel) -{ - int __result; - unsigned long long __cpa; - pte_t __pte; - struct init_edma_ring_aux_param temp; - struct init_edma_ring_aux_param *params = &temp; - - __result = va_to_cpa_and_pte(mem_va, &__cpa, &__pte); - if (__result != 0) - return __result; - params->buffer.kernel.cpa = __cpa; - params->buffer.kernel.size = mem_size; - params->buffer.kernel.pte = __pte; - params->buffer.kernel.flags = mem_flags; - params->ring = ring; - params->channel = channel; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_INIT_EDMA_RING_AUX); -} - -EXPORT_SYMBOL(gxio_mpipe_init_edma_ring_aux); - - -int gxio_mpipe_commit_rules(gxio_mpipe_context_t *context, const void *blob, - size_t blob_size) -{ - const void *params = blob; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, blob_size, - GXIO_MPIPE_OP_COMMIT_RULES); -} - -EXPORT_SYMBOL(gxio_mpipe_commit_rules); - -struct register_client_memory_param { - unsigned int iotlb; - HV_PTE pte; - unsigned int flags; -}; - -int gxio_mpipe_register_client_memory(gxio_mpipe_context_t *context, - unsigned int iotlb, HV_PTE pte, - unsigned int flags) -{ - struct register_client_memory_param temp; - struct register_client_memory_param *params = &temp; - - params->iotlb = iotlb; - params->pte = pte; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_MPIPE_OP_REGISTER_CLIENT_MEMORY); -} - -EXPORT_SYMBOL(gxio_mpipe_register_client_memory); - -struct link_open_aux_param { - _gxio_mpipe_link_name_t name; - unsigned int flags; -}; - -int gxio_mpipe_link_open_aux(gxio_mpipe_context_t *context, - _gxio_mpipe_link_name_t name, unsigned int flags) -{ - struct link_open_aux_param temp; - struct link_open_aux_param *params = &temp; - - params->name = name; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_LINK_OPEN_AUX); -} - -EXPORT_SYMBOL(gxio_mpipe_link_open_aux); - -struct link_close_aux_param { - int mac; -}; - -int gxio_mpipe_link_close_aux(gxio_mpipe_context_t *context, int mac) -{ - struct link_close_aux_param temp; - struct link_close_aux_param *params = &temp; - - params->mac = mac; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_LINK_CLOSE_AUX); -} - -EXPORT_SYMBOL(gxio_mpipe_link_close_aux); - -struct link_set_attr_aux_param { - int mac; - uint32_t attr; - int64_t val; -}; - -int gxio_mpipe_link_set_attr_aux(gxio_mpipe_context_t *context, int mac, - uint32_t attr, int64_t val) -{ - struct link_set_attr_aux_param temp; - struct link_set_attr_aux_param *params = &temp; - - params->mac = mac; - params->attr = attr; - params->val = val; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_LINK_SET_ATTR_AUX); -} - -EXPORT_SYMBOL(gxio_mpipe_link_set_attr_aux); - -struct get_timestamp_aux_param { - uint64_t sec; - uint64_t nsec; - uint64_t cycles; -}; - -int gxio_mpipe_get_timestamp_aux(gxio_mpipe_context_t *context, uint64_t *sec, - uint64_t *nsec, uint64_t *cycles) -{ - int __result; - struct get_timestamp_aux_param temp; - struct get_timestamp_aux_param *params = &temp; - - __result = - hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params), - GXIO_MPIPE_OP_GET_TIMESTAMP_AUX); - *sec = params->sec; - *nsec = params->nsec; - *cycles = params->cycles; - - return __result; -} - -EXPORT_SYMBOL(gxio_mpipe_get_timestamp_aux); - -struct set_timestamp_aux_param { - uint64_t sec; - uint64_t nsec; - uint64_t cycles; -}; - -int gxio_mpipe_set_timestamp_aux(gxio_mpipe_context_t *context, uint64_t sec, - uint64_t nsec, uint64_t cycles) -{ - struct set_timestamp_aux_param temp; - struct set_timestamp_aux_param *params = &temp; - - params->sec = sec; - params->nsec = nsec; - params->cycles = cycles; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_SET_TIMESTAMP_AUX); -} - -EXPORT_SYMBOL(gxio_mpipe_set_timestamp_aux); - -struct adjust_timestamp_aux_param { - int64_t nsec; -}; - -int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t *context, int64_t nsec) -{ - struct adjust_timestamp_aux_param temp; - struct adjust_timestamp_aux_param *params = &temp; - - params->nsec = nsec; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_MPIPE_OP_ADJUST_TIMESTAMP_AUX); -} - -EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_aux); - -struct config_edma_ring_blks_param { - unsigned int ering; - unsigned int max_blks; - unsigned int min_snf_blks; - unsigned int db; -}; - -int gxio_mpipe_config_edma_ring_blks(gxio_mpipe_context_t *context, - unsigned int ering, unsigned int max_blks, - unsigned int min_snf_blks, unsigned int db) -{ - struct config_edma_ring_blks_param temp; - struct config_edma_ring_blks_param *params = &temp; - - params->ering = ering; - params->max_blks = max_blks; - params->min_snf_blks = min_snf_blks; - params->db = db; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_MPIPE_OP_CONFIG_EDMA_RING_BLKS); -} - -EXPORT_SYMBOL(gxio_mpipe_config_edma_ring_blks); - -struct adjust_timestamp_freq_param { - int32_t ppb; -}; - -int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t *context, int32_t ppb) -{ - struct adjust_timestamp_freq_param temp; - struct adjust_timestamp_freq_param *params = &temp; - - params->ppb = ppb; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_MPIPE_OP_ADJUST_TIMESTAMP_FREQ); -} - -EXPORT_SYMBOL(gxio_mpipe_adjust_timestamp_freq); - -struct arm_pollfd_param { - union iorpc_pollfd pollfd; -}; - -int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t *context, int pollfd_cookie) -{ - struct arm_pollfd_param temp; - struct arm_pollfd_param *params = &temp; - - params->pollfd.kernel.cookie = pollfd_cookie; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_ARM_POLLFD); -} - -EXPORT_SYMBOL(gxio_mpipe_arm_pollfd); - -struct close_pollfd_param { - union iorpc_pollfd pollfd; -}; - -int gxio_mpipe_close_pollfd(gxio_mpipe_context_t *context, int pollfd_cookie) -{ - struct close_pollfd_param temp; - struct close_pollfd_param *params = &temp; - - params->pollfd.kernel.cookie = pollfd_cookie; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_CLOSE_POLLFD); -} - -EXPORT_SYMBOL(gxio_mpipe_close_pollfd); - -struct get_mmio_base_param { - HV_PTE base; -}; - -int gxio_mpipe_get_mmio_base(gxio_mpipe_context_t *context, HV_PTE *base) -{ - int __result; - struct get_mmio_base_param temp; - struct get_mmio_base_param *params = &temp; - - __result = - hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params), - GXIO_MPIPE_OP_GET_MMIO_BASE); - *base = params->base; - - return __result; -} - -EXPORT_SYMBOL(gxio_mpipe_get_mmio_base); - -struct check_mmio_offset_param { - unsigned long offset; - unsigned long size; -}; - -int gxio_mpipe_check_mmio_offset(gxio_mpipe_context_t *context, - unsigned long offset, unsigned long size) -{ - struct check_mmio_offset_param temp; - struct check_mmio_offset_param *params = &temp; - - params->offset = offset; - params->size = size; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_OP_CHECK_MMIO_OFFSET); -} - -EXPORT_SYMBOL(gxio_mpipe_check_mmio_offset); diff --git a/arch/tile/gxio/iorpc_mpipe_info.c b/arch/tile/gxio/iorpc_mpipe_info.c deleted file mode 100644 index 77019c6e9b4a..000000000000 --- a/arch/tile/gxio/iorpc_mpipe_info.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#include "gxio/iorpc_mpipe_info.h" - -struct instance_aux_param { - _gxio_mpipe_link_name_t name; -}; - -int gxio_mpipe_info_instance_aux(gxio_mpipe_info_context_t *context, - _gxio_mpipe_link_name_t name) -{ - struct instance_aux_param temp; - struct instance_aux_param *params = &temp; - - params->name = name; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_MPIPE_INFO_OP_INSTANCE_AUX); -} - -EXPORT_SYMBOL(gxio_mpipe_info_instance_aux); - -struct enumerate_aux_param { - _gxio_mpipe_link_name_t name; - _gxio_mpipe_link_mac_t mac; -}; - -int gxio_mpipe_info_enumerate_aux(gxio_mpipe_info_context_t *context, - unsigned int idx, - _gxio_mpipe_link_name_t *name, - _gxio_mpipe_link_mac_t *mac) -{ - int __result; - struct enumerate_aux_param temp; - struct enumerate_aux_param *params = &temp; - - __result = - hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params), - (((uint64_t)idx << 32) | - GXIO_MPIPE_INFO_OP_ENUMERATE_AUX)); - *name = params->name; - *mac = params->mac; - - return __result; -} - -EXPORT_SYMBOL(gxio_mpipe_info_enumerate_aux); - -struct get_mmio_base_param { - HV_PTE base; -}; - -int gxio_mpipe_info_get_mmio_base(gxio_mpipe_info_context_t *context, - HV_PTE *base) -{ - int __result; - struct get_mmio_base_param temp; - struct get_mmio_base_param *params = &temp; - - __result = - hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params), - GXIO_MPIPE_INFO_OP_GET_MMIO_BASE); - *base = params->base; - - return __result; -} - -EXPORT_SYMBOL(gxio_mpipe_info_get_mmio_base); - -struct check_mmio_offset_param { - unsigned long offset; - unsigned long size; -}; - -int gxio_mpipe_info_check_mmio_offset(gxio_mpipe_info_context_t *context, - unsigned long offset, unsigned long size) -{ - struct check_mmio_offset_param temp; - struct check_mmio_offset_param *params = &temp; - - params->offset = offset; - params->size = size; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_MPIPE_INFO_OP_CHECK_MMIO_OFFSET); -} - -EXPORT_SYMBOL(gxio_mpipe_info_check_mmio_offset); diff --git a/arch/tile/gxio/iorpc_trio.c b/arch/tile/gxio/iorpc_trio.c deleted file mode 100644 index 1d3cedb9aeb4..000000000000 --- a/arch/tile/gxio/iorpc_trio.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#include "gxio/iorpc_trio.h" - -struct alloc_asids_param { - unsigned int count; - unsigned int first; - unsigned int flags; -}; - -int gxio_trio_alloc_asids(gxio_trio_context_t *context, unsigned int count, - unsigned int first, unsigned int flags) -{ - struct alloc_asids_param temp; - struct alloc_asids_param *params = &temp; - - params->count = count; - params->first = first; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_TRIO_OP_ALLOC_ASIDS); -} - -EXPORT_SYMBOL(gxio_trio_alloc_asids); - - -struct alloc_memory_maps_param { - unsigned int count; - unsigned int first; - unsigned int flags; -}; - -int gxio_trio_alloc_memory_maps(gxio_trio_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags) -{ - struct alloc_memory_maps_param temp; - struct alloc_memory_maps_param *params = &temp; - - params->count = count; - params->first = first; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_TRIO_OP_ALLOC_MEMORY_MAPS); -} - -EXPORT_SYMBOL(gxio_trio_alloc_memory_maps); - -struct alloc_scatter_queues_param { - unsigned int count; - unsigned int first; - unsigned int flags; -}; - -int gxio_trio_alloc_scatter_queues(gxio_trio_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags) -{ - struct alloc_scatter_queues_param temp; - struct alloc_scatter_queues_param *params = &temp; - - params->count = count; - params->first = first; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_TRIO_OP_ALLOC_SCATTER_QUEUES); -} - -EXPORT_SYMBOL(gxio_trio_alloc_scatter_queues); - -struct alloc_pio_regions_param { - unsigned int count; - unsigned int first; - unsigned int flags; -}; - -int gxio_trio_alloc_pio_regions(gxio_trio_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags) -{ - struct alloc_pio_regions_param temp; - struct alloc_pio_regions_param *params = &temp; - - params->count = count; - params->first = first; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_TRIO_OP_ALLOC_PIO_REGIONS); -} - -EXPORT_SYMBOL(gxio_trio_alloc_pio_regions); - -struct init_pio_region_aux_param { - unsigned int pio_region; - unsigned int mac; - uint32_t bus_address_hi; - unsigned int flags; -}; - -int gxio_trio_init_pio_region_aux(gxio_trio_context_t *context, - unsigned int pio_region, unsigned int mac, - uint32_t bus_address_hi, unsigned int flags) -{ - struct init_pio_region_aux_param temp; - struct init_pio_region_aux_param *params = &temp; - - params->pio_region = pio_region; - params->mac = mac; - params->bus_address_hi = bus_address_hi; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_TRIO_OP_INIT_PIO_REGION_AUX); -} - -EXPORT_SYMBOL(gxio_trio_init_pio_region_aux); - - -struct init_memory_map_mmu_aux_param { - unsigned int map; - unsigned long va; - uint64_t size; - unsigned int asid; - unsigned int mac; - uint64_t bus_address; - unsigned int node; - unsigned int order_mode; -}; - -int gxio_trio_init_memory_map_mmu_aux(gxio_trio_context_t *context, - unsigned int map, unsigned long va, - uint64_t size, unsigned int asid, - unsigned int mac, uint64_t bus_address, - unsigned int node, - unsigned int order_mode) -{ - struct init_memory_map_mmu_aux_param temp; - struct init_memory_map_mmu_aux_param *params = &temp; - - params->map = map; - params->va = va; - params->size = size; - params->asid = asid; - params->mac = mac; - params->bus_address = bus_address; - params->node = node; - params->order_mode = order_mode; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_TRIO_OP_INIT_MEMORY_MAP_MMU_AUX); -} - -EXPORT_SYMBOL(gxio_trio_init_memory_map_mmu_aux); - -struct get_port_property_param { - struct pcie_trio_ports_property trio_ports; -}; - -int gxio_trio_get_port_property(gxio_trio_context_t *context, - struct pcie_trio_ports_property *trio_ports) -{ - int __result; - struct get_port_property_param temp; - struct get_port_property_param *params = &temp; - - __result = - hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params), - GXIO_TRIO_OP_GET_PORT_PROPERTY); - *trio_ports = params->trio_ports; - - return __result; -} - -EXPORT_SYMBOL(gxio_trio_get_port_property); - -struct config_legacy_intr_param { - union iorpc_interrupt interrupt; - unsigned int mac; - unsigned int intx; -}; - -int gxio_trio_config_legacy_intr(gxio_trio_context_t *context, int inter_x, - int inter_y, int inter_ipi, int inter_event, - unsigned int mac, unsigned int intx) -{ - struct config_legacy_intr_param temp; - struct config_legacy_intr_param *params = &temp; - - params->interrupt.kernel.x = inter_x; - params->interrupt.kernel.y = inter_y; - params->interrupt.kernel.ipi = inter_ipi; - params->interrupt.kernel.event = inter_event; - params->mac = mac; - params->intx = intx; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_TRIO_OP_CONFIG_LEGACY_INTR); -} - -EXPORT_SYMBOL(gxio_trio_config_legacy_intr); - -struct config_msi_intr_param { - union iorpc_interrupt interrupt; - unsigned int mac; - unsigned int mem_map; - uint64_t mem_map_base; - uint64_t mem_map_limit; - unsigned int asid; -}; - -int gxio_trio_config_msi_intr(gxio_trio_context_t *context, int inter_x, - int inter_y, int inter_ipi, int inter_event, - unsigned int mac, unsigned int mem_map, - uint64_t mem_map_base, uint64_t mem_map_limit, - unsigned int asid) -{ - struct config_msi_intr_param temp; - struct config_msi_intr_param *params = &temp; - - params->interrupt.kernel.x = inter_x; - params->interrupt.kernel.y = inter_y; - params->interrupt.kernel.ipi = inter_ipi; - params->interrupt.kernel.event = inter_event; - params->mac = mac; - params->mem_map = mem_map; - params->mem_map_base = mem_map_base; - params->mem_map_limit = mem_map_limit; - params->asid = asid; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_TRIO_OP_CONFIG_MSI_INTR); -} - -EXPORT_SYMBOL(gxio_trio_config_msi_intr); - - -struct set_mps_mrs_param { - uint16_t mps; - uint16_t mrs; - unsigned int mac; -}; - -int gxio_trio_set_mps_mrs(gxio_trio_context_t *context, uint16_t mps, - uint16_t mrs, unsigned int mac) -{ - struct set_mps_mrs_param temp; - struct set_mps_mrs_param *params = &temp; - - params->mps = mps; - params->mrs = mrs; - params->mac = mac; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_TRIO_OP_SET_MPS_MRS); -} - -EXPORT_SYMBOL(gxio_trio_set_mps_mrs); - -struct force_rc_link_up_param { - unsigned int mac; -}; - -int gxio_trio_force_rc_link_up(gxio_trio_context_t *context, unsigned int mac) -{ - struct force_rc_link_up_param temp; - struct force_rc_link_up_param *params = &temp; - - params->mac = mac; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_TRIO_OP_FORCE_RC_LINK_UP); -} - -EXPORT_SYMBOL(gxio_trio_force_rc_link_up); - -struct force_ep_link_up_param { - unsigned int mac; -}; - -int gxio_trio_force_ep_link_up(gxio_trio_context_t *context, unsigned int mac) -{ - struct force_ep_link_up_param temp; - struct force_ep_link_up_param *params = &temp; - - params->mac = mac; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_TRIO_OP_FORCE_EP_LINK_UP); -} - -EXPORT_SYMBOL(gxio_trio_force_ep_link_up); - -struct get_mmio_base_param { - HV_PTE base; -}; - -int gxio_trio_get_mmio_base(gxio_trio_context_t *context, HV_PTE *base) -{ - int __result; - struct get_mmio_base_param temp; - struct get_mmio_base_param *params = &temp; - - __result = - hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params), - GXIO_TRIO_OP_GET_MMIO_BASE); - *base = params->base; - - return __result; -} - -EXPORT_SYMBOL(gxio_trio_get_mmio_base); - -struct check_mmio_offset_param { - unsigned long offset; - unsigned long size; -}; - -int gxio_trio_check_mmio_offset(gxio_trio_context_t *context, - unsigned long offset, unsigned long size) -{ - struct check_mmio_offset_param temp; - struct check_mmio_offset_param *params = &temp; - - params->offset = offset; - params->size = size; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_TRIO_OP_CHECK_MMIO_OFFSET); -} - -EXPORT_SYMBOL(gxio_trio_check_mmio_offset); diff --git a/arch/tile/gxio/iorpc_uart.c b/arch/tile/gxio/iorpc_uart.c deleted file mode 100644 index b9a6d6193d73..000000000000 --- a/arch/tile/gxio/iorpc_uart.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#include "gxio/iorpc_uart.h" - -struct cfg_interrupt_param { - union iorpc_interrupt interrupt; -}; - -int gxio_uart_cfg_interrupt(gxio_uart_context_t *context, int inter_x, - int inter_y, int inter_ipi, int inter_event) -{ - struct cfg_interrupt_param temp; - struct cfg_interrupt_param *params = &temp; - - params->interrupt.kernel.x = inter_x; - params->interrupt.kernel.y = inter_y; - params->interrupt.kernel.ipi = inter_ipi; - params->interrupt.kernel.event = inter_event; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_UART_OP_CFG_INTERRUPT); -} - -EXPORT_SYMBOL(gxio_uart_cfg_interrupt); - -struct get_mmio_base_param { - HV_PTE base; -}; - -int gxio_uart_get_mmio_base(gxio_uart_context_t *context, HV_PTE *base) -{ - int __result; - struct get_mmio_base_param temp; - struct get_mmio_base_param *params = &temp; - - __result = - hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params), - GXIO_UART_OP_GET_MMIO_BASE); - *base = params->base; - - return __result; -} - -EXPORT_SYMBOL(gxio_uart_get_mmio_base); - -struct check_mmio_offset_param { - unsigned long offset; - unsigned long size; -}; - -int gxio_uart_check_mmio_offset(gxio_uart_context_t *context, - unsigned long offset, unsigned long size) -{ - struct check_mmio_offset_param temp; - struct check_mmio_offset_param *params = &temp; - - params->offset = offset; - params->size = size; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_UART_OP_CHECK_MMIO_OFFSET); -} - -EXPORT_SYMBOL(gxio_uart_check_mmio_offset); diff --git a/arch/tile/gxio/iorpc_usb_host.c b/arch/tile/gxio/iorpc_usb_host.c deleted file mode 100644 index 9c820073bfc0..000000000000 --- a/arch/tile/gxio/iorpc_usb_host.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#include "gxio/iorpc_usb_host.h" - -struct cfg_interrupt_param { - union iorpc_interrupt interrupt; -}; - -int gxio_usb_host_cfg_interrupt(gxio_usb_host_context_t *context, int inter_x, - int inter_y, int inter_ipi, int inter_event) -{ - struct cfg_interrupt_param temp; - struct cfg_interrupt_param *params = &temp; - - params->interrupt.kernel.x = inter_x; - params->interrupt.kernel.y = inter_y; - params->interrupt.kernel.ipi = inter_ipi; - params->interrupt.kernel.event = inter_event; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), GXIO_USB_HOST_OP_CFG_INTERRUPT); -} - -EXPORT_SYMBOL(gxio_usb_host_cfg_interrupt); - -struct register_client_memory_param { - HV_PTE pte; - unsigned int flags; -}; - -int gxio_usb_host_register_client_memory(gxio_usb_host_context_t *context, - HV_PTE pte, unsigned int flags) -{ - struct register_client_memory_param temp; - struct register_client_memory_param *params = &temp; - - params->pte = pte; - params->flags = flags; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_USB_HOST_OP_REGISTER_CLIENT_MEMORY); -} - -EXPORT_SYMBOL(gxio_usb_host_register_client_memory); - -struct get_mmio_base_param { - HV_PTE base; -}; - -int gxio_usb_host_get_mmio_base(gxio_usb_host_context_t *context, HV_PTE *base) -{ - int __result; - struct get_mmio_base_param temp; - struct get_mmio_base_param *params = &temp; - - __result = - hv_dev_pread(context->fd, 0, (HV_VirtAddr) params, sizeof(*params), - GXIO_USB_HOST_OP_GET_MMIO_BASE); - *base = params->base; - - return __result; -} - -EXPORT_SYMBOL(gxio_usb_host_get_mmio_base); - -struct check_mmio_offset_param { - unsigned long offset; - unsigned long size; -}; - -int gxio_usb_host_check_mmio_offset(gxio_usb_host_context_t *context, - unsigned long offset, unsigned long size) -{ - struct check_mmio_offset_param temp; - struct check_mmio_offset_param *params = &temp; - - params->offset = offset; - params->size = size; - - return hv_dev_pwrite(context->fd, 0, (HV_VirtAddr) params, - sizeof(*params), - GXIO_USB_HOST_OP_CHECK_MMIO_OFFSET); -} - -EXPORT_SYMBOL(gxio_usb_host_check_mmio_offset); diff --git a/arch/tile/gxio/kiorpc.c b/arch/tile/gxio/kiorpc.c deleted file mode 100644 index c8096aa5a3fc..000000000000 --- a/arch/tile/gxio/kiorpc.c +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * TILE-Gx IORPC support for kernel I/O drivers. - */ - -#include -#include -#include -#include -#include - -#ifdef DEBUG_IORPC -#define TRACE(FMT, ...) pr_info(SIMPLE_MSG_LINE FMT, ## __VA_ARGS__) -#else -#define TRACE(...) -#endif - -/* Create kernel-VA-space MMIO mapping for an on-chip IO device. */ -void __iomem *iorpc_ioremap(int hv_fd, resource_size_t offset, - unsigned long size) -{ - pgprot_t mmio_base, prot = { 0 }; - unsigned long pfn; - int err; - - /* Look up the shim's lotar and base PA. */ - err = __iorpc_get_mmio_base(hv_fd, &mmio_base); - if (err) { - TRACE("get_mmio_base() failure: %d\n", err); - return NULL; - } - - /* Make sure the HV driver approves of our offset and size. */ - err = __iorpc_check_mmio_offset(hv_fd, offset, size); - if (err) { - TRACE("check_mmio_offset() failure: %d\n", err); - return NULL; - } - - /* - * mmio_base contains a base pfn and homing coordinates. Turn - * it into an MMIO pgprot and offset pfn. - */ - prot = hv_pte_set_lotar(prot, hv_pte_get_lotar(mmio_base)); - pfn = pte_pfn(mmio_base) + PFN_DOWN(offset); - - return ioremap_prot(PFN_PHYS(pfn), size, prot); -} - -EXPORT_SYMBOL(iorpc_ioremap); diff --git a/arch/tile/gxio/mpipe.c b/arch/tile/gxio/mpipe.c deleted file mode 100644 index 34de300ab320..000000000000 --- a/arch/tile/gxio/mpipe.c +++ /dev/null @@ -1,584 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* - * Implementation of mpipe gxio calls. - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -/* HACK: Avoid pointless "shadow" warnings. */ -#define link link_shadow - -int gxio_mpipe_init(gxio_mpipe_context_t *context, unsigned int mpipe_index) -{ - char file[32]; - - int fd; - int i; - - if (mpipe_index >= GXIO_MPIPE_INSTANCE_MAX) - return -EINVAL; - - snprintf(file, sizeof(file), "mpipe/%d/iorpc", mpipe_index); - fd = hv_dev_open((HV_VirtAddr) file, 0); - - context->fd = fd; - - if (fd < 0) { - if (fd >= GXIO_ERR_MIN && fd <= GXIO_ERR_MAX) - return fd; - else - return -ENODEV; - } - - /* Map in the MMIO space. */ - context->mmio_cfg_base = (void __force *) - iorpc_ioremap(fd, HV_MPIPE_CONFIG_MMIO_OFFSET, - HV_MPIPE_CONFIG_MMIO_SIZE); - if (context->mmio_cfg_base == NULL) - goto cfg_failed; - - context->mmio_fast_base = (void __force *) - iorpc_ioremap(fd, HV_MPIPE_FAST_MMIO_OFFSET, - HV_MPIPE_FAST_MMIO_SIZE); - if (context->mmio_fast_base == NULL) - goto fast_failed; - - /* Initialize the stacks. */ - for (i = 0; i < 8; i++) - context->__stacks.stacks[i] = 255; - - context->instance = mpipe_index; - - return 0; - - fast_failed: - iounmap((void __force __iomem *)(context->mmio_cfg_base)); - cfg_failed: - hv_dev_close(context->fd); - context->fd = -1; - return -ENODEV; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_init); - -int gxio_mpipe_destroy(gxio_mpipe_context_t *context) -{ - iounmap((void __force __iomem *)(context->mmio_cfg_base)); - iounmap((void __force __iomem *)(context->mmio_fast_base)); - return hv_dev_close(context->fd); -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_destroy); - -static int16_t gxio_mpipe_buffer_sizes[8] = - { 128, 256, 512, 1024, 1664, 4096, 10368, 16384 }; - -gxio_mpipe_buffer_size_enum_t gxio_mpipe_buffer_size_to_buffer_size_enum(size_t - size) -{ - int i; - for (i = 0; i < 7; i++) - if (size <= gxio_mpipe_buffer_sizes[i]) - break; - return i; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_buffer_size_to_buffer_size_enum); - -size_t gxio_mpipe_buffer_size_enum_to_buffer_size(gxio_mpipe_buffer_size_enum_t - buffer_size_enum) -{ - if (buffer_size_enum > 7) - buffer_size_enum = 7; - - return gxio_mpipe_buffer_sizes[buffer_size_enum]; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_buffer_size_enum_to_buffer_size); - -size_t gxio_mpipe_calc_buffer_stack_bytes(unsigned long buffers) -{ - const int BUFFERS_PER_LINE = 12; - - /* Count the number of cachelines. */ - unsigned long lines = - (buffers + BUFFERS_PER_LINE - 1) / BUFFERS_PER_LINE; - - /* Convert to bytes. */ - return lines * CHIP_L2_LINE_SIZE(); -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_calc_buffer_stack_bytes); - -int gxio_mpipe_init_buffer_stack(gxio_mpipe_context_t *context, - unsigned int stack, - gxio_mpipe_buffer_size_enum_t - buffer_size_enum, void *mem, size_t mem_size, - unsigned int mem_flags) -{ - int result; - - memset(mem, 0, mem_size); - - result = gxio_mpipe_init_buffer_stack_aux(context, mem, mem_size, - mem_flags, stack, - buffer_size_enum); - if (result < 0) - return result; - - /* Save the stack. */ - context->__stacks.stacks[buffer_size_enum] = stack; - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_init_buffer_stack); - -int gxio_mpipe_init_notif_ring(gxio_mpipe_context_t *context, - unsigned int ring, - void *mem, size_t mem_size, - unsigned int mem_flags) -{ - return gxio_mpipe_init_notif_ring_aux(context, mem, mem_size, - mem_flags, ring); -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_init_notif_ring); - -int gxio_mpipe_init_notif_group_and_buckets(gxio_mpipe_context_t *context, - unsigned int group, - unsigned int ring, - unsigned int num_rings, - unsigned int bucket, - unsigned int num_buckets, - gxio_mpipe_bucket_mode_t mode) -{ - int i; - int result; - - gxio_mpipe_bucket_info_t bucket_info = { { - .group = group, - .mode = mode, - } - }; - - gxio_mpipe_notif_group_bits_t bits = { {0} }; - - for (i = 0; i < num_rings; i++) - gxio_mpipe_notif_group_add_ring(&bits, ring + i); - - result = gxio_mpipe_init_notif_group(context, group, bits); - if (result != 0) - return result; - - for (i = 0; i < num_buckets; i++) { - bucket_info.notifring = ring + (i % num_rings); - - result = gxio_mpipe_init_bucket(context, bucket + i, - bucket_info); - if (result != 0) - return result; - } - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_init_notif_group_and_buckets); - -int gxio_mpipe_init_edma_ring(gxio_mpipe_context_t *context, - unsigned int ring, unsigned int channel, - void *mem, size_t mem_size, - unsigned int mem_flags) -{ - memset(mem, 0, mem_size); - - return gxio_mpipe_init_edma_ring_aux(context, mem, mem_size, mem_flags, - ring, channel); -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_init_edma_ring); - -void gxio_mpipe_rules_init(gxio_mpipe_rules_t *rules, - gxio_mpipe_context_t *context) -{ - rules->context = context; - memset(&rules->list, 0, sizeof(rules->list)); -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_rules_init); - -int gxio_mpipe_rules_begin(gxio_mpipe_rules_t *rules, - unsigned int bucket, unsigned int num_buckets, - gxio_mpipe_rules_stacks_t *stacks) -{ - int i; - int stack = 255; - - gxio_mpipe_rules_list_t *list = &rules->list; - - /* Current rule. */ - gxio_mpipe_rules_rule_t *rule = - (gxio_mpipe_rules_rule_t *) (list->rules + list->head); - - unsigned int head = list->tail; - - /* - * Align next rule properly. - *Note that "dmacs_and_vlans" will also be aligned. - */ - unsigned int pad = 0; - while (((head + pad) % __alignof__(gxio_mpipe_rules_rule_t)) != 0) - pad++; - - /* - * Verify room. - * ISSUE: Mark rules as broken on error? - */ - if (head + pad + sizeof(*rule) >= sizeof(list->rules)) - return GXIO_MPIPE_ERR_RULES_FULL; - - /* Verify num_buckets is a power of 2. */ - if (__builtin_popcount(num_buckets) != 1) - return GXIO_MPIPE_ERR_RULES_INVALID; - - /* Add padding to previous rule. */ - rule->size += pad; - - /* Start a new rule. */ - list->head = head + pad; - - rule = (gxio_mpipe_rules_rule_t *) (list->rules + list->head); - - /* Default some values. */ - rule->headroom = 2; - rule->tailroom = 0; - rule->capacity = 16384; - - /* Save the bucket info. */ - rule->bucket_mask = num_buckets - 1; - rule->bucket_first = bucket; - - for (i = 8 - 1; i >= 0; i--) { - int maybe = - stacks ? stacks->stacks[i] : rules->context->__stacks. - stacks[i]; - if (maybe != 255) - stack = maybe; - rule->stacks.stacks[i] = stack; - } - - if (stack == 255) - return GXIO_MPIPE_ERR_RULES_INVALID; - - /* NOTE: Only entries at the end of the array can be 255. */ - for (i = 8 - 1; i > 0; i--) { - if (rule->stacks.stacks[i] == 255) { - rule->stacks.stacks[i] = stack; - rule->capacity = - gxio_mpipe_buffer_size_enum_to_buffer_size(i - - 1); - } - } - - rule->size = sizeof(*rule); - list->tail = list->head + rule->size; - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_rules_begin); - -int gxio_mpipe_rules_add_channel(gxio_mpipe_rules_t *rules, - unsigned int channel) -{ - gxio_mpipe_rules_list_t *list = &rules->list; - - gxio_mpipe_rules_rule_t *rule = - (gxio_mpipe_rules_rule_t *) (list->rules + list->head); - - /* Verify channel. */ - if (channel >= 32) - return GXIO_MPIPE_ERR_RULES_INVALID; - - /* Verify begun. */ - if (list->tail == 0) - return GXIO_MPIPE_ERR_RULES_EMPTY; - - rule->channel_bits |= (1UL << channel); - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_rules_add_channel); - -int gxio_mpipe_rules_set_headroom(gxio_mpipe_rules_t *rules, uint8_t headroom) -{ - gxio_mpipe_rules_list_t *list = &rules->list; - - gxio_mpipe_rules_rule_t *rule = - (gxio_mpipe_rules_rule_t *) (list->rules + list->head); - - /* Verify begun. */ - if (list->tail == 0) - return GXIO_MPIPE_ERR_RULES_EMPTY; - - rule->headroom = headroom; - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_rules_set_headroom); - -int gxio_mpipe_rules_commit(gxio_mpipe_rules_t *rules) -{ - gxio_mpipe_rules_list_t *list = &rules->list; - unsigned int size = - offsetof(gxio_mpipe_rules_list_t, rules) + list->tail; - return gxio_mpipe_commit_rules(rules->context, list, size); -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_rules_commit); - -int gxio_mpipe_iqueue_init(gxio_mpipe_iqueue_t *iqueue, - gxio_mpipe_context_t *context, - unsigned int ring, - void *mem, size_t mem_size, unsigned int mem_flags) -{ - /* The init call below will verify that "mem_size" is legal. */ - unsigned int num_entries = mem_size / sizeof(gxio_mpipe_idesc_t); - - iqueue->context = context; - iqueue->idescs = (gxio_mpipe_idesc_t *)mem; - iqueue->ring = ring; - iqueue->num_entries = num_entries; - iqueue->mask_num_entries = num_entries - 1; - iqueue->log2_num_entries = __builtin_ctz(num_entries); - iqueue->head = 1; -#ifdef __BIG_ENDIAN__ - iqueue->swapped = 0; -#endif - - /* Initialize the "tail". */ - __gxio_mmio_write(mem, iqueue->head); - - return gxio_mpipe_init_notif_ring(context, ring, mem, mem_size, - mem_flags); -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_iqueue_init); - -int gxio_mpipe_equeue_init(gxio_mpipe_equeue_t *equeue, - gxio_mpipe_context_t *context, - unsigned int ering, - unsigned int channel, - void *mem, unsigned int mem_size, - unsigned int mem_flags) -{ - /* The init call below will verify that "mem_size" is legal. */ - unsigned int num_entries = mem_size / sizeof(gxio_mpipe_edesc_t); - - /* Offset used to read number of completed commands. */ - MPIPE_EDMA_POST_REGION_ADDR_t offset; - - int result = gxio_mpipe_init_edma_ring(context, ering, channel, - mem, mem_size, mem_flags); - if (result < 0) - return result; - - memset(equeue, 0, sizeof(*equeue)); - - offset.word = 0; - offset.region = - MPIPE_MMIO_ADDR__REGION_VAL_EDMA - - MPIPE_MMIO_ADDR__REGION_VAL_IDMA; - offset.ring = ering; - - __gxio_dma_queue_init(&equeue->dma_queue, - context->mmio_fast_base + offset.word, - num_entries); - equeue->edescs = mem; - equeue->mask_num_entries = num_entries - 1; - equeue->log2_num_entries = __builtin_ctz(num_entries); - equeue->context = context; - equeue->ering = ering; - equeue->channel = channel; - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_equeue_init); - -int gxio_mpipe_set_timestamp(gxio_mpipe_context_t *context, - const struct timespec64 *ts) -{ - cycles_t cycles = get_cycles(); - return gxio_mpipe_set_timestamp_aux(context, (uint64_t)ts->tv_sec, - (uint64_t)ts->tv_nsec, - (uint64_t)cycles); -} -EXPORT_SYMBOL_GPL(gxio_mpipe_set_timestamp); - -int gxio_mpipe_get_timestamp(gxio_mpipe_context_t *context, - struct timespec64 *ts) -{ - int ret; - cycles_t cycles_prev, cycles_now, clock_rate; - cycles_prev = get_cycles(); - ret = gxio_mpipe_get_timestamp_aux(context, (uint64_t *)&ts->tv_sec, - (uint64_t *)&ts->tv_nsec, - (uint64_t *)&cycles_now); - if (ret < 0) { - return ret; - } - - clock_rate = get_clock_rate(); - ts->tv_nsec -= (cycles_now - cycles_prev) * 1000000000LL / clock_rate; - if (ts->tv_nsec < 0) { - ts->tv_nsec += 1000000000LL; - ts->tv_sec -= 1; - } - return ret; -} -EXPORT_SYMBOL_GPL(gxio_mpipe_get_timestamp); - -int gxio_mpipe_adjust_timestamp(gxio_mpipe_context_t *context, int64_t delta) -{ - return gxio_mpipe_adjust_timestamp_aux(context, delta); -} -EXPORT_SYMBOL_GPL(gxio_mpipe_adjust_timestamp); - -/* Get our internal context used for link name access. This context is - * special in that it is not associated with an mPIPE service domain. - */ -static gxio_mpipe_context_t *_gxio_get_link_context(void) -{ - static gxio_mpipe_context_t context; - static gxio_mpipe_context_t *contextp; - static int tried_open = 0; - static DEFINE_MUTEX(mutex); - - mutex_lock(&mutex); - - if (!tried_open) { - int i = 0; - tried_open = 1; - - /* - * "4" here is the maximum possible number of mPIPE shims; it's - * an exaggeration but we shouldn't ever go beyond 2 anyway. - */ - for (i = 0; i < 4; i++) { - char file[80]; - - snprintf(file, sizeof(file), "mpipe/%d/iorpc_info", i); - context.fd = hv_dev_open((HV_VirtAddr) file, 0); - if (context.fd < 0) - continue; - - contextp = &context; - break; - } - } - - mutex_unlock(&mutex); - - return contextp; -} - -int gxio_mpipe_link_instance(const char *link_name) -{ - _gxio_mpipe_link_name_t name; - gxio_mpipe_context_t *context = _gxio_get_link_context(); - - if (!context) - return GXIO_ERR_NO_DEVICE; - - if (strscpy(name.name, link_name, sizeof(name.name)) < 0) - return GXIO_ERR_NO_DEVICE; - - return gxio_mpipe_info_instance_aux(context, name); -} -EXPORT_SYMBOL_GPL(gxio_mpipe_link_instance); - -int gxio_mpipe_link_enumerate_mac(int idx, char *link_name, uint8_t *link_mac) -{ - int rv; - _gxio_mpipe_link_name_t name; - _gxio_mpipe_link_mac_t mac; - - gxio_mpipe_context_t *context = _gxio_get_link_context(); - if (!context) - return GXIO_ERR_NO_DEVICE; - - rv = gxio_mpipe_info_enumerate_aux(context, idx, &name, &mac); - if (rv >= 0) { - if (strscpy(link_name, name.name, sizeof(name.name)) < 0) - return GXIO_ERR_INVAL_MEMORY_SIZE; - memcpy(link_mac, mac.mac, sizeof(mac.mac)); - } - - return rv; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_link_enumerate_mac); - -int gxio_mpipe_link_open(gxio_mpipe_link_t *link, - gxio_mpipe_context_t *context, const char *link_name, - unsigned int flags) -{ - _gxio_mpipe_link_name_t name; - int rv; - - if (strscpy(name.name, link_name, sizeof(name.name)) < 0) - return GXIO_ERR_NO_DEVICE; - - rv = gxio_mpipe_link_open_aux(context, name, flags); - if (rv < 0) - return rv; - - link->context = context; - link->channel = rv >> 8; - link->mac = rv & 0xFF; - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_link_open); - -int gxio_mpipe_link_close(gxio_mpipe_link_t *link) -{ - return gxio_mpipe_link_close_aux(link->context, link->mac); -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_link_close); - -int gxio_mpipe_link_set_attr(gxio_mpipe_link_t *link, uint32_t attr, - int64_t val) -{ - return gxio_mpipe_link_set_attr_aux(link->context, link->mac, attr, - val); -} - -EXPORT_SYMBOL_GPL(gxio_mpipe_link_set_attr); diff --git a/arch/tile/gxio/trio.c b/arch/tile/gxio/trio.c deleted file mode 100644 index 69f0b8df3ce3..000000000000 --- a/arch/tile/gxio/trio.c +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* - * Implementation of trio gxio calls. - */ - -#include -#include -#include - -#include -#include -#include -#include - -int gxio_trio_init(gxio_trio_context_t *context, unsigned int trio_index) -{ - char file[32]; - int fd; - - snprintf(file, sizeof(file), "trio/%d/iorpc", trio_index); - fd = hv_dev_open((HV_VirtAddr) file, 0); - if (fd < 0) { - context->fd = -1; - - if (fd >= GXIO_ERR_MIN && fd <= GXIO_ERR_MAX) - return fd; - else - return -ENODEV; - } - - context->fd = fd; - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_trio_init); diff --git a/arch/tile/gxio/uart.c b/arch/tile/gxio/uart.c deleted file mode 100644 index ba585175ef88..000000000000 --- a/arch/tile/gxio/uart.c +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* - * Implementation of UART gxio calls. - */ - -#include -#include -#include - -#include -#include -#include -#include - -int gxio_uart_init(gxio_uart_context_t *context, int uart_index) -{ - char file[32]; - int fd; - - snprintf(file, sizeof(file), "uart/%d/iorpc", uart_index); - fd = hv_dev_open((HV_VirtAddr) file, 0); - if (fd < 0) { - if (fd >= GXIO_ERR_MIN && fd <= GXIO_ERR_MAX) - return fd; - else - return -ENODEV; - } - - context->fd = fd; - - /* Map in the MMIO space. */ - context->mmio_base = (void __force *) - iorpc_ioremap(fd, HV_UART_MMIO_OFFSET, HV_UART_MMIO_SIZE); - - if (context->mmio_base == NULL) { - hv_dev_close(context->fd); - context->fd = -1; - return -ENODEV; - } - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_uart_init); - -int gxio_uart_destroy(gxio_uart_context_t *context) -{ - iounmap((void __force __iomem *)(context->mmio_base)); - hv_dev_close(context->fd); - - context->mmio_base = NULL; - context->fd = -1; - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_uart_destroy); - -/* UART register write wrapper. */ -void gxio_uart_write(gxio_uart_context_t *context, uint64_t offset, - uint64_t word) -{ - __gxio_mmio_write(context->mmio_base + offset, word); -} - -EXPORT_SYMBOL_GPL(gxio_uart_write); - -/* UART register read wrapper. */ -uint64_t gxio_uart_read(gxio_uart_context_t *context, uint64_t offset) -{ - return __gxio_mmio_read(context->mmio_base + offset); -} - -EXPORT_SYMBOL_GPL(gxio_uart_read); diff --git a/arch/tile/gxio/usb_host.c b/arch/tile/gxio/usb_host.c deleted file mode 100644 index 785afad7922e..000000000000 --- a/arch/tile/gxio/usb_host.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* - * - * Implementation of USB gxio calls. - */ - -#include -#include -#include - -#include -#include -#include -#include - -int gxio_usb_host_init(gxio_usb_host_context_t *context, int usb_index, - int is_ehci) -{ - char file[32]; - int fd; - - if (is_ehci) - snprintf(file, sizeof(file), "usb_host/%d/iorpc/ehci", - usb_index); - else - snprintf(file, sizeof(file), "usb_host/%d/iorpc/ohci", - usb_index); - - fd = hv_dev_open((HV_VirtAddr) file, 0); - if (fd < 0) { - if (fd >= GXIO_ERR_MIN && fd <= GXIO_ERR_MAX) - return fd; - else - return -ENODEV; - } - - context->fd = fd; - - // Map in the MMIO space. - context->mmio_base = - (void __force *)iorpc_ioremap(fd, 0, HV_USB_HOST_MMIO_SIZE); - - if (context->mmio_base == NULL) { - hv_dev_close(context->fd); - return -ENODEV; - } - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_usb_host_init); - -int gxio_usb_host_destroy(gxio_usb_host_context_t *context) -{ - iounmap((void __force __iomem *)(context->mmio_base)); - hv_dev_close(context->fd); - - context->mmio_base = NULL; - context->fd = -1; - - return 0; -} - -EXPORT_SYMBOL_GPL(gxio_usb_host_destroy); - -void *gxio_usb_host_get_reg_start(gxio_usb_host_context_t *context) -{ - return context->mmio_base; -} - -EXPORT_SYMBOL_GPL(gxio_usb_host_get_reg_start); - -size_t gxio_usb_host_get_reg_len(gxio_usb_host_context_t *context) -{ - return HV_USB_HOST_MMIO_SIZE; -} - -EXPORT_SYMBOL_GPL(gxio_usb_host_get_reg_len); diff --git a/arch/tile/include/arch/mpipe.h b/arch/tile/include/arch/mpipe.h deleted file mode 100644 index 904538e754d8..000000000000 --- a/arch/tile/include/arch/mpipe.h +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_MPIPE_H__ -#define __ARCH_MPIPE_H__ - -#include -#include - -#ifndef __ASSEMBLER__ - -/* - * MMIO Ingress DMA Release Region Address. - * This is a description of the physical addresses used to manipulate ingress - * credit counters. Accesses to this address space should use an address of - * this form and a value like that specified in IDMA_RELEASE_REGION_VAL. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Reserved. */ - uint_reg_t __reserved_0 : 3; - /* NotifRing to be released */ - uint_reg_t ring : 8; - /* Bucket to be released */ - uint_reg_t bucket : 13; - /* Enable NotifRing release */ - uint_reg_t ring_enable : 1; - /* Enable Bucket release */ - uint_reg_t bucket_enable : 1; - /* - * This field of the address selects the region (address space) to be - * accessed. For the iDMA release region, this field must be 4. - */ - uint_reg_t region : 3; - /* Reserved. */ - uint_reg_t __reserved_1 : 6; - /* This field of the address indexes the 32 entry service domain table. */ - uint_reg_t svc_dom : 5; - /* Reserved. */ - uint_reg_t __reserved_2 : 24; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_2 : 24; - uint_reg_t svc_dom : 5; - uint_reg_t __reserved_1 : 6; - uint_reg_t region : 3; - uint_reg_t bucket_enable : 1; - uint_reg_t ring_enable : 1; - uint_reg_t bucket : 13; - uint_reg_t ring : 8; - uint_reg_t __reserved_0 : 3; -#endif - }; - - uint_reg_t word; -} MPIPE_IDMA_RELEASE_REGION_ADDR_t; - -/* - * MMIO Ingress DMA Release Region Value - Release NotifRing and/or Bucket. - * Provides release of the associated NotifRing. The address of the MMIO - * operation is described in IDMA_RELEASE_REGION_ADDR. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* - * Number of packets being released. The load balancer's count of - * inflight packets will be decremented by this amount for the associated - * Bucket and/or NotifRing - */ - uint_reg_t count : 16; - /* Reserved. */ - uint_reg_t __reserved : 48; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved : 48; - uint_reg_t count : 16; -#endif - }; - - uint_reg_t word; -} MPIPE_IDMA_RELEASE_REGION_VAL_t; - -/* - * MMIO Buffer Stack Manager Region Address. - * This MMIO region is used for posting or fetching buffers to/from the - * buffer stack manager. On an MMIO load, this pops a buffer descriptor from - * the top of stack if one is available. On an MMIO store, this pushes a - * buffer to the stack. The value read or written is described in - * BSM_REGION_VAL. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Reserved. */ - uint_reg_t __reserved_0 : 3; - /* BufferStack being accessed. */ - uint_reg_t stack : 5; - /* Reserved. */ - uint_reg_t __reserved_1 : 18; - /* - * This field of the address selects the region (address space) to be - * accessed. For the buffer stack manager region, this field must be 6. - */ - uint_reg_t region : 3; - /* Reserved. */ - uint_reg_t __reserved_2 : 6; - /* This field of the address indexes the 32 entry service domain table. */ - uint_reg_t svc_dom : 5; - /* Reserved. */ - uint_reg_t __reserved_3 : 24; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_3 : 24; - uint_reg_t svc_dom : 5; - uint_reg_t __reserved_2 : 6; - uint_reg_t region : 3; - uint_reg_t __reserved_1 : 18; - uint_reg_t stack : 5; - uint_reg_t __reserved_0 : 3; -#endif - }; - - uint_reg_t word; -} MPIPE_BSM_REGION_ADDR_t; - -/* - * MMIO Buffer Stack Manager Region Value. - * This MMIO region is used for posting or fetching buffers to/from the - * buffer stack manager. On an MMIO load, this pops a buffer descriptor from - * the top of stack if one is available. On an MMIO store, this pushes a - * buffer to the stack. The address of the MMIO operation is described in - * BSM_REGION_ADDR. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Reserved. */ - uint_reg_t __reserved_0 : 7; - /* - * Base virtual address of the buffer. Must be sign extended by consumer. - */ - int_reg_t va : 35; - /* Reserved. */ - uint_reg_t __reserved_1 : 6; - /* - * Index of the buffer stack to which this buffer belongs. Ignored on - * writes since the offset bits specify the stack being accessed. - */ - uint_reg_t stack_idx : 5; - /* Reserved. */ - uint_reg_t __reserved_2 : 3; - /* - * Instance ID. For devices that support automatic buffer return between - * mPIPE instances, this field indicates the buffer owner. If the INST - * field does not match the mPIPE's instance number when a packet is - * egressed, buffers with HWB set will be returned to the other mPIPE - * instance. Note that not all devices support multi-mPIPE buffer - * return. The MPIPE_EDMA_INFO.REMOTE_BUFF_RTN_SUPPORT bit indicates - * whether the INST field in the buffer descriptor is populated by iDMA - * hardware. This field is ignored on writes. - */ - uint_reg_t inst : 2; - /* - * Reads as one to indicate that this is a hardware managed buffer. - * Ignored on writes since all buffers on a given stack are the same size. - */ - uint_reg_t hwb : 1; - /* - * Encoded size of buffer (ignored on writes): - * 0 = 128 bytes - * 1 = 256 bytes - * 2 = 512 bytes - * 3 = 1024 bytes - * 4 = 1664 bytes - * 5 = 4096 bytes - * 6 = 10368 bytes - * 7 = 16384 bytes - */ - uint_reg_t size : 3; - /* - * Valid indication for the buffer. Ignored on writes. - * 0 : Valid buffer descriptor popped from stack. - * 3 : Could not pop a buffer from the stack. Either the stack is empty, - * or the hardware's prefetch buffer is empty for this stack. - */ - uint_reg_t c : 2; -#else /* __BIG_ENDIAN__ */ - uint_reg_t c : 2; - uint_reg_t size : 3; - uint_reg_t hwb : 1; - uint_reg_t inst : 2; - uint_reg_t __reserved_2 : 3; - uint_reg_t stack_idx : 5; - uint_reg_t __reserved_1 : 6; - int_reg_t va : 35; - uint_reg_t __reserved_0 : 7; -#endif - }; - - uint_reg_t word; -} MPIPE_BSM_REGION_VAL_t; - -/* - * MMIO Egress DMA Post Region Address. - * Used to post descriptor locations to the eDMA descriptor engine. The - * value to be written is described in EDMA_POST_REGION_VAL - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Reserved. */ - uint_reg_t __reserved_0 : 3; - /* eDMA ring being accessed */ - uint_reg_t ring : 6; - /* Reserved. */ - uint_reg_t __reserved_1 : 17; - /* - * This field of the address selects the region (address space) to be - * accessed. For the egress DMA post region, this field must be 5. - */ - uint_reg_t region : 3; - /* Reserved. */ - uint_reg_t __reserved_2 : 6; - /* This field of the address indexes the 32 entry service domain table. */ - uint_reg_t svc_dom : 5; - /* Reserved. */ - uint_reg_t __reserved_3 : 24; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_3 : 24; - uint_reg_t svc_dom : 5; - uint_reg_t __reserved_2 : 6; - uint_reg_t region : 3; - uint_reg_t __reserved_1 : 17; - uint_reg_t ring : 6; - uint_reg_t __reserved_0 : 3; -#endif - }; - - uint_reg_t word; -} MPIPE_EDMA_POST_REGION_ADDR_t; - -/* - * MMIO Egress DMA Post Region Value. - * Used to post descriptor locations to the eDMA descriptor engine. The - * address is described in EDMA_POST_REGION_ADDR. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* - * For writes, this specifies the current ring tail pointer prior to any - * post. For example, to post 1 or more descriptors starting at location - * 23, this would contain 23 (not 24). On writes, this index must be - * masked based on the ring size. The new tail pointer after this post - * is COUNT+RING_IDX (masked by the ring size). - * - * For reads, this provides the hardware descriptor fetcher's head - * pointer. The descriptors prior to the head pointer, however, may not - * yet have been processed so this indicator is only used to determine - * how full the ring is and if software may post more descriptors. - */ - uint_reg_t ring_idx : 16; - /* - * For writes, this specifies number of contiguous descriptors that are - * being posted. Software may post up to RingSize descriptors with a - * single MMIO store. A zero in this field on a write will "wake up" an - * eDMA ring and cause it fetch descriptors regardless of the hardware's - * current view of the state of the tail pointer. - * - * For reads, this field provides a rolling count of the number of - * descriptors that have been completely processed. This may be used by - * software to determine when buffers associated with a descriptor may be - * returned or reused. When the ring's flush bit is cleared by software - * (after having been set by HW or SW), the COUNT will be cleared. - */ - uint_reg_t count : 16; - /* - * For writes, this specifies the generation number of the tail being - * posted. Note that if tail+cnt wraps to the beginning of the ring, the - * eDMA hardware assumes that the descriptors posted at the beginning of - * the ring are also valid so it is okay to post around the wrap point. - * - * For reads, this is the current generation number. Valid descriptors - * will have the inverse of this generation number. - */ - uint_reg_t gen : 1; - /* Reserved. */ - uint_reg_t __reserved : 31; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved : 31; - uint_reg_t gen : 1; - uint_reg_t count : 16; - uint_reg_t ring_idx : 16; -#endif - }; - - uint_reg_t word; -} MPIPE_EDMA_POST_REGION_VAL_t; - -/* - * Load Balancer Bucket Status Data. - * Read/Write data for load balancer Bucket-Status Table. 4160 entries - * indexed by LBL_INIT_CTL.IDX when LBL_INIT_CTL.STRUCT_SEL is BSTS_TBL - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* NotifRing currently assigned to this bucket. */ - uint_reg_t notifring : 8; - /* Current reference count. */ - uint_reg_t count : 16; - /* Group associated with this bucket. */ - uint_reg_t group : 5; - /* Mode select for this bucket. */ - uint_reg_t mode : 3; - /* Reserved. */ - uint_reg_t __reserved : 32; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved : 32; - uint_reg_t mode : 3; - uint_reg_t group : 5; - uint_reg_t count : 16; - uint_reg_t notifring : 8; -#endif - }; - - uint_reg_t word; -} MPIPE_LBL_INIT_DAT_BSTS_TBL_t; -#endif /* !defined(__ASSEMBLER__) */ - -#endif /* !defined(__ARCH_MPIPE_H__) */ diff --git a/arch/tile/include/arch/mpipe_constants.h b/arch/tile/include/arch/mpipe_constants.h deleted file mode 100644 index 84022ac5fe82..000000000000 --- a/arch/tile/include/arch/mpipe_constants.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - - -#ifndef __ARCH_MPIPE_CONSTANTS_H__ -#define __ARCH_MPIPE_CONSTANTS_H__ - -#define MPIPE_NUM_CLASSIFIERS 16 -#define MPIPE_CLS_MHZ 1200 - -#define MPIPE_NUM_EDMA_RINGS 64 - -#define MPIPE_NUM_SGMII_MACS 16 -#define MPIPE_NUM_XAUI_MACS 16 -#define MPIPE_NUM_LOOPBACK_CHANNELS 4 -#define MPIPE_NUM_NON_LB_CHANNELS 28 - -#define MPIPE_NUM_IPKT_BLOCKS 1536 - -#define MPIPE_NUM_BUCKETS 4160 - -#define MPIPE_NUM_NOTIF_RINGS 256 - -#define MPIPE_NUM_NOTIF_GROUPS 32 - -#define MPIPE_NUM_TLBS_PER_ASID 16 -#define MPIPE_TLB_IDX_WIDTH 4 - -#define MPIPE_MMIO_NUM_SVC_DOM 32 - -#endif /* __ARCH_MPIPE_CONSTANTS_H__ */ diff --git a/arch/tile/include/arch/mpipe_def.h b/arch/tile/include/arch/mpipe_def.h deleted file mode 100644 index c3d30217fc66..000000000000 --- a/arch/tile/include/arch/mpipe_def.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_MPIPE_DEF_H__ -#define __ARCH_MPIPE_DEF_H__ -#define MPIPE_MMIO_ADDR__REGION_SHIFT 26 -#define MPIPE_MMIO_ADDR__REGION_VAL_CFG 0x0 -#define MPIPE_MMIO_ADDR__REGION_VAL_IDMA 0x4 -#define MPIPE_MMIO_ADDR__REGION_VAL_EDMA 0x5 -#define MPIPE_MMIO_ADDR__REGION_VAL_BSM 0x6 -#define MPIPE_BSM_REGION_VAL__VA_SHIFT 7 -#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_128 0x0 -#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_256 0x1 -#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_512 0x2 -#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_1024 0x3 -#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_1664 0x4 -#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_4096 0x5 -#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_10368 0x6 -#define MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_16384 0x7 -#define MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_DFA 0x0 -#define MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_FIXED 0x1 -#define MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_ALWAYS_PICK 0x2 -#define MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_STICKY 0x3 -#define MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_STICKY_RAND 0x7 -#define MPIPE_LBL_NR_STATE__FIRST_WORD 0x2138 -#endif /* !defined(__ARCH_MPIPE_DEF_H__) */ diff --git a/arch/tile/include/arch/mpipe_shm.h b/arch/tile/include/arch/mpipe_shm.h deleted file mode 100644 index 13b3c4300e50..000000000000 --- a/arch/tile/include/arch/mpipe_shm.h +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - - -#ifndef __ARCH_MPIPE_SHM_H__ -#define __ARCH_MPIPE_SHM_H__ - -#include -#include - -#ifndef __ASSEMBLER__ -/** - * MPIPE eDMA Descriptor. - * The eDMA descriptor is written by software and consumed by hardware. It - * is used to specify the location of egress packet data to be sent out of - * the chip via one of the packet interfaces. - */ - -__extension__ -typedef union -{ - struct - { - /* Word 0 */ - -#ifndef __BIG_ENDIAN__ - /** - * Generation number. Used to indicate a valid descriptor in ring. When - * a new descriptor is written into the ring, software must toggle this - * bit. The net effect is that the GEN bit being written into new - * descriptors toggles each time the ring tail pointer wraps. - */ - uint_reg_t gen : 1; - /** - * For devices with EDMA reorder support, this field allows the - * descriptor to select the egress FIFO. The associated DMA ring must - * have ALLOW_EFIFO_SEL enabled. - */ - uint_reg_t efifo_sel : 6; - /** Reserved. Must be zero. */ - uint_reg_t r0 : 1; - /** Checksum generation enabled for this transfer. */ - uint_reg_t csum : 1; - /** - * Nothing to be sent. Used, for example, when software has dropped a - * packet but still wishes to return all of the associated buffers. - */ - uint_reg_t ns : 1; - /** - * Notification interrupt will be delivered when packet has been egressed. - */ - uint_reg_t notif : 1; - /** - * Boundary indicator. When 1, this transfer includes the EOP for this - * command. Must be clear on all but the last descriptor for an egress - * packet. - */ - uint_reg_t bound : 1; - /** Reserved. Must be zero. */ - uint_reg_t r1 : 4; - /** - * Number of bytes to be sent for this descriptor. When zero, no data - * will be moved and the buffer descriptor will be ignored. If the - * buffer descriptor indicates that it is chained, the low 7 bits of the - * VA indicate the offset within the first buffer (e.g. 127 bytes is the - * maximum offset into the first buffer). If the size exceeds a single - * buffer, subsequent buffer descriptors will be fetched prior to - * processing the next eDMA descriptor in the ring. - */ - uint_reg_t xfer_size : 14; - /** Reserved. Must be zero. */ - uint_reg_t r2 : 2; - /** - * Destination of checksum relative to CSUM_START relative to the first - * byte moved by this descriptor. Must be zero if CSUM=0 in this - * descriptor. Must be less than XFER_SIZE (e.g. the first byte of the - * CSUM_DEST must be within the span of this descriptor). - */ - uint_reg_t csum_dest : 8; - /** - * Start byte of checksum relative to the first byte moved by this - * descriptor. If this is not the first descriptor for the egress - * packet, CSUM_START is still relative to the first byte in this - * descriptor. Must be zero if CSUM=0 in this descriptor. - */ - uint_reg_t csum_start : 8; - /** - * Initial value for 16-bit 1's compliment checksum if enabled via CSUM. - * Specified in network order. That is, bits[7:0] will be added to the - * byte pointed to by CSUM_START and bits[15:8] will be added to the byte - * pointed to by CSUM_START+1 (with appropriate 1's compliment carries). - * Must be zero if CSUM=0 in this descriptor. - */ - uint_reg_t csum_seed : 16; -#else /* __BIG_ENDIAN__ */ - uint_reg_t csum_seed : 16; - uint_reg_t csum_start : 8; - uint_reg_t csum_dest : 8; - uint_reg_t r2 : 2; - uint_reg_t xfer_size : 14; - uint_reg_t r1 : 4; - uint_reg_t bound : 1; - uint_reg_t notif : 1; - uint_reg_t ns : 1; - uint_reg_t csum : 1; - uint_reg_t r0 : 1; - uint_reg_t efifo_sel : 6; - uint_reg_t gen : 1; -#endif - - /* Word 1 */ - -#ifndef __BIG_ENDIAN__ - /** Virtual address. Must be sign extended by consumer. */ - int_reg_t va : 42; - /** Reserved. */ - uint_reg_t __reserved_0 : 6; - /** Index of the buffer stack to which this buffer belongs. */ - uint_reg_t stack_idx : 5; - /** Reserved. */ - uint_reg_t __reserved_1 : 3; - /** - * Instance ID. For devices that support automatic buffer return between - * mPIPE instances, this field indicates the buffer owner. If the INST - * field does not match the mPIPE's instance number when a packet is - * egressed, buffers with HWB set will be returned to the other mPIPE - * instance. Note that not all devices support multi-mPIPE buffer - * return. The MPIPE_EDMA_INFO.REMOTE_BUFF_RTN_SUPPORT bit indicates - * whether the INST field in the buffer descriptor is populated by iDMA - * hardware. - */ - uint_reg_t inst : 2; - /** - * Always set to one by hardware in iDMA packet descriptors. For eDMA, - * indicates whether the buffer will be released to the buffer stack - * manager. When 0, software is responsible for releasing the buffer. - */ - uint_reg_t hwb : 1; - /** - * Encoded size of buffer. Set by the ingress hardware for iDMA packet - * descriptors. For eDMA descriptors, indicates the buffer size if .c - * indicates a chained packet. If an eDMA descriptor is not chained and - * the .hwb bit is not set, this field is ignored and the size is - * specified by the .xfer_size field. - * 0 = 128 bytes - * 1 = 256 bytes - * 2 = 512 bytes - * 3 = 1024 bytes - * 4 = 1664 bytes - * 5 = 4096 bytes - * 6 = 10368 bytes - * 7 = 16384 bytes - */ - uint_reg_t size : 3; - /** - * Chaining configuration for the buffer. Indicates that an ingress - * packet or egress command is chained across multiple buffers, with each - * buffer's size indicated by the .size field. - */ - uint_reg_t c : 2; -#else /* __BIG_ENDIAN__ */ - uint_reg_t c : 2; - uint_reg_t size : 3; - uint_reg_t hwb : 1; - uint_reg_t inst : 2; - uint_reg_t __reserved_1 : 3; - uint_reg_t stack_idx : 5; - uint_reg_t __reserved_0 : 6; - int_reg_t va : 42; -#endif - - }; - - /** Word access */ - uint_reg_t words[2]; -} MPIPE_EDMA_DESC_t; - -/** - * MPIPE Packet Descriptor. - * The packet descriptor is filled by the mPIPE's classification, - * load-balancing, and buffer management services. Some fields are consumed - * by mPIPE hardware, and others are consumed by Tile software. - */ - -__extension__ -typedef union -{ - struct - { - /* Word 0 */ - -#ifndef __BIG_ENDIAN__ - /** - * Notification ring into which this packet descriptor is written. - * Typically written by load balancer, but can be overridden by - * classification program if NR is asserted. - */ - uint_reg_t notif_ring : 8; - /** Source channel for this packet. Written by mPIPE DMA hardware. */ - uint_reg_t channel : 5; - /** Reserved. */ - uint_reg_t __reserved_0 : 1; - /** - * MAC Error. - * Generated by the MAC interface. Asserted if there was an overrun of - * the MAC's receive FIFO. This condition generally only occurs if the - * mPIPE clock is running too slowly. - */ - uint_reg_t me : 1; - /** - * Truncation Error. - * Written by the iDMA hardware. Asserted if packet was truncated due to - * insufficient space in iPkt buffer - */ - uint_reg_t tr : 1; - /** - * Written by the iDMA hardware. Indicates the number of bytes written - * to Tile memory. In general, this is the actual size of the packet as - * received from the MAC. But if the packet is truncated due to running - * out of buffers or due to the iPkt buffer filling up, then the L2_SIZE - * will be reduced to reflect the actual number of valid bytes written to - * Tile memory. - */ - uint_reg_t l2_size : 14; - /** - * CRC Error. - * Generated by the MAC. Asserted if MAC indicated an L2 CRC error or - * other L2 error (bad length etc.) on the packet. - */ - uint_reg_t ce : 1; - /** - * Cut Through. - * Written by the iDMA hardware. Asserted if packet was not completely - * received before being sent to classifier. L2_Size will indicate - * number of bytes received so far. - */ - uint_reg_t ct : 1; - /** - * Written by the classification program. Used by the load balancer to - * select the ring into which this packet descriptor is written. - */ - uint_reg_t bucket_id : 13; - /** Reserved. */ - uint_reg_t __reserved_1 : 3; - /** - * Checksum. - * Written by classification program. When 1, the checksum engine will - * perform checksum based on the CSUM_SEED, CSUM_START, and CSUM_BYTES - * fields. The result will be placed in CSUM_VAL. - */ - uint_reg_t cs : 1; - /** - * Notification Ring Select. - * Written by the classification program. When 1, the NotifRingIDX is - * set by classification program rather than being set by load balancer. - */ - uint_reg_t nr : 1; - /** - * Written by classification program. Indicates whether packet and - * descriptor should both be dropped, both be delivered, or only the - * descriptor should be delivered. - */ - uint_reg_t dest : 2; - /** - * General Purpose Sequence Number Enable. - * Written by the classification program. When 1, the GP_SQN_SEL field - * contains the sequence number selector and the GP_SQN field will be - * replaced with the associated sequence number. When clear, the GP_SQN - * field is left intact and be used as "Custom" bytes. - */ - uint_reg_t sq : 1; - /** - * TimeStamp Enable. - * Enable TimeStamp insertion. When clear, timestamp field may be filled - * with custom data by classifier. When set, hardware inserts the - * timestamp when the start of packet is received from the MAC. - */ - uint_reg_t ts : 1; - /** - * Packet Sequence Number Enable. - * Enable PacketSQN insertion. When clear, PacketSQN field may be filled - * with custom data by classifier. When set, hardware inserts the packet - * sequence number when the packet descriptor is written to a - * notification ring. - */ - uint_reg_t ps : 1; - /** - * Buffer Error. - * Written by the iDMA hardware. Asserted if iDMA ran out of buffers - * while writing the packet. Software must still return any buffer - * descriptors whose C field indicates a valid descriptor was consumed. - */ - uint_reg_t be : 1; - /** - * Written by the classification program. The associated counter is - * incremented when the packet is sent. - */ - uint_reg_t ctr0 : 5; - /** Reserved. */ - uint_reg_t __reserved_2 : 3; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_2 : 3; - uint_reg_t ctr0 : 5; - uint_reg_t be : 1; - uint_reg_t ps : 1; - uint_reg_t ts : 1; - uint_reg_t sq : 1; - uint_reg_t dest : 2; - uint_reg_t nr : 1; - uint_reg_t cs : 1; - uint_reg_t __reserved_1 : 3; - uint_reg_t bucket_id : 13; - uint_reg_t ct : 1; - uint_reg_t ce : 1; - uint_reg_t l2_size : 14; - uint_reg_t tr : 1; - uint_reg_t me : 1; - uint_reg_t __reserved_0 : 1; - uint_reg_t channel : 5; - uint_reg_t notif_ring : 8; -#endif - - /* Word 1 */ - -#ifndef __BIG_ENDIAN__ - /** - * Written by the classification program. The associated counter is - * incremented when the packet is sent. - */ - uint_reg_t ctr1 : 5; - /** Reserved. */ - uint_reg_t __reserved_3 : 3; - /** - * Written by classification program. Indicates the start byte for - * checksum. Relative to 1st byte received from MAC. - */ - uint_reg_t csum_start : 8; - /** - * Checksum seed written by classification program. Overwritten with - * resultant checksum if CS bit is asserted. The endianness of the CSUM - * value bits when viewed by Tile software match the packet byte order. - * That is, bits[7:0] of the resulting checksum value correspond to - * earlier (more significant) bytes in the packet. To avoid classifier - * software from having to byte swap the CSUM_SEED, the iDMA checksum - * engine byte swaps the classifier's result before seeding the checksum - * calculation. Thus, the CSUM_START byte of packet data is added to - * bits[15:8] of the CSUM_SEED field generated by the classifier. This - * byte swap will be visible to Tile software if the CS bit is clear. - */ - uint_reg_t csum_seed_val : 16; - /** - * Written by the classification program. Not interpreted by mPIPE - * hardware. - */ - uint_reg_t custom0 : 32; -#else /* __BIG_ENDIAN__ */ - uint_reg_t custom0 : 32; - uint_reg_t csum_seed_val : 16; - uint_reg_t csum_start : 8; - uint_reg_t __reserved_3 : 3; - uint_reg_t ctr1 : 5; -#endif - - /* Word 2 */ - -#ifndef __BIG_ENDIAN__ - /** - * Written by the classification program. Not interpreted by mPIPE - * hardware. - */ - uint_reg_t custom1 : 64; -#else /* __BIG_ENDIAN__ */ - uint_reg_t custom1 : 64; -#endif - - /* Word 3 */ - -#ifndef __BIG_ENDIAN__ - /** - * Written by the classification program. Not interpreted by mPIPE - * hardware. - */ - uint_reg_t custom2 : 64; -#else /* __BIG_ENDIAN__ */ - uint_reg_t custom2 : 64; -#endif - - /* Word 4 */ - -#ifndef __BIG_ENDIAN__ - /** - * Written by the classification program. Not interpreted by mPIPE - * hardware. - */ - uint_reg_t custom3 : 64; -#else /* __BIG_ENDIAN__ */ - uint_reg_t custom3 : 64; -#endif - - /* Word 5 */ - -#ifndef __BIG_ENDIAN__ - /** - * Sequence number applied when packet is distributed. Classifier - * selects which sequence number is to be applied by writing the 13-bit - * SQN-selector into this field. For devices that support EXT_SQN (as - * indicated in IDMA_INFO.EXT_SQN_SUPPORT), the GP_SQN can be extended to - * 32-bits via the IDMA_CTL.EXT_SQN register. In this case the - * PACKET_SQN will be reduced to 32 bits. - */ - uint_reg_t gp_sqn : 16; - /** - * Written by notification hardware. The packet sequence number is - * incremented for each packet that wasn't dropped. - */ - uint_reg_t packet_sqn : 48; -#else /* __BIG_ENDIAN__ */ - uint_reg_t packet_sqn : 48; - uint_reg_t gp_sqn : 16; -#endif - - /* Word 6 */ - -#ifndef __BIG_ENDIAN__ - /** - * Written by hardware when the start-of-packet is received by the mPIPE - * from the MAC. This is the nanoseconds part of the packet timestamp. - */ - uint_reg_t time_stamp_ns : 32; - /** - * Written by hardware when the start-of-packet is received by the mPIPE - * from the MAC. This is the seconds part of the packet timestamp. - */ - uint_reg_t time_stamp_sec : 32; -#else /* __BIG_ENDIAN__ */ - uint_reg_t time_stamp_sec : 32; - uint_reg_t time_stamp_ns : 32; -#endif - - /* Word 7 */ - -#ifndef __BIG_ENDIAN__ - /** Virtual address. Must be sign extended by consumer. */ - int_reg_t va : 42; - /** Reserved. */ - uint_reg_t __reserved_4 : 6; - /** Index of the buffer stack to which this buffer belongs. */ - uint_reg_t stack_idx : 5; - /** Reserved. */ - uint_reg_t __reserved_5 : 3; - /** - * Instance ID. For devices that support automatic buffer return between - * mPIPE instances, this field indicates the buffer owner. If the INST - * field does not match the mPIPE's instance number when a packet is - * egressed, buffers with HWB set will be returned to the other mPIPE - * instance. Note that not all devices support multi-mPIPE buffer - * return. The MPIPE_EDMA_INFO.REMOTE_BUFF_RTN_SUPPORT bit indicates - * whether the INST field in the buffer descriptor is populated by iDMA - * hardware. - */ - uint_reg_t inst : 2; - /** - * Always set to one by hardware in iDMA packet descriptors. For eDMA, - * indicates whether the buffer will be released to the buffer stack - * manager. When 0, software is responsible for releasing the buffer. - */ - uint_reg_t hwb : 1; - /** - * Encoded size of buffer. Set by the ingress hardware for iDMA packet - * descriptors. For eDMA descriptors, indicates the buffer size if .c - * indicates a chained packet. If an eDMA descriptor is not chained and - * the .hwb bit is not set, this field is ignored and the size is - * specified by the .xfer_size field. - * 0 = 128 bytes - * 1 = 256 bytes - * 2 = 512 bytes - * 3 = 1024 bytes - * 4 = 1664 bytes - * 5 = 4096 bytes - * 6 = 10368 bytes - * 7 = 16384 bytes - */ - uint_reg_t size : 3; - /** - * Chaining configuration for the buffer. Indicates that an ingress - * packet or egress command is chained across multiple buffers, with each - * buffer's size indicated by the .size field. - */ - uint_reg_t c : 2; -#else /* __BIG_ENDIAN__ */ - uint_reg_t c : 2; - uint_reg_t size : 3; - uint_reg_t hwb : 1; - uint_reg_t inst : 2; - uint_reg_t __reserved_5 : 3; - uint_reg_t stack_idx : 5; - uint_reg_t __reserved_4 : 6; - int_reg_t va : 42; -#endif - - }; - - /** Word access */ - uint_reg_t words[8]; -} MPIPE_PDESC_t; -#endif /* !defined(__ASSEMBLER__) */ - -#endif /* !defined(__ARCH_MPIPE_SHM_H__) */ diff --git a/arch/tile/include/arch/mpipe_shm_def.h b/arch/tile/include/arch/mpipe_shm_def.h deleted file mode 100644 index 6124d39c8318..000000000000 --- a/arch/tile/include/arch/mpipe_shm_def.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_MPIPE_SHM_DEF_H__ -#define __ARCH_MPIPE_SHM_DEF_H__ -#define MPIPE_EDMA_DESC_WORD1__C_VAL_UNCHAINED 0x0 -#define MPIPE_EDMA_DESC_WORD1__C_VAL_CHAINED 0x1 -#define MPIPE_EDMA_DESC_WORD1__C_VAL_NOT_RDY 0x2 -#define MPIPE_EDMA_DESC_WORD1__C_VAL_INVALID 0x3 -#endif /* !defined(__ARCH_MPIPE_SHM_DEF_H__) */ diff --git a/arch/tile/include/arch/spr_def.h b/arch/tile/include/arch/spr_def.h deleted file mode 100644 index 2de83e7aff3e..000000000000 --- a/arch/tile/include/arch/spr_def.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ -#ifndef __ARCH_SPR_DEF_H__ -#define __ARCH_SPR_DEF_H__ - -#include - - -/* - * In addition to including the proper base SPR definition file, depending - * on machine architecture, this file defines several macros which allow - * kernel code to use protection-level dependent SPRs without worrying - * about which PL it's running at. In these macros, the PL that the SPR - * or interrupt number applies to is replaced by K. - */ - -#if CONFIG_KERNEL_PL != 1 && CONFIG_KERNEL_PL != 2 -#error CONFIG_KERNEL_PL must be 1 or 2 -#endif - -/* Concatenate 4 strings. */ -#define __concat4(a, b, c, d) a ## b ## c ## d -#define _concat4(a, b, c, d) __concat4(a, b, c, d) - -#ifdef __tilegx__ - -/* TILE-Gx dependent, protection-level dependent SPRs. */ - -#define SPR_INTERRUPT_MASK_K \ - _concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL,,) -#define SPR_INTERRUPT_MASK_SET_K \ - _concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL,,) -#define SPR_INTERRUPT_MASK_RESET_K \ - _concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL,,) -#define SPR_INTERRUPT_VECTOR_BASE_K \ - _concat4(SPR_INTERRUPT_VECTOR_BASE_, CONFIG_KERNEL_PL,,) - -#define SPR_IPI_MASK_K \ - _concat4(SPR_IPI_MASK_, CONFIG_KERNEL_PL,,) -#define SPR_IPI_MASK_RESET_K \ - _concat4(SPR_IPI_MASK_RESET_, CONFIG_KERNEL_PL,,) -#define SPR_IPI_MASK_SET_K \ - _concat4(SPR_IPI_MASK_SET_, CONFIG_KERNEL_PL,,) -#define SPR_IPI_EVENT_K \ - _concat4(SPR_IPI_EVENT_, CONFIG_KERNEL_PL,,) -#define SPR_IPI_EVENT_RESET_K \ - _concat4(SPR_IPI_EVENT_RESET_, CONFIG_KERNEL_PL,,) -#define SPR_IPI_EVENT_SET_K \ - _concat4(SPR_IPI_EVENT_SET_, CONFIG_KERNEL_PL,,) -#define INT_IPI_K \ - _concat4(INT_IPI_, CONFIG_KERNEL_PL,,) - -#define SPR_SINGLE_STEP_CONTROL_K \ - _concat4(SPR_SINGLE_STEP_CONTROL_, CONFIG_KERNEL_PL,,) -#define SPR_SINGLE_STEP_EN_K_K \ - _concat4(SPR_SINGLE_STEP_EN_, CONFIG_KERNEL_PL, _, CONFIG_KERNEL_PL) -#define INT_SINGLE_STEP_K \ - _concat4(INT_SINGLE_STEP_, CONFIG_KERNEL_PL,,) - -#else - -/* TILEPro dependent, protection-level dependent SPRs. */ - -#define SPR_INTERRUPT_MASK_K_0 \ - _concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL, _0,) -#define SPR_INTERRUPT_MASK_K_1 \ - _concat4(SPR_INTERRUPT_MASK_, CONFIG_KERNEL_PL, _1,) -#define SPR_INTERRUPT_MASK_SET_K_0 \ - _concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL, _0,) -#define SPR_INTERRUPT_MASK_SET_K_1 \ - _concat4(SPR_INTERRUPT_MASK_SET_, CONFIG_KERNEL_PL, _1,) -#define SPR_INTERRUPT_MASK_RESET_K_0 \ - _concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL, _0,) -#define SPR_INTERRUPT_MASK_RESET_K_1 \ - _concat4(SPR_INTERRUPT_MASK_RESET_, CONFIG_KERNEL_PL, _1,) - -#endif - -/* Generic protection-level dependent SPRs. */ - -#define SPR_SYSTEM_SAVE_K_0 \ - _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _0,) -#define SPR_SYSTEM_SAVE_K_1 \ - _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _1,) -#define SPR_SYSTEM_SAVE_K_2 \ - _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _2,) -#define SPR_SYSTEM_SAVE_K_3 \ - _concat4(SPR_SYSTEM_SAVE_, CONFIG_KERNEL_PL, _3,) -#define SPR_EX_CONTEXT_K_0 \ - _concat4(SPR_EX_CONTEXT_, CONFIG_KERNEL_PL, _0,) -#define SPR_EX_CONTEXT_K_1 \ - _concat4(SPR_EX_CONTEXT_, CONFIG_KERNEL_PL, _1,) -#define SPR_INTCTRL_K_STATUS \ - _concat4(SPR_INTCTRL_, CONFIG_KERNEL_PL, _STATUS,) -#define INT_INTCTRL_K \ - _concat4(INT_INTCTRL_, CONFIG_KERNEL_PL,,) - -#endif /* __ARCH_SPR_DEF_H__ */ diff --git a/arch/tile/include/arch/trio.h b/arch/tile/include/arch/trio.h deleted file mode 100644 index c0ddedcae085..000000000000 --- a/arch/tile/include/arch/trio.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_TRIO_H__ -#define __ARCH_TRIO_H__ - -#include -#include - -#ifndef __ASSEMBLER__ - -/* - * Map SQ Doorbell Format. - * This describes the format of the write-only doorbell register that exists - * in the last 8-bytes of the MAP_SQ_BASE/LIM range. This register is only - * writable from PCIe space. Writes to this register will not be written to - * Tile memory space and thus no IO VA translation is required if the last - * page of the BASE/LIM range is not otherwise written. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* - * When written with a 1, the associated MAP_SQ region's doorbell - * interrupt will be triggered once all previous writes are visible to - * Tile software. - */ - uint_reg_t doorbell : 1; - /* - * When written with a 1, the descriptor at the head of the associated - * MAP_SQ's FIFO will be dequeued. - */ - uint_reg_t pop : 1; - /* Reserved. */ - uint_reg_t __reserved : 62; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved : 62; - uint_reg_t pop : 1; - uint_reg_t doorbell : 1; -#endif - }; - - uint_reg_t word; -} TRIO_MAP_SQ_DOORBELL_FMT_t; - - -/* - * Tile PIO Region Configuration - CFG Address Format. - * This register describes the address format for PIO accesses when the - * associated region is setup with TYPE=CFG. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Register Address (full byte address). */ - uint_reg_t reg_addr : 12; - /* Function Number */ - uint_reg_t fn : 3; - /* Device Number */ - uint_reg_t dev : 5; - /* BUS Number */ - uint_reg_t bus : 8; - /* Config Type: 0 for access to directly-attached device. 1 otherwise. */ - uint_reg_t type : 1; - /* Reserved. */ - uint_reg_t __reserved_0 : 1; - /* - * MAC select. This must match the configuration in - * TILE_PIO_REGION_SETUP.MAC. - */ - uint_reg_t mac : 2; - /* Reserved. */ - uint_reg_t __reserved_1 : 32; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_1 : 32; - uint_reg_t mac : 2; - uint_reg_t __reserved_0 : 1; - uint_reg_t type : 1; - uint_reg_t bus : 8; - uint_reg_t dev : 5; - uint_reg_t fn : 3; - uint_reg_t reg_addr : 12; -#endif - }; - - uint_reg_t word; -} TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR_t; -#endif /* !defined(__ASSEMBLER__) */ - -#endif /* !defined(__ARCH_TRIO_H__) */ diff --git a/arch/tile/include/arch/trio_constants.h b/arch/tile/include/arch/trio_constants.h deleted file mode 100644 index 85647e91a458..000000000000 --- a/arch/tile/include/arch/trio_constants.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - - -#ifndef __ARCH_TRIO_CONSTANTS_H__ -#define __ARCH_TRIO_CONSTANTS_H__ - -#define TRIO_NUM_ASIDS 32 -#define TRIO_NUM_TLBS_PER_ASID 16 - -#define TRIO_NUM_TPIO_REGIONS 8 -#define TRIO_LOG2_NUM_TPIO_REGIONS 3 - -#define TRIO_NUM_MAP_MEM_REGIONS 32 -#define TRIO_LOG2_NUM_MAP_MEM_REGIONS 5 -#define TRIO_NUM_MAP_SQ_REGIONS 8 -#define TRIO_LOG2_NUM_MAP_SQ_REGIONS 3 - -#define TRIO_LOG2_NUM_SQ_FIFO_ENTRIES 6 - -#define TRIO_NUM_PUSH_DMA_RINGS 64 - -#define TRIO_NUM_PULL_DMA_RINGS 64 - -#endif /* __ARCH_TRIO_CONSTANTS_H__ */ diff --git a/arch/tile/include/arch/trio_def.h b/arch/tile/include/arch/trio_def.h deleted file mode 100644 index e80500317dc4..000000000000 --- a/arch/tile/include/arch/trio_def.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_TRIO_DEF_H__ -#define __ARCH_TRIO_DEF_H__ -#define TRIO_CFG_REGION_ADDR__REG_SHIFT 0 -#define TRIO_CFG_REGION_ADDR__INTFC_SHIFT 16 -#define TRIO_CFG_REGION_ADDR__INTFC_VAL_TRIO 0x0 -#define TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE 0x1 -#define TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD 0x2 -#define TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_PROTECTED 0x3 -#define TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT 18 -#define TRIO_CFG_REGION_ADDR__PROT_SHIFT 20 -#define TRIO_PIO_REGIONS_ADDR__REGION_SHIFT 32 -#define TRIO_MAP_MEM_REG_INT0 0x1000000000 -#define TRIO_MAP_MEM_REG_INT1 0x1000000008 -#define TRIO_MAP_MEM_REG_INT2 0x1000000010 -#define TRIO_MAP_MEM_REG_INT3 0x1000000018 -#define TRIO_MAP_MEM_REG_INT4 0x1000000020 -#define TRIO_MAP_MEM_REG_INT5 0x1000000028 -#define TRIO_MAP_MEM_REG_INT6 0x1000000030 -#define TRIO_MAP_MEM_REG_INT7 0x1000000038 -#define TRIO_MAP_MEM_LIM__ADDR_SHIFT 12 -#define TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_UNORDERED 0x0 -#define TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_STRICT 0x1 -#define TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_REL_ORD 0x2 -#define TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT 30 -#endif /* !defined(__ARCH_TRIO_DEF_H__) */ diff --git a/arch/tile/include/arch/trio_pcie_intfc.h b/arch/tile/include/arch/trio_pcie_intfc.h deleted file mode 100644 index 0487fdb9d581..000000000000 --- a/arch/tile/include/arch/trio_pcie_intfc.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_TRIO_PCIE_INTFC_H__ -#define __ARCH_TRIO_PCIE_INTFC_H__ - -#include -#include - -#ifndef __ASSEMBLER__ - -/* - * Port Configuration. - * Configuration of the PCIe Port - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Provides the state of the strapping pins for this port. */ - uint_reg_t strap_state : 3; - /* Reserved. */ - uint_reg_t __reserved_0 : 1; - /* - * When 1, the device type will be overridden using OVD_DEV_TYPE_VAL. - * When 0, the device type is determined based on the STRAP_STATE. - */ - uint_reg_t ovd_dev_type : 1; - /* Provides the device type when OVD_DEV_TYPE is 1. */ - uint_reg_t ovd_dev_type_val : 4; - /* Determines how link is trained. */ - uint_reg_t train_mode : 2; - /* Reserved. */ - uint_reg_t __reserved_1 : 1; - /* - * For PCIe, used to flip physical RX lanes that were not properly wired. - * This is not the same as lane reversal which is handled automatically - * during link training. When 0, RX Lane0 must be wired to the link - * partner (either to its Lane0 or it's LaneN). When RX_LANE_FLIP is 1, - * the highest numbered lane for this port becomes Lane0 and Lane0 does - * NOT have to be wired to the link partner. - */ - uint_reg_t rx_lane_flip : 1; - /* - * For PCIe, used to flip physical TX lanes that were not properly wired. - * This is not the same as lane reversal which is handled automatically - * during link training. When 0, TX Lane0 must be wired to the link - * partner (either to its Lane0 or it's LaneN). When TX_LANE_FLIP is 1, - * the highest numbered lane for this port becomes Lane0 and Lane0 does - * NOT have to be wired to the link partner. - */ - uint_reg_t tx_lane_flip : 1; - /* - * For StreamIO port, configures the width of the port when TRAIN_MODE is - * not STRAP. - */ - uint_reg_t stream_width : 2; - /* - * For StreamIO port, configures the rate of the port when TRAIN_MODE is - * not STRAP. - */ - uint_reg_t stream_rate : 2; - /* Reserved. */ - uint_reg_t __reserved_2 : 46; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_2 : 46; - uint_reg_t stream_rate : 2; - uint_reg_t stream_width : 2; - uint_reg_t tx_lane_flip : 1; - uint_reg_t rx_lane_flip : 1; - uint_reg_t __reserved_1 : 1; - uint_reg_t train_mode : 2; - uint_reg_t ovd_dev_type_val : 4; - uint_reg_t ovd_dev_type : 1; - uint_reg_t __reserved_0 : 1; - uint_reg_t strap_state : 3; -#endif - }; - - uint_reg_t word; -} TRIO_PCIE_INTFC_PORT_CONFIG_t; - -/* - * Port Status. - * Status of the PCIe Port. This register applies to the StreamIO port when - * StreamIO is enabled. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* - * Indicates the DL state of the port. When 1, the port is up and ready - * to receive traffic. - */ - uint_reg_t dl_up : 1; - /* - * Indicates the number of times the link has gone down. Clears on read. - */ - uint_reg_t dl_down_cnt : 7; - /* Indicates the SERDES PLL has spun up and is providing a valid clock. */ - uint_reg_t clock_ready : 1; - /* Reserved. */ - uint_reg_t __reserved_0 : 7; - /* Device revision ID. */ - uint_reg_t device_rev : 8; - /* Link state (PCIe). */ - uint_reg_t ltssm_state : 6; - /* Link power management state (PCIe). */ - uint_reg_t pm_state : 3; - /* Reserved. */ - uint_reg_t __reserved_1 : 31; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_1 : 31; - uint_reg_t pm_state : 3; - uint_reg_t ltssm_state : 6; - uint_reg_t device_rev : 8; - uint_reg_t __reserved_0 : 7; - uint_reg_t clock_ready : 1; - uint_reg_t dl_down_cnt : 7; - uint_reg_t dl_up : 1; -#endif - }; - - uint_reg_t word; -} TRIO_PCIE_INTFC_PORT_STATUS_t; - -/* - * Transmit FIFO Control. - * Contains TX FIFO thresholds. These registers are for diagnostics purposes - * only. Changing these values causes undefined behavior. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* - * Almost-Empty level for TX0 data. Typically set to at least - * roundup(38.0*M/N) where N=tclk frequency and M=MAC symbol rate in MHz - * for a x4 port (250MHz). - */ - uint_reg_t tx0_data_ae_lvl : 7; - /* Reserved. */ - uint_reg_t __reserved_0 : 1; - /* Almost-Empty level for TX1 data. */ - uint_reg_t tx1_data_ae_lvl : 7; - /* Reserved. */ - uint_reg_t __reserved_1 : 1; - /* Almost-Full level for TX0 data. */ - uint_reg_t tx0_data_af_lvl : 7; - /* Reserved. */ - uint_reg_t __reserved_2 : 1; - /* Almost-Full level for TX1 data. */ - uint_reg_t tx1_data_af_lvl : 7; - /* Reserved. */ - uint_reg_t __reserved_3 : 1; - /* Almost-Full level for TX0 info. */ - uint_reg_t tx0_info_af_lvl : 5; - /* Reserved. */ - uint_reg_t __reserved_4 : 3; - /* Almost-Full level for TX1 info. */ - uint_reg_t tx1_info_af_lvl : 5; - /* Reserved. */ - uint_reg_t __reserved_5 : 3; - /* - * This register provides performance adjustment for high bandwidth - * flows. The MAC will assert almost-full to TRIO if non-posted credits - * fall below this level. Note that setting this larger than the initial - * PORT_CREDIT.NPH value will cause READS to never be sent. If the - * initial credit value from the link partner is smaller than this value - * when the link comes up, the value will be reset to the initial credit - * value to prevent lockup. - */ - uint_reg_t min_np_credits : 8; - /* - * This register provides performance adjustment for high bandwidth - * flows. The MAC will assert almost-full to TRIO if posted credits fall - * below this level. Note that setting this larger than the initial - * PORT_CREDIT.PH value will cause WRITES to never be sent. If the - * initial credit value from the link partner is smaller than this value - * when the link comes up, the value will be reset to the initial credit - * value to prevent lockup. - */ - uint_reg_t min_p_credits : 8; -#else /* __BIG_ENDIAN__ */ - uint_reg_t min_p_credits : 8; - uint_reg_t min_np_credits : 8; - uint_reg_t __reserved_5 : 3; - uint_reg_t tx1_info_af_lvl : 5; - uint_reg_t __reserved_4 : 3; - uint_reg_t tx0_info_af_lvl : 5; - uint_reg_t __reserved_3 : 1; - uint_reg_t tx1_data_af_lvl : 7; - uint_reg_t __reserved_2 : 1; - uint_reg_t tx0_data_af_lvl : 7; - uint_reg_t __reserved_1 : 1; - uint_reg_t tx1_data_ae_lvl : 7; - uint_reg_t __reserved_0 : 1; - uint_reg_t tx0_data_ae_lvl : 7; -#endif - }; - - uint_reg_t word; -} TRIO_PCIE_INTFC_TX_FIFO_CTL_t; -#endif /* !defined(__ASSEMBLER__) */ - -#endif /* !defined(__ARCH_TRIO_PCIE_INTFC_H__) */ diff --git a/arch/tile/include/arch/trio_pcie_intfc_def.h b/arch/tile/include/arch/trio_pcie_intfc_def.h deleted file mode 100644 index d3fd6781fb24..000000000000 --- a/arch/tile/include/arch/trio_pcie_intfc_def.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_TRIO_PCIE_INTFC_DEF_H__ -#define __ARCH_TRIO_PCIE_INTFC_DEF_H__ -#define TRIO_PCIE_INTFC_MAC_INT_STS 0x0000 -#define TRIO_PCIE_INTFC_MAC_INT_STS__INT_LEVEL_MASK 0xf000 -#define TRIO_PCIE_INTFC_PORT_CONFIG 0x0018 -#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_DISABLED 0x0 -#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT 0x1 -#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC 0x2 -#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT_G1 0x3 -#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC_G1 0x4 -#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_XLINK 0x5 -#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_STREAM_X1 0x6 -#define TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_STREAM_X4 0x7 -#define TRIO_PCIE_INTFC_PORT_STATUS 0x0020 -#define TRIO_PCIE_INTFC_TX_FIFO_CTL 0x0050 -#endif /* !defined(__ARCH_TRIO_PCIE_INTFC_DEF_H__) */ diff --git a/arch/tile/include/arch/trio_pcie_rc.h b/arch/tile/include/arch/trio_pcie_rc.h deleted file mode 100644 index 6a25d0aca857..000000000000 --- a/arch/tile/include/arch/trio_pcie_rc.h +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_TRIO_PCIE_RC_H__ -#define __ARCH_TRIO_PCIE_RC_H__ - -#include -#include - -#ifndef __ASSEMBLER__ - -/* Device Capabilities Register. */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* - * Max_Payload_Size Supported, writablethrough the MAC_STANDARD interface - */ - uint_reg_t mps_sup : 3; - /* - * This field is writable through the MAC_STANDARD interface. However, - * Phantom Function is not supported. Therefore, the application must - * not write any value other than 0x0 to this field. - */ - uint_reg_t phantom_function_supported : 2; - /* This bit is writable through the MAC_STANDARD interface. */ - uint_reg_t ext_tag_field_supported : 1; - /* Reserved. */ - uint_reg_t __reserved_0 : 3; - /* Endpoint L1 Acceptable Latency Must be 0x0 for non-Endpoint devices. */ - uint_reg_t l1_lat : 3; - /* - * Undefined since PCI Express 1.1 (Was Attention Button Present for PCI - * Express 1.0a) - */ - uint_reg_t r1 : 1; - /* - * Undefined since PCI Express 1.1 (Was Attention Indicator Present for - * PCI Express 1.0a) - */ - uint_reg_t r2 : 1; - /* - * Undefined since PCI Express 1.1 (Was Power Indicator Present for PCI - * Express 1.0a) - */ - uint_reg_t r3 : 1; - /* - * Role-Based Error Reporting, writable through the MAC_STANDARD - * interface. Required to be set for device compliant to 1.1 spec and - * later. - */ - uint_reg_t rer : 1; - /* Reserved. */ - uint_reg_t __reserved_1 : 2; - /* Captured Slot Power Limit Value Upstream port only. */ - uint_reg_t slot_pwr_lim : 8; - /* Captured Slot Power Limit Scale Upstream port only. */ - uint_reg_t slot_pwr_scale : 2; - /* Reserved. */ - uint_reg_t __reserved_2 : 4; - /* Endpoint L0s Acceptable LatencyMust be 0x0 for non-Endpoint devices. */ - uint_reg_t l0s_lat : 1; - /* Reserved. */ - uint_reg_t __reserved_3 : 31; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_3 : 31; - uint_reg_t l0s_lat : 1; - uint_reg_t __reserved_2 : 4; - uint_reg_t slot_pwr_scale : 2; - uint_reg_t slot_pwr_lim : 8; - uint_reg_t __reserved_1 : 2; - uint_reg_t rer : 1; - uint_reg_t r3 : 1; - uint_reg_t r2 : 1; - uint_reg_t r1 : 1; - uint_reg_t l1_lat : 3; - uint_reg_t __reserved_0 : 3; - uint_reg_t ext_tag_field_supported : 1; - uint_reg_t phantom_function_supported : 2; - uint_reg_t mps_sup : 3; -#endif - }; - - uint_reg_t word; -} TRIO_PCIE_RC_DEVICE_CAP_t; - -/* Device Control Register. */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Correctable Error Reporting Enable */ - uint_reg_t cor_err_ena : 1; - /* Non-Fatal Error Reporting Enable */ - uint_reg_t nf_err_ena : 1; - /* Fatal Error Reporting Enable */ - uint_reg_t fatal_err_ena : 1; - /* Unsupported Request Reporting Enable */ - uint_reg_t ur_ena : 1; - /* Relaxed orderring enable */ - uint_reg_t ro_ena : 1; - /* Max Payload Size */ - uint_reg_t max_payload_size : 3; - /* Extended Tag Field Enable */ - uint_reg_t ext_tag : 1; - /* Phantom Function Enable */ - uint_reg_t ph_fn_ena : 1; - /* AUX Power PM Enable */ - uint_reg_t aux_pm_ena : 1; - /* Enable NoSnoop */ - uint_reg_t no_snoop : 1; - /* Max read request size */ - uint_reg_t max_read_req_sz : 3; - /* Reserved. */ - uint_reg_t __reserved : 49; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved : 49; - uint_reg_t max_read_req_sz : 3; - uint_reg_t no_snoop : 1; - uint_reg_t aux_pm_ena : 1; - uint_reg_t ph_fn_ena : 1; - uint_reg_t ext_tag : 1; - uint_reg_t max_payload_size : 3; - uint_reg_t ro_ena : 1; - uint_reg_t ur_ena : 1; - uint_reg_t fatal_err_ena : 1; - uint_reg_t nf_err_ena : 1; - uint_reg_t cor_err_ena : 1; -#endif - }; - - uint_reg_t word; -} TRIO_PCIE_RC_DEVICE_CONTROL_t; -#endif /* !defined(__ASSEMBLER__) */ - -#endif /* !defined(__ARCH_TRIO_PCIE_RC_H__) */ diff --git a/arch/tile/include/arch/trio_pcie_rc_def.h b/arch/tile/include/arch/trio_pcie_rc_def.h deleted file mode 100644 index 74081a65b6f2..000000000000 --- a/arch/tile/include/arch/trio_pcie_rc_def.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_TRIO_PCIE_RC_DEF_H__ -#define __ARCH_TRIO_PCIE_RC_DEF_H__ -#define TRIO_PCIE_RC_DEVICE_CAP 0x0074 -#define TRIO_PCIE_RC_DEVICE_CONTROL 0x0078 -#define TRIO_PCIE_RC_DEVICE_ID_VEN_ID 0x0000 -#define TRIO_PCIE_RC_DEVICE_ID_VEN_ID__DEV_ID_SHIFT 16 -#define TRIO_PCIE_RC_REVISION_ID 0x0008 -#endif /* !defined(__ARCH_TRIO_PCIE_RC_DEF_H__) */ diff --git a/arch/tile/include/arch/trio_shm.h b/arch/tile/include/arch/trio_shm.h deleted file mode 100644 index 3382e38245af..000000000000 --- a/arch/tile/include/arch/trio_shm.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - - -#ifndef __ARCH_TRIO_SHM_H__ -#define __ARCH_TRIO_SHM_H__ - -#include -#include - -#ifndef __ASSEMBLER__ -/** - * TRIO DMA Descriptor. - * The TRIO DMA descriptor is written by software and consumed by hardware. - * It is used to specify the location of transaction data in the IO and Tile - * domains. - */ - -__extension__ -typedef union -{ - struct - { - /* Word 0 */ - -#ifndef __BIG_ENDIAN__ - /** Tile side virtual address. */ - int_reg_t va : 42; - /** - * Encoded size of buffer used on push DMA when C=1: - * 0 = 128 bytes - * 1 = 256 bytes - * 2 = 512 bytes - * 3 = 1024 bytes - * 4 = 1664 bytes - * 5 = 4096 bytes - * 6 = 10368 bytes - * 7 = 16384 bytes - */ - uint_reg_t bsz : 3; - /** - * Chaining designation. Always zero for pull DMA - * 0 : Unchained buffer pointer - * 1 : Chained buffer pointer. Next buffer descriptor (e.g. VA) stored - * in 1st 8-bytes in buffer. For chained buffers, first 8-bytes of each - * buffer contain the next buffer descriptor formatted exactly like a PDE - * buffer descriptor. This allows a chained PDE buffer to be sent using - * push DMA. - */ - uint_reg_t c : 1; - /** - * Notification interrupt will be delivered when the transaction has - * completed (all data has been read from or written to the Tile-side - * buffer). - */ - uint_reg_t notif : 1; - /** - * When 0, the XSIZE field specifies the total byte count for the - * transaction. When 1, the XSIZE field is encoded as 2^(N+14) for N in - * {0..6}: - * 0 = 16KB - * 1 = 32KB - * 2 = 64KB - * 3 = 128KB - * 4 = 256KB - * 5 = 512KB - * 6 = 1MB - * All other encodings of the XSIZE field are reserved when SMOD=1 - */ - uint_reg_t smod : 1; - /** - * Total number of bytes to move for this transaction. When SMOD=1, - * this field is encoded - see SMOD description. - */ - uint_reg_t xsize : 14; - /** Reserved. */ - uint_reg_t __reserved_0 : 1; - /** - * Generation number. Used to indicate a valid descriptor in ring. When - * a new descriptor is written into the ring, software must toggle this - * bit. The net effect is that the GEN bit being written into new - * descriptors toggles each time the ring tail pointer wraps. - */ - uint_reg_t gen : 1; -#else /* __BIG_ENDIAN__ */ - uint_reg_t gen : 1; - uint_reg_t __reserved_0 : 1; - uint_reg_t xsize : 14; - uint_reg_t smod : 1; - uint_reg_t notif : 1; - uint_reg_t c : 1; - uint_reg_t bsz : 3; - int_reg_t va : 42; -#endif - - /* Word 1 */ - -#ifndef __BIG_ENDIAN__ - /** IO-side address */ - uint_reg_t io_address : 64; -#else /* __BIG_ENDIAN__ */ - uint_reg_t io_address : 64; -#endif - - }; - - /** Word access */ - uint_reg_t words[2]; -} TRIO_DMA_DESC_t; -#endif /* !defined(__ASSEMBLER__) */ - -#endif /* !defined(__ARCH_TRIO_SHM_H__) */ diff --git a/arch/tile/include/arch/trio_shm_def.h b/arch/tile/include/arch/trio_shm_def.h deleted file mode 100644 index 72a59c88b06a..000000000000 --- a/arch/tile/include/arch/trio_shm_def.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_TRIO_SHM_DEF_H__ -#define __ARCH_TRIO_SHM_DEF_H__ -#endif /* !defined(__ARCH_TRIO_SHM_DEF_H__) */ diff --git a/arch/tile/include/arch/uart.h b/arch/tile/include/arch/uart.h deleted file mode 100644 index 07966970adad..000000000000 --- a/arch/tile/include/arch/uart.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_UART_H__ -#define __ARCH_UART_H__ - -#include -#include - -#ifndef __ASSEMBLER__ - -/* Divisor. */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* - * Baud Rate Divisor. Desired_baud_rate = REF_CLK frequency / (baud * - * 16). - * Note: REF_CLK is always 125 MHz, the default - * divisor = 68, baud rate = 125M/(68*16) = 115200 baud. - */ - uint_reg_t divisor : 12; - /* Reserved. */ - uint_reg_t __reserved : 52; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved : 52; - uint_reg_t divisor : 12; -#endif - }; - - uint_reg_t word; -} UART_DIVISOR_t; - -/* FIFO Count. */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* - * n: n active entries in the receive FIFO (max is 2**8). Each entry has - * 8 bits. - * 0: no active entry in the receive FIFO (that is empty). - */ - uint_reg_t rfifo_count : 9; - /* Reserved. */ - uint_reg_t __reserved_0 : 7; - /* - * n: n active entries in the transmit FIFO (max is 2**8). Each entry has - * 8 bits. - * 0: no active entry in the transmit FIFO (that is empty). - */ - uint_reg_t tfifo_count : 9; - /* Reserved. */ - uint_reg_t __reserved_1 : 7; - /* - * n: n active entries in the write FIFO (max is 2**2). Each entry has 8 - * bits. - * 0: no active entry in the write FIFO (that is empty). - */ - uint_reg_t wfifo_count : 3; - /* Reserved. */ - uint_reg_t __reserved_2 : 29; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_2 : 29; - uint_reg_t wfifo_count : 3; - uint_reg_t __reserved_1 : 7; - uint_reg_t tfifo_count : 9; - uint_reg_t __reserved_0 : 7; - uint_reg_t rfifo_count : 9; -#endif - }; - - uint_reg_t word; -} UART_FIFO_COUNT_t; - -/* FLAG. */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Reserved. */ - uint_reg_t __reserved_0 : 1; - /* 1: receive FIFO is empty */ - uint_reg_t rfifo_empty : 1; - /* 1: write FIFO is empty. */ - uint_reg_t wfifo_empty : 1; - /* 1: transmit FIFO is empty. */ - uint_reg_t tfifo_empty : 1; - /* 1: receive FIFO is full. */ - uint_reg_t rfifo_full : 1; - /* 1: write FIFO is full. */ - uint_reg_t wfifo_full : 1; - /* 1: transmit FIFO is full. */ - uint_reg_t tfifo_full : 1; - /* Reserved. */ - uint_reg_t __reserved_1 : 57; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_1 : 57; - uint_reg_t tfifo_full : 1; - uint_reg_t wfifo_full : 1; - uint_reg_t rfifo_full : 1; - uint_reg_t tfifo_empty : 1; - uint_reg_t wfifo_empty : 1; - uint_reg_t rfifo_empty : 1; - uint_reg_t __reserved_0 : 1; -#endif - }; - - uint_reg_t word; -} UART_FLAG_t; - -/* - * Interrupt Vector Mask. - * Each bit in this register corresponds to a specific interrupt. When set, - * the associated interrupt will not be dispatched. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Read data FIFO read and no data available */ - uint_reg_t rdat_err : 1; - /* Write FIFO was written but it was full */ - uint_reg_t wdat_err : 1; - /* Stop bit not found when current data was received */ - uint_reg_t frame_err : 1; - /* Parity error was detected when current data was received */ - uint_reg_t parity_err : 1; - /* Data was received but the receive FIFO was full */ - uint_reg_t rfifo_overflow : 1; - /* - * An almost full event is reached when data is to be written to the - * receive FIFO, and the receive FIFO has more than or equal to - * BUFFER_THRESHOLD.RFIFO_AFULL bytes. - */ - uint_reg_t rfifo_afull : 1; - /* Reserved. */ - uint_reg_t __reserved_0 : 1; - /* An entry in the transmit FIFO was popped */ - uint_reg_t tfifo_re : 1; - /* An entry has been pushed into the receive FIFO */ - uint_reg_t rfifo_we : 1; - /* An entry of the write FIFO has been popped */ - uint_reg_t wfifo_re : 1; - /* Rshim read receive FIFO in protocol mode */ - uint_reg_t rfifo_err : 1; - /* - * An almost empty event is reached when data is to be read from the - * transmit FIFO, and the transmit FIFO has less than or equal to - * BUFFER_THRESHOLD.TFIFO_AEMPTY bytes. - */ - uint_reg_t tfifo_aempty : 1; - /* Reserved. */ - uint_reg_t __reserved_1 : 52; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_1 : 52; - uint_reg_t tfifo_aempty : 1; - uint_reg_t rfifo_err : 1; - uint_reg_t wfifo_re : 1; - uint_reg_t rfifo_we : 1; - uint_reg_t tfifo_re : 1; - uint_reg_t __reserved_0 : 1; - uint_reg_t rfifo_afull : 1; - uint_reg_t rfifo_overflow : 1; - uint_reg_t parity_err : 1; - uint_reg_t frame_err : 1; - uint_reg_t wdat_err : 1; - uint_reg_t rdat_err : 1; -#endif - }; - - uint_reg_t word; -} UART_INTERRUPT_MASK_t; - -/* - * Interrupt vector, write-one-to-clear. - * Each bit in this register corresponds to a specific interrupt. Hardware - * sets the bit when the associated condition has occurred. Writing a 1 - * clears the status bit. - */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Read data FIFO read and no data available */ - uint_reg_t rdat_err : 1; - /* Write FIFO was written but it was full */ - uint_reg_t wdat_err : 1; - /* Stop bit not found when current data was received */ - uint_reg_t frame_err : 1; - /* Parity error was detected when current data was received */ - uint_reg_t parity_err : 1; - /* Data was received but the receive FIFO was full */ - uint_reg_t rfifo_overflow : 1; - /* - * Data was received and the receive FIFO is now almost full (more than - * BUFFER_THRESHOLD.RFIFO_AFULL bytes in it) - */ - uint_reg_t rfifo_afull : 1; - /* Reserved. */ - uint_reg_t __reserved_0 : 1; - /* An entry in the transmit FIFO was popped */ - uint_reg_t tfifo_re : 1; - /* An entry has been pushed into the receive FIFO */ - uint_reg_t rfifo_we : 1; - /* An entry of the write FIFO has been popped */ - uint_reg_t wfifo_re : 1; - /* Rshim read receive FIFO in protocol mode */ - uint_reg_t rfifo_err : 1; - /* - * Data was read from the transmit FIFO and now it is almost empty (less - * than or equal to BUFFER_THRESHOLD.TFIFO_AEMPTY bytes in it). - */ - uint_reg_t tfifo_aempty : 1; - /* Reserved. */ - uint_reg_t __reserved_1 : 52; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_1 : 52; - uint_reg_t tfifo_aempty : 1; - uint_reg_t rfifo_err : 1; - uint_reg_t wfifo_re : 1; - uint_reg_t rfifo_we : 1; - uint_reg_t tfifo_re : 1; - uint_reg_t __reserved_0 : 1; - uint_reg_t rfifo_afull : 1; - uint_reg_t rfifo_overflow : 1; - uint_reg_t parity_err : 1; - uint_reg_t frame_err : 1; - uint_reg_t wdat_err : 1; - uint_reg_t rdat_err : 1; -#endif - }; - - uint_reg_t word; -} UART_INTERRUPT_STATUS_t; - -/* Type. */ - -__extension__ -typedef union -{ - struct - { -#ifndef __BIG_ENDIAN__ - /* Number of stop bits, rx and tx */ - uint_reg_t sbits : 1; - /* Reserved. */ - uint_reg_t __reserved_0 : 1; - /* Data word size, rx and tx */ - uint_reg_t dbits : 1; - /* Reserved. */ - uint_reg_t __reserved_1 : 1; - /* Parity selection, rx and tx */ - uint_reg_t ptype : 3; - /* Reserved. */ - uint_reg_t __reserved_2 : 57; -#else /* __BIG_ENDIAN__ */ - uint_reg_t __reserved_2 : 57; - uint_reg_t ptype : 3; - uint_reg_t __reserved_1 : 1; - uint_reg_t dbits : 1; - uint_reg_t __reserved_0 : 1; - uint_reg_t sbits : 1; -#endif - }; - - uint_reg_t word; -} UART_TYPE_t; -#endif /* !defined(__ASSEMBLER__) */ - -#endif /* !defined(__ARCH_UART_H__) */ diff --git a/arch/tile/include/arch/uart_def.h b/arch/tile/include/arch/uart_def.h deleted file mode 100644 index 42bcaf535379..000000000000 --- a/arch/tile/include/arch/uart_def.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_UART_DEF_H__ -#define __ARCH_UART_DEF_H__ -#define UART_DIVISOR 0x0158 -#define UART_FIFO_COUNT 0x0110 -#define UART_FLAG 0x0108 -#define UART_INTERRUPT_MASK 0x0208 -#define UART_INTERRUPT_MASK__RDAT_ERR_SHIFT 0 -#define UART_INTERRUPT_MASK__RDAT_ERR_WIDTH 1 -#define UART_INTERRUPT_MASK__RDAT_ERR_RESET_VAL 1 -#define UART_INTERRUPT_MASK__RDAT_ERR_RMASK 0x1 -#define UART_INTERRUPT_MASK__RDAT_ERR_MASK 0x1 -#define UART_INTERRUPT_MASK__RDAT_ERR_FIELD 0,0 -#define UART_INTERRUPT_MASK__WDAT_ERR_SHIFT 1 -#define UART_INTERRUPT_MASK__WDAT_ERR_WIDTH 1 -#define UART_INTERRUPT_MASK__WDAT_ERR_RESET_VAL 1 -#define UART_INTERRUPT_MASK__WDAT_ERR_RMASK 0x1 -#define UART_INTERRUPT_MASK__WDAT_ERR_MASK 0x2 -#define UART_INTERRUPT_MASK__WDAT_ERR_FIELD 1,1 -#define UART_INTERRUPT_MASK__FRAME_ERR_SHIFT 2 -#define UART_INTERRUPT_MASK__FRAME_ERR_WIDTH 1 -#define UART_INTERRUPT_MASK__FRAME_ERR_RESET_VAL 1 -#define UART_INTERRUPT_MASK__FRAME_ERR_RMASK 0x1 -#define UART_INTERRUPT_MASK__FRAME_ERR_MASK 0x4 -#define UART_INTERRUPT_MASK__FRAME_ERR_FIELD 2,2 -#define UART_INTERRUPT_MASK__PARITY_ERR_SHIFT 3 -#define UART_INTERRUPT_MASK__PARITY_ERR_WIDTH 1 -#define UART_INTERRUPT_MASK__PARITY_ERR_RESET_VAL 1 -#define UART_INTERRUPT_MASK__PARITY_ERR_RMASK 0x1 -#define UART_INTERRUPT_MASK__PARITY_ERR_MASK 0x8 -#define UART_INTERRUPT_MASK__PARITY_ERR_FIELD 3,3 -#define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_SHIFT 4 -#define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_WIDTH 1 -#define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_RESET_VAL 1 -#define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_RMASK 0x1 -#define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_MASK 0x10 -#define UART_INTERRUPT_MASK__RFIFO_OVERFLOW_FIELD 4,4 -#define UART_INTERRUPT_MASK__RFIFO_AFULL_SHIFT 5 -#define UART_INTERRUPT_MASK__RFIFO_AFULL_WIDTH 1 -#define UART_INTERRUPT_MASK__RFIFO_AFULL_RESET_VAL 1 -#define UART_INTERRUPT_MASK__RFIFO_AFULL_RMASK 0x1 -#define UART_INTERRUPT_MASK__RFIFO_AFULL_MASK 0x20 -#define UART_INTERRUPT_MASK__RFIFO_AFULL_FIELD 5,5 -#define UART_INTERRUPT_MASK__TFIFO_RE_SHIFT 7 -#define UART_INTERRUPT_MASK__TFIFO_RE_WIDTH 1 -#define UART_INTERRUPT_MASK__TFIFO_RE_RESET_VAL 1 -#define UART_INTERRUPT_MASK__TFIFO_RE_RMASK 0x1 -#define UART_INTERRUPT_MASK__TFIFO_RE_MASK 0x80 -#define UART_INTERRUPT_MASK__TFIFO_RE_FIELD 7,7 -#define UART_INTERRUPT_MASK__RFIFO_WE_SHIFT 8 -#define UART_INTERRUPT_MASK__RFIFO_WE_WIDTH 1 -#define UART_INTERRUPT_MASK__RFIFO_WE_RESET_VAL 1 -#define UART_INTERRUPT_MASK__RFIFO_WE_RMASK 0x1 -#define UART_INTERRUPT_MASK__RFIFO_WE_MASK 0x100 -#define UART_INTERRUPT_MASK__RFIFO_WE_FIELD 8,8 -#define UART_INTERRUPT_MASK__WFIFO_RE_SHIFT 9 -#define UART_INTERRUPT_MASK__WFIFO_RE_WIDTH 1 -#define UART_INTERRUPT_MASK__WFIFO_RE_RESET_VAL 1 -#define UART_INTERRUPT_MASK__WFIFO_RE_RMASK 0x1 -#define UART_INTERRUPT_MASK__WFIFO_RE_MASK 0x200 -#define UART_INTERRUPT_MASK__WFIFO_RE_FIELD 9,9 -#define UART_INTERRUPT_MASK__RFIFO_ERR_SHIFT 10 -#define UART_INTERRUPT_MASK__RFIFO_ERR_WIDTH 1 -#define UART_INTERRUPT_MASK__RFIFO_ERR_RESET_VAL 1 -#define UART_INTERRUPT_MASK__RFIFO_ERR_RMASK 0x1 -#define UART_INTERRUPT_MASK__RFIFO_ERR_MASK 0x400 -#define UART_INTERRUPT_MASK__RFIFO_ERR_FIELD 10,10 -#define UART_INTERRUPT_MASK__TFIFO_AEMPTY_SHIFT 11 -#define UART_INTERRUPT_MASK__TFIFO_AEMPTY_WIDTH 1 -#define UART_INTERRUPT_MASK__TFIFO_AEMPTY_RESET_VAL 1 -#define UART_INTERRUPT_MASK__TFIFO_AEMPTY_RMASK 0x1 -#define UART_INTERRUPT_MASK__TFIFO_AEMPTY_MASK 0x800 -#define UART_INTERRUPT_MASK__TFIFO_AEMPTY_FIELD 11,11 -#define UART_INTERRUPT_STATUS 0x0200 -#define UART_RECEIVE_DATA 0x0148 -#define UART_TRANSMIT_DATA 0x0140 -#define UART_TYPE 0x0160 -#define UART_TYPE__SBITS_SHIFT 0 -#define UART_TYPE__SBITS_WIDTH 1 -#define UART_TYPE__SBITS_RESET_VAL 1 -#define UART_TYPE__SBITS_RMASK 0x1 -#define UART_TYPE__SBITS_MASK 0x1 -#define UART_TYPE__SBITS_FIELD 0,0 -#define UART_TYPE__SBITS_VAL_ONE_SBITS 0x0 -#define UART_TYPE__SBITS_VAL_TWO_SBITS 0x1 -#define UART_TYPE__DBITS_SHIFT 2 -#define UART_TYPE__DBITS_WIDTH 1 -#define UART_TYPE__DBITS_RESET_VAL 0 -#define UART_TYPE__DBITS_RMASK 0x1 -#define UART_TYPE__DBITS_MASK 0x4 -#define UART_TYPE__DBITS_FIELD 2,2 -#define UART_TYPE__DBITS_VAL_EIGHT_DBITS 0x0 -#define UART_TYPE__DBITS_VAL_SEVEN_DBITS 0x1 -#define UART_TYPE__PTYPE_SHIFT 4 -#define UART_TYPE__PTYPE_WIDTH 3 -#define UART_TYPE__PTYPE_RESET_VAL 3 -#define UART_TYPE__PTYPE_RMASK 0x7 -#define UART_TYPE__PTYPE_MASK 0x70 -#define UART_TYPE__PTYPE_FIELD 4,6 -#define UART_TYPE__PTYPE_VAL_NONE 0x0 -#define UART_TYPE__PTYPE_VAL_MARK 0x1 -#define UART_TYPE__PTYPE_VAL_SPACE 0x2 -#define UART_TYPE__PTYPE_VAL_EVEN 0x3 -#define UART_TYPE__PTYPE_VAL_ODD 0x4 -#endif /* !defined(__ARCH_UART_DEF_H__) */ diff --git a/arch/tile/include/arch/usb_host.h b/arch/tile/include/arch/usb_host.h deleted file mode 100644 index d09f32683962..000000000000 --- a/arch/tile/include/arch/usb_host.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_USB_HOST_H__ -#define __ARCH_USB_HOST_H__ - -#include -#include - -#ifndef __ASSEMBLER__ -#endif /* !defined(__ASSEMBLER__) */ - -#endif /* !defined(__ARCH_USB_HOST_H__) */ diff --git a/arch/tile/include/arch/usb_host_def.h b/arch/tile/include/arch/usb_host_def.h deleted file mode 100644 index aeed7753e8e1..000000000000 --- a/arch/tile/include/arch/usb_host_def.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Machine-generated file; do not edit. */ - -#ifndef __ARCH_USB_HOST_DEF_H__ -#define __ARCH_USB_HOST_DEF_H__ -#endif /* !defined(__ARCH_USB_HOST_DEF_H__) */ diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild deleted file mode 100644 index 414dfc3a1808..000000000000 --- a/arch/tile/include/asm/Kbuild +++ /dev/null @@ -1,18 +0,0 @@ -generic-y += bug.h -generic-y += bugs.h -generic-y += emergency-restart.h -generic-y += exec.h -generic-y += extable.h -generic-y += fb.h -generic-y += hw_irq.h -generic-y += irq_regs.h -generic-y += local.h -generic-y += local64.h -generic-y += mcs_spinlock.h -generic-y += mm-arch-hooks.h -generic-y += parport.h -generic-y += preempt.h -generic-y += seccomp.h -generic-y += serial.h -generic-y += trace_clock.h -generic-y += xor.h diff --git a/arch/tile/include/asm/asm-offsets.h b/arch/tile/include/asm/asm-offsets.h deleted file mode 100644 index d370ee36a182..000000000000 --- a/arch/tile/include/asm/asm-offsets.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/tile/include/asm/atomic.h b/arch/tile/include/asm/atomic.h deleted file mode 100644 index 8dda3c8ff5ab..000000000000 --- a/arch/tile/include/asm/atomic.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Atomic primitives. - */ - -#ifndef _ASM_TILE_ATOMIC_H -#define _ASM_TILE_ATOMIC_H - -#include - -#ifndef __ASSEMBLY__ - -#include -#include - -#define ATOMIC_INIT(i) { (i) } - -/** - * atomic_read - read atomic variable - * @v: pointer of type atomic_t - * - * Atomically reads the value of @v. - */ -static inline int atomic_read(const atomic_t *v) -{ - return READ_ONCE(v->counter); -} - -/** - * atomic_sub_return - subtract integer and return - * @v: pointer of type atomic_t - * @i: integer value to subtract - * - * Atomically subtracts @i from @v and returns @v - @i - */ -#define atomic_sub_return(i, v) atomic_add_return((int)(-(i)), (v)) - -#define atomic_fetch_sub(i, v) atomic_fetch_add(-(int)(i), (v)) - -/** - * atomic_sub - subtract integer from atomic variable - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v. - */ -#define atomic_sub(i, v) atomic_add((int)(-(i)), (v)) - -/** - * atomic_sub_and_test - subtract value from variable and test result - * @i: integer value to subtract - * @v: pointer of type atomic_t - * - * Atomically subtracts @i from @v and returns true if the result is - * zero, or false for all other cases. - */ -#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) - -/** - * atomic_inc_return - increment memory and return - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1 and returns the new value. - */ -#define atomic_inc_return(v) atomic_add_return(1, (v)) - -/** - * atomic_dec_return - decrement memory and return - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1 and returns the new value. - */ -#define atomic_dec_return(v) atomic_sub_return(1, (v)) - -/** - * atomic_inc - increment atomic variable - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1. - */ -#define atomic_inc(v) atomic_add(1, (v)) - -/** - * atomic_dec - decrement atomic variable - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1. - */ -#define atomic_dec(v) atomic_sub(1, (v)) - -/** - * atomic_dec_and_test - decrement and test - * @v: pointer of type atomic_t - * - * Atomically decrements @v by 1 and returns true if the result is 0. - */ -#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) - -/** - * atomic_inc_and_test - increment and test - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1 and returns true if the result is 0. - */ -#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) - -/** - * atomic_xchg - atomically exchange contents of memory with a new value - * @v: pointer of type atomic_t - * @i: integer value to store in memory - * - * Atomically sets @v to @i and returns old @v - */ -static inline int atomic_xchg(atomic_t *v, int n) -{ - return xchg(&v->counter, n); -} - -/** - * atomic_cmpxchg - atomically exchange contents of memory if it matches - * @v: pointer of type atomic_t - * @o: old value that memory should have - * @n: new value to write to memory if it matches - * - * Atomically checks if @v holds @o and replaces it with @n if so. - * Returns the old value at @v. - */ -static inline int atomic_cmpxchg(atomic_t *v, int o, int n) -{ - return cmpxchg(&v->counter, o, n); -} - -/** - * atomic_add_negative - add and test if negative - * @v: pointer of type atomic_t - * @i: integer value to add - * - * Atomically adds @i to @v and returns true if the result is - * negative, or false when result is greater than or equal to zero. - */ -#define atomic_add_negative(i, v) (atomic_add_return((i), (v)) < 0) - -#endif /* __ASSEMBLY__ */ - -#ifndef __tilegx__ -#include -#else -#include -#endif - -#ifndef __ASSEMBLY__ - -/** - * atomic64_xchg - atomically exchange contents of memory with a new value - * @v: pointer of type atomic64_t - * @i: integer value to store in memory - * - * Atomically sets @v to @i and returns old @v - */ -static inline long long atomic64_xchg(atomic64_t *v, long long n) -{ - return xchg64(&v->counter, n); -} - -/** - * atomic64_cmpxchg - atomically exchange contents of memory if it matches - * @v: pointer of type atomic64_t - * @o: old value that memory should have - * @n: new value to write to memory if it matches - * - * Atomically checks if @v holds @o and replaces it with @n if so. - * Returns the old value at @v. - */ -static inline long long atomic64_cmpxchg(atomic64_t *v, long long o, - long long n) -{ - return cmpxchg64(&v->counter, o, n); -} - -static inline long long atomic64_dec_if_positive(atomic64_t *v) -{ - long long c, old, dec; - - c = atomic64_read(v); - for (;;) { - dec = c - 1; - if (unlikely(dec < 0)) - break; - old = atomic64_cmpxchg((v), c, dec); - if (likely(old == c)) - break; - c = old; - } - return dec; -} - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_TILE_ATOMIC_H */ diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h deleted file mode 100644 index 53a423e7cb92..000000000000 --- a/arch/tile/include/asm/atomic_32.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Do not include directly; use . - */ - -#ifndef _ASM_TILE_ATOMIC_32_H -#define _ASM_TILE_ATOMIC_32_H - -#include -#include - -#ifndef __ASSEMBLY__ - -/** - * atomic_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic_t - * - * Atomically adds @i to @v. - */ -static inline void atomic_add(int i, atomic_t *v) -{ - _atomic_xchg_add(&v->counter, i); -} - -#define ATOMIC_OPS(op) \ -unsigned long _atomic_fetch_##op(volatile unsigned long *p, unsigned long mask); \ -static inline void atomic_##op(int i, atomic_t *v) \ -{ \ - _atomic_fetch_##op((unsigned long *)&v->counter, i); \ -} \ -static inline int atomic_fetch_##op(int i, atomic_t *v) \ -{ \ - smp_mb(); \ - return _atomic_fetch_##op((unsigned long *)&v->counter, i); \ -} - -ATOMIC_OPS(and) -ATOMIC_OPS(or) -ATOMIC_OPS(xor) - -#undef ATOMIC_OPS - -static inline int atomic_fetch_add(int i, atomic_t *v) -{ - smp_mb(); - return _atomic_xchg_add(&v->counter, i); -} - -/** - * atomic_add_return - add integer and return - * @v: pointer of type atomic_t - * @i: integer value to add - * - * Atomically adds @i to @v and returns @i + @v - */ -static inline int atomic_add_return(int i, atomic_t *v) -{ - smp_mb(); /* barrier for proper semantics */ - return _atomic_xchg_add(&v->counter, i) + i; -} - -/** - * __atomic_add_unless - add unless the number is already a given value - * @v: pointer of type atomic_t - * @a: the amount to add to v... - * @u: ...unless v is equal to u. - * - * Atomically adds @a to @v, so long as @v was not already @u. - * Returns the old value of @v. - */ -static inline int __atomic_add_unless(atomic_t *v, int a, int u) -{ - smp_mb(); /* barrier for proper semantics */ - return _atomic_xchg_add_unless(&v->counter, a, u); -} - -/** - * atomic_set - set atomic variable - * @v: pointer of type atomic_t - * @i: required value - * - * Atomically sets the value of @v to @i. - * - * atomic_set() can't be just a raw store, since it would be lost if it - * fell between the load and store of one of the other atomic ops. - */ -static inline void atomic_set(atomic_t *v, int n) -{ - _atomic_xchg(&v->counter, n); -} - -#define atomic_set_release(v, i) atomic_set((v), (i)) - -/* A 64bit atomic type */ - -typedef struct { - long long counter; -} atomic64_t; - -#define ATOMIC64_INIT(val) { (val) } - -/** - * atomic64_read - read atomic variable - * @v: pointer of type atomic64_t - * - * Atomically reads the value of @v. - */ -static inline long long atomic64_read(const atomic64_t *v) -{ - /* - * Requires an atomic op to read both 32-bit parts consistently. - * Casting away const is safe since the atomic support routines - * do not write to memory if the value has not been modified. - */ - return _atomic64_xchg_add((long long *)&v->counter, 0); -} - -/** - * atomic64_add - add integer to atomic variable - * @i: integer value to add - * @v: pointer of type atomic64_t - * - * Atomically adds @i to @v. - */ -static inline void atomic64_add(long long i, atomic64_t *v) -{ - _atomic64_xchg_add(&v->counter, i); -} - -#define ATOMIC64_OPS(op) \ -long long _atomic64_fetch_##op(long long *v, long long n); \ -static inline void atomic64_##op(long long i, atomic64_t *v) \ -{ \ - _atomic64_fetch_##op(&v->counter, i); \ -} \ -static inline long long atomic64_fetch_##op(long long i, atomic64_t *v) \ -{ \ - smp_mb(); \ - return _atomic64_fetch_##op(&v->counter, i); \ -} - -ATOMIC64_OPS(and) -ATOMIC64_OPS(or) -ATOMIC64_OPS(xor) - -#undef ATOMIC64_OPS - -static inline long long atomic64_fetch_add(long long i, atomic64_t *v) -{ - smp_mb(); - return _atomic64_xchg_add(&v->counter, i); -} - -/** - * atomic64_add_return - add integer and return - * @v: pointer of type atomic64_t - * @i: integer value to add - * - * Atomically adds @i to @v and returns @i + @v - */ -static inline long long atomic64_add_return(long long i, atomic64_t *v) -{ - smp_mb(); /* barrier for proper semantics */ - return _atomic64_xchg_add(&v->counter, i) + i; -} - -/** - * atomic64_add_unless - add unless the number is already a given value - * @v: pointer of type atomic64_t - * @a: the amount to add to v... - * @u: ...unless v is equal to u. - * - * Atomically adds @a to @v, so long as @v was not already @u. - * Returns non-zero if @v was not @u, and zero otherwise. - */ -static inline long long atomic64_add_unless(atomic64_t *v, long long a, - long long u) -{ - smp_mb(); /* barrier for proper semantics */ - return _atomic64_xchg_add_unless(&v->counter, a, u) != u; -} - -/** - * atomic64_set - set atomic variable - * @v: pointer of type atomic64_t - * @i: required value - * - * Atomically sets the value of @v to @i. - * - * atomic64_set() can't be just a raw store, since it would be lost if it - * fell between the load and store of one of the other atomic ops. - */ -static inline void atomic64_set(atomic64_t *v, long long n) -{ - _atomic64_xchg(&v->counter, n); -} - -#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) -#define atomic64_inc(v) atomic64_add(1LL, (v)) -#define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) -#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) -#define atomic64_sub_return(i, v) atomic64_add_return(-(i), (v)) -#define atomic64_fetch_sub(i, v) atomic64_fetch_add(-(i), (v)) -#define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) -#define atomic64_sub(i, v) atomic64_add(-(i), (v)) -#define atomic64_dec(v) atomic64_sub(1LL, (v)) -#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) -#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) -#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) - -#endif /* !__ASSEMBLY__ */ - -/* - * Internal definitions only beyond this point. - */ - -/* - * Number of atomic locks in atomic_locks[]. Must be a power of two. - * There is no reason for more than PAGE_SIZE / 8 entries, since that - * is the maximum number of pointer bits we can use to index this. - * And we cannot have more than PAGE_SIZE / 4, since this has to - * fit on a single page and each entry takes 4 bytes. - */ -#define ATOMIC_HASH_SHIFT (PAGE_SHIFT - 3) -#define ATOMIC_HASH_SIZE (1 << ATOMIC_HASH_SHIFT) - -#ifndef __ASSEMBLY__ -extern int atomic_locks[]; -#endif - -/* - * All the code that may fault while holding an atomic lock must - * place the pointer to the lock in ATOMIC_LOCK_REG so the fault code - * can correctly release and reacquire the lock. Note that we - * mention the register number in a comment in "lib/atomic_asm.S" to help - * assembly coders from using this register by mistake, so if it - * is changed here, change that comment as well. - */ -#define ATOMIC_LOCK_REG 20 -#define ATOMIC_LOCK_REG_NAME r20 - -#ifndef __ASSEMBLY__ -/* Called from setup to initialize a hash table to point to per_cpu locks. */ -void __init_atomic_per_cpu(void); - -#ifdef CONFIG_SMP -/* Support releasing the atomic lock in do_page_fault_ics(). */ -void __atomic_fault_unlock(int *lock_ptr); -#endif - -/* Return a pointer to the lock for the given address. */ -int *__atomic_hashed_lock(volatile void *v); - -/* Private helper routines in lib/atomic_asm_32.S */ -struct __get_user { - unsigned long val; - int err; -}; -extern struct __get_user __atomic32_cmpxchg(volatile int *p, - int *lock, int o, int n); -extern struct __get_user __atomic32_xchg(volatile int *p, int *lock, int n); -extern struct __get_user __atomic32_xchg_add(volatile int *p, int *lock, int n); -extern struct __get_user __atomic32_xchg_add_unless(volatile int *p, - int *lock, int o, int n); -extern struct __get_user __atomic32_fetch_or(volatile int *p, int *lock, int n); -extern struct __get_user __atomic32_fetch_and(volatile int *p, int *lock, int n); -extern struct __get_user __atomic32_fetch_andn(volatile int *p, int *lock, int n); -extern struct __get_user __atomic32_fetch_xor(volatile int *p, int *lock, int n); -extern long long __atomic64_cmpxchg(volatile long long *p, int *lock, - long long o, long long n); -extern long long __atomic64_xchg(volatile long long *p, int *lock, long long n); -extern long long __atomic64_xchg_add(volatile long long *p, int *lock, - long long n); -extern long long __atomic64_xchg_add_unless(volatile long long *p, - int *lock, long long o, long long n); -extern long long __atomic64_fetch_and(volatile long long *p, int *lock, long long n); -extern long long __atomic64_fetch_or(volatile long long *p, int *lock, long long n); -extern long long __atomic64_fetch_xor(volatile long long *p, int *lock, long long n); - -/* Return failure from the atomic wrappers. */ -struct __get_user __atomic_bad_address(int __user *addr); - -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASM_TILE_ATOMIC_32_H */ diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h deleted file mode 100644 index 4cefa0c9fd81..000000000000 --- a/arch/tile/include/asm/atomic_64.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Do not include directly; use . - */ - -#ifndef _ASM_TILE_ATOMIC_64_H -#define _ASM_TILE_ATOMIC_64_H - -#ifndef __ASSEMBLY__ - -#include -#include - -/* First, the 32-bit atomic ops that are "real" on our 64-bit platform. */ - -#define atomic_set(v, i) WRITE_ONCE((v)->counter, (i)) - -/* - * The smp_mb() operations throughout are to support the fact that - * Linux requires memory barriers before and after the operation, - * on any routine which updates memory and returns a value. - */ - -/* - * Note a subtlety of the locking here. We are required to provide a - * full memory barrier before and after the operation. However, we - * only provide an explicit mb before the operation. After the - * operation, we use barrier() to get a full mb for free, because: - * - * (1) The barrier directive to the compiler prohibits any instructions - * being statically hoisted before the barrier; - * (2) the microarchitecture will not issue any further instructions - * until the fetchadd result is available for the "+ i" add instruction; - * (3) the smb_mb before the fetchadd ensures that no other memory - * operations are in flight at this point. - */ -static inline int atomic_add_return(int i, atomic_t *v) -{ - int val; - smp_mb(); /* barrier for proper semantics */ - val = __insn_fetchadd4((void *)&v->counter, i) + i; - barrier(); /* equivalent to smp_mb(); see block comment above */ - return val; -} - -#define ATOMIC_OPS(op) \ -static inline int atomic_fetch_##op(int i, atomic_t *v) \ -{ \ - int val; \ - smp_mb(); \ - val = __insn_fetch##op##4((void *)&v->counter, i); \ - smp_mb(); \ - return val; \ -} \ -static inline void atomic_##op(int i, atomic_t *v) \ -{ \ - __insn_fetch##op##4((void *)&v->counter, i); \ -} - -ATOMIC_OPS(add) -ATOMIC_OPS(and) -ATOMIC_OPS(or) - -#undef ATOMIC_OPS - -static inline int atomic_fetch_xor(int i, atomic_t *v) -{ - int guess, oldval = v->counter; - smp_mb(); - do { - guess = oldval; - __insn_mtspr(SPR_CMPEXCH_VALUE, guess); - oldval = __insn_cmpexch4(&v->counter, guess ^ i); - } while (guess != oldval); - smp_mb(); - return oldval; -} - -static inline void atomic_xor(int i, atomic_t *v) -{ - int guess, oldval = v->counter; - do { - guess = oldval; - __insn_mtspr(SPR_CMPEXCH_VALUE, guess); - oldval = __insn_cmpexch4(&v->counter, guess ^ i); - } while (guess != oldval); -} - -static inline int __atomic_add_unless(atomic_t *v, int a, int u) -{ - int guess, oldval = v->counter; - do { - if (oldval == u) - break; - guess = oldval; - oldval = cmpxchg(&v->counter, guess, guess + a); - } while (guess != oldval); - return oldval; -} - -/* Now the true 64-bit operations. */ - -#define ATOMIC64_INIT(i) { (i) } - -#define atomic64_read(v) READ_ONCE((v)->counter) -#define atomic64_set(v, i) WRITE_ONCE((v)->counter, (i)) - -static inline long atomic64_add_return(long i, atomic64_t *v) -{ - int val; - smp_mb(); /* barrier for proper semantics */ - val = __insn_fetchadd((void *)&v->counter, i) + i; - barrier(); /* equivalent to smp_mb; see atomic_add_return() */ - return val; -} - -#define ATOMIC64_OPS(op) \ -static inline long atomic64_fetch_##op(long i, atomic64_t *v) \ -{ \ - long val; \ - smp_mb(); \ - val = __insn_fetch##op((void *)&v->counter, i); \ - smp_mb(); \ - return val; \ -} \ -static inline void atomic64_##op(long i, atomic64_t *v) \ -{ \ - __insn_fetch##op((void *)&v->counter, i); \ -} - -ATOMIC64_OPS(add) -ATOMIC64_OPS(and) -ATOMIC64_OPS(or) - -#undef ATOMIC64_OPS - -static inline long atomic64_fetch_xor(long i, atomic64_t *v) -{ - long guess, oldval = v->counter; - smp_mb(); - do { - guess = oldval; - __insn_mtspr(SPR_CMPEXCH_VALUE, guess); - oldval = __insn_cmpexch(&v->counter, guess ^ i); - } while (guess != oldval); - smp_mb(); - return oldval; -} - -static inline void atomic64_xor(long i, atomic64_t *v) -{ - long guess, oldval = v->counter; - do { - guess = oldval; - __insn_mtspr(SPR_CMPEXCH_VALUE, guess); - oldval = __insn_cmpexch(&v->counter, guess ^ i); - } while (guess != oldval); -} - -static inline long atomic64_add_unless(atomic64_t *v, long a, long u) -{ - long guess, oldval = v->counter; - do { - if (oldval == u) - break; - guess = oldval; - oldval = cmpxchg(&v->counter, guess, guess + a); - } while (guess != oldval); - return oldval != u; -} - -#define atomic64_sub_return(i, v) atomic64_add_return(-(i), (v)) -#define atomic64_fetch_sub(i, v) atomic64_fetch_add(-(i), (v)) -#define atomic64_sub(i, v) atomic64_add(-(i), (v)) -#define atomic64_inc_return(v) atomic64_add_return(1, (v)) -#define atomic64_dec_return(v) atomic64_sub_return(1, (v)) -#define atomic64_inc(v) atomic64_add(1, (v)) -#define atomic64_dec(v) atomic64_sub(1, (v)) - -#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) -#define atomic64_dec_and_test(v) (atomic64_dec_return(v) == 0) -#define atomic64_sub_and_test(i, v) (atomic64_sub_return((i), (v)) == 0) -#define atomic64_add_negative(i, v) (atomic64_add_return((i), (v)) < 0) - -#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) - -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASM_TILE_ATOMIC_64_H */ diff --git a/arch/tile/include/asm/backtrace.h b/arch/tile/include/asm/backtrace.h deleted file mode 100644 index bd5399a69edf..000000000000 --- a/arch/tile/include/asm/backtrace.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_BACKTRACE_H -#define _ASM_TILE_BACKTRACE_H - -#include - -/* Reads 'size' bytes from 'address' and writes the data to 'result'. - * Returns true if successful, else false (e.g. memory not readable). - */ -typedef bool (*BacktraceMemoryReader)(void *result, - unsigned long address, - unsigned int size, - void *extra); - -typedef struct { - /* Current PC. */ - unsigned long pc; - - /* Current stack pointer value. */ - unsigned long sp; - - /* Current frame pointer value (i.e. caller's stack pointer) */ - unsigned long fp; - - /* Internal use only: caller's PC for first frame. */ - unsigned long initial_frame_caller_pc; - - /* Internal use only: callback to read memory. */ - BacktraceMemoryReader read_memory_func; - - /* Internal use only: arbitrary argument to read_memory_func. */ - void *read_memory_func_extra; - -} BacktraceIterator; - - -typedef enum { - - /* We have no idea what the caller's pc is. */ - PC_LOC_UNKNOWN, - - /* The caller's pc is currently in lr. */ - PC_LOC_IN_LR, - - /* The caller's pc can be found by dereferencing the caller's sp. */ - PC_LOC_ON_STACK - -} CallerPCLocation; - - -typedef enum { - - /* We have no idea what the caller's sp is. */ - SP_LOC_UNKNOWN, - - /* The caller's sp is currently in r52. */ - SP_LOC_IN_R52, - - /* The caller's sp can be found by adding a certain constant - * to the current value of sp. - */ - SP_LOC_OFFSET - -} CallerSPLocation; - - -/* Bit values ORed into CALLER_* values for info ops. */ -enum { - /* Setting the low bit on any of these values means the info op - * applies only to one bundle ago. - */ - ONE_BUNDLE_AGO_FLAG = 1, - - /* Setting this bit on a CALLER_SP_* value means the PC is in LR. - * If not set, PC is on the stack. - */ - PC_IN_LR_FLAG = 2, - - /* This many of the low bits of a CALLER_SP_* value are for the - * flag bits above. - */ - NUM_INFO_OP_FLAGS = 2, - - /* We cannot have one in the memory pipe so this is the maximum. */ - MAX_INFO_OPS_PER_BUNDLE = 2 -}; - - -/* Internal constants used to define 'info' operands. */ -enum { - /* 0 and 1 are reserved, as are all negative numbers. */ - - CALLER_UNKNOWN_BASE = 2, - - CALLER_SP_IN_R52_BASE = 4, - - CALLER_SP_OFFSET_BASE = 8, -}; - - -/* Current backtracer state describing where it thinks the caller is. */ -typedef struct { - /* - * Public fields - */ - - /* How do we find the caller's PC? */ - CallerPCLocation pc_location : 8; - - /* How do we find the caller's SP? */ - CallerSPLocation sp_location : 8; - - /* If sp_location == SP_LOC_OFFSET, then caller_sp == sp + - * loc->sp_offset. Else this field is undefined. - */ - uint16_t sp_offset; - - /* In the most recently visited bundle a terminating bundle? */ - bool at_terminating_bundle; - - /* - * Private fields - */ - - /* Will the forward scanner see someone clobbering sp - * (i.e. changing it with something other than addi sp, sp, N?) - */ - bool sp_clobber_follows; - - /* Operand to next "visible" info op (no more than one bundle past - * the next terminating bundle), or -32768 if none. - */ - int16_t next_info_operand; - - /* Is the info of in next_info_op in the very next bundle? */ - bool is_next_info_operand_adjacent; - -} CallerLocation; - -extern void backtrace_init(BacktraceIterator *state, - BacktraceMemoryReader read_memory_func, - void *read_memory_func_extra, - unsigned long pc, unsigned long lr, - unsigned long sp, unsigned long r52); - - -extern bool backtrace_next(BacktraceIterator *state); - -#endif /* _ASM_TILE_BACKTRACE_H */ diff --git a/arch/tile/include/asm/barrier.h b/arch/tile/include/asm/barrier.h deleted file mode 100644 index 4c419ab95ab7..000000000000 --- a/arch/tile/include/asm/barrier.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_BARRIER_H -#define _ASM_TILE_BARRIER_H - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -#define __sync() __insn_mf() - -#include -/* - * Issue an uncacheable load to each memory controller, then - * wait until those loads have completed. - */ -static inline void __mb_incoherent(void) -{ - long clobber_r10; - asm volatile("swint2" - : "=R10" (clobber_r10) - : "R10" (HV_SYS_fence_incoherent) - : "r0", "r1", "r2", "r3", "r4", - "r5", "r6", "r7", "r8", "r9", - "r11", "r12", "r13", "r14", - "r15", "r16", "r17", "r18", "r19", - "r20", "r21", "r22", "r23", "r24", - "r25", "r26", "r27", "r28", "r29"); -} - -/* Fence to guarantee visibility of stores to incoherent memory. */ -static inline void -mb_incoherent(void) -{ - __insn_mf(); - - { -#if CHIP_HAS_TILE_WRITE_PENDING() - const unsigned long WRITE_TIMEOUT_CYCLES = 400; - unsigned long start = get_cycles_low(); - do { - if (__insn_mfspr(SPR_TILE_WRITE_PENDING) == 0) - return; - } while ((get_cycles_low() - start) < WRITE_TIMEOUT_CYCLES); -#endif /* CHIP_HAS_TILE_WRITE_PENDING() */ - (void) __mb_incoherent(); - } -} - -#define fast_wmb() __sync() -#define fast_rmb() __sync() -#define fast_mb() __sync() -#define fast_iob() mb_incoherent() - -#define wmb() fast_wmb() -#define rmb() fast_rmb() -#define mb() fast_mb() -#define iob() fast_iob() - -#ifndef __tilegx__ /* 32 bit */ -/* - * We need to barrier before modifying the word, since the _atomic_xxx() - * routines just tns the lock and then read/modify/write of the word. - * But after the word is updated, the routine issues an "mf" before returning, - * and since it's a function call, we don't even need a compiler barrier. - */ -#define __smp_mb__before_atomic() __smp_mb() -#define __smp_mb__after_atomic() do { } while (0) -#define smp_mb__after_atomic() __smp_mb__after_atomic() -#else /* 64 bit */ -#define __smp_mb__before_atomic() __smp_mb() -#define __smp_mb__after_atomic() __smp_mb() -#endif - -/* - * The TILE architecture does not do speculative reads; this ensures - * that a control dependency also orders against loads and already provides - * a LOAD->{LOAD,STORE} order and can forgo the additional RMB. - */ -#define smp_acquire__after_ctrl_dep() barrier() - -#include - -#endif /* !__ASSEMBLY__ */ -#endif /* _ASM_TILE_BARRIER_H */ diff --git a/arch/tile/include/asm/bitops.h b/arch/tile/include/asm/bitops.h deleted file mode 100644 index 20caa346ac06..000000000000 --- a/arch/tile/include/asm/bitops.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 1992, Linus Torvalds. - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_BITOPS_H -#define _ASM_TILE_BITOPS_H - -#include -#include - -#ifndef _LINUX_BITOPS_H -#error only can be included directly -#endif - -#ifdef __tilegx__ -#include -#else -#include -#endif - -/** - * ffz - find first zero bit in word - * @word: The word to search - * - * Undefined if no zero exists, so code should check against ~0UL first. - */ -static inline unsigned long ffz(unsigned long word) -{ - return __builtin_ctzl(~word); -} - -static inline int fls64(__u64 w) -{ - return (sizeof(__u64) * 8) - __builtin_clzll(w); -} - -/** - * fls - find last set bit in word - * @x: the word to search - * - * This is defined in a similar way as the libc and compiler builtin - * ffs, but returns the position of the most significant set bit. - * - * fls(value) returns 0 if value is 0 or the position of the last - * set bit if value is nonzero. The last (most significant) bit is - * at position 32. - */ -static inline int fls(int x) -{ - return fls64((unsigned int) x); -} - -static inline unsigned int __arch_hweight32(unsigned int w) -{ - return __builtin_popcount(w); -} - -static inline unsigned int __arch_hweight16(unsigned int w) -{ - return __builtin_popcount(w & 0xffff); -} - -static inline unsigned int __arch_hweight8(unsigned int w) -{ - return __builtin_popcount(w & 0xff); -} - -static inline unsigned long __arch_hweight64(__u64 w) -{ - return __builtin_popcountll(w); -} - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#endif /* _ASM_TILE_BITOPS_H */ diff --git a/arch/tile/include/asm/bitops_32.h b/arch/tile/include/asm/bitops_32.h deleted file mode 100644 index d1406a95f6b7..000000000000 --- a/arch/tile/include/asm/bitops_32.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_BITOPS_32_H -#define _ASM_TILE_BITOPS_32_H - -#include -#include - -/* Tile-specific routines to support . */ -unsigned long _atomic_fetch_or(volatile unsigned long *p, unsigned long mask); -unsigned long _atomic_fetch_andn(volatile unsigned long *p, unsigned long mask); -unsigned long _atomic_fetch_xor(volatile unsigned long *p, unsigned long mask); - -/** - * set_bit - Atomically set a bit in memory - * @nr: the bit to set - * @addr: the address to start counting from - * - * This function is atomic and may not be reordered. - * See __set_bit() if you do not require the atomic guarantees. - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - */ -static inline void set_bit(unsigned nr, volatile unsigned long *addr) -{ - _atomic_fetch_or(addr + BIT_WORD(nr), BIT_MASK(nr)); -} - -/** - * clear_bit - Clears a bit in memory - * @nr: Bit to clear - * @addr: Address to start counting from - * - * clear_bit() is atomic and may not be reordered. - * See __clear_bit() if you do not require the atomic guarantees. - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - * - * clear_bit() may not contain a memory barrier, so if it is used for - * locking purposes, you should call smp_mb__before_atomic() and/or - * smp_mb__after_atomic() to ensure changes are visible on other cpus. - */ -static inline void clear_bit(unsigned nr, volatile unsigned long *addr) -{ - _atomic_fetch_andn(addr + BIT_WORD(nr), BIT_MASK(nr)); -} - -/** - * change_bit - Toggle a bit in memory - * @nr: Bit to change - * @addr: Address to start counting from - * - * change_bit() is atomic and may not be reordered. - * See __change_bit() if you do not require the atomic guarantees. - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - */ -static inline void change_bit(unsigned nr, volatile unsigned long *addr) -{ - _atomic_fetch_xor(addr + BIT_WORD(nr), BIT_MASK(nr)); -} - -/** - * test_and_set_bit - Set a bit and return its old value - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ -static inline int test_and_set_bit(unsigned nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - addr += BIT_WORD(nr); - smp_mb(); /* barrier for proper semantics */ - return (_atomic_fetch_or(addr, mask) & mask) != 0; -} - -/** - * test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to clear - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ -static inline int test_and_clear_bit(unsigned nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - addr += BIT_WORD(nr); - smp_mb(); /* barrier for proper semantics */ - return (_atomic_fetch_andn(addr, mask) & mask) != 0; -} - -/** - * test_and_change_bit - Change a bit and return its old value - * @nr: Bit to change - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ -static inline int test_and_change_bit(unsigned nr, - volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - addr += BIT_WORD(nr); - smp_mb(); /* barrier for proper semantics */ - return (_atomic_fetch_xor(addr, mask) & mask) != 0; -} - -#include - -#endif /* _ASM_TILE_BITOPS_32_H */ diff --git a/arch/tile/include/asm/bitops_64.h b/arch/tile/include/asm/bitops_64.h deleted file mode 100644 index bb1a29221fcd..000000000000 --- a/arch/tile/include/asm/bitops_64.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_BITOPS_64_H -#define _ASM_TILE_BITOPS_64_H - -#include -#include - -/* See for API comments. */ - -static inline void set_bit(unsigned nr, volatile unsigned long *addr) -{ - unsigned long mask = (1UL << (nr % BITS_PER_LONG)); - __insn_fetchor((void *)(addr + nr / BITS_PER_LONG), mask); -} - -static inline void clear_bit(unsigned nr, volatile unsigned long *addr) -{ - unsigned long mask = (1UL << (nr % BITS_PER_LONG)); - __insn_fetchand((void *)(addr + nr / BITS_PER_LONG), ~mask); -} - -static inline void change_bit(unsigned nr, volatile unsigned long *addr) -{ - unsigned long mask = (1UL << (nr % BITS_PER_LONG)); - unsigned long guess, oldval; - addr += nr / BITS_PER_LONG; - oldval = *addr; - do { - guess = oldval; - oldval = cmpxchg(addr, guess, guess ^ mask); - } while (guess != oldval); -} - - -/* - * The test_and_xxx_bit() routines require a memory fence before we - * start the operation, and after the operation completes. We use - * smp_mb() before, and rely on the "!= 0" comparison, plus a compiler - * barrier(), to block until the atomic op is complete. - */ - -static inline int test_and_set_bit(unsigned nr, volatile unsigned long *addr) -{ - int val; - unsigned long mask = (1UL << (nr % BITS_PER_LONG)); - smp_mb(); /* barrier for proper semantics */ - val = (__insn_fetchor((void *)(addr + nr / BITS_PER_LONG), mask) - & mask) != 0; - barrier(); - return val; -} - - -static inline int test_and_clear_bit(unsigned nr, volatile unsigned long *addr) -{ - int val; - unsigned long mask = (1UL << (nr % BITS_PER_LONG)); - smp_mb(); /* barrier for proper semantics */ - val = (__insn_fetchand((void *)(addr + nr / BITS_PER_LONG), ~mask) - & mask) != 0; - barrier(); - return val; -} - - -static inline int test_and_change_bit(unsigned nr, - volatile unsigned long *addr) -{ - unsigned long mask = (1UL << (nr % BITS_PER_LONG)); - unsigned long guess, oldval; - addr += nr / BITS_PER_LONG; - oldval = *addr; - do { - guess = oldval; - oldval = cmpxchg(addr, guess, guess ^ mask); - } while (guess != oldval); - return (oldval & mask) != 0; -} - -#include - -#endif /* _ASM_TILE_BITOPS_64_H */ diff --git a/arch/tile/include/asm/cache.h b/arch/tile/include/asm/cache.h deleted file mode 100644 index 7d6aaa128e8b..000000000000 --- a/arch/tile/include/asm/cache.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_CACHE_H -#define _ASM_TILE_CACHE_H - -#include - -/* bytes per L1 data cache line */ -#define L1_CACHE_SHIFT CHIP_L1D_LOG_LINE_SIZE() -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) - -/* bytes per L2 cache line */ -#define L2_CACHE_SHIFT CHIP_L2_LOG_LINE_SIZE() -#define L2_CACHE_BYTES (1 << L2_CACHE_SHIFT) -#define L2_CACHE_ALIGN(x) (((x)+(L2_CACHE_BYTES-1)) & -L2_CACHE_BYTES) - -/* - * TILEPro I/O is not always coherent (networking typically uses coherent - * I/O, but PCI traffic does not) and setting ARCH_DMA_MINALIGN to the - * L2 cacheline size helps ensure that kernel heap allocations are aligned. - * TILE-Gx I/O is always coherent when used on hash-for-home pages. - * - * However, it's possible at runtime to request not to use hash-for-home - * for the kernel heap, in which case the kernel will use flush-and-inval - * to manage coherence. As a result, we use L2_CACHE_BYTES for the - * DMA minimum alignment to avoid false sharing in the kernel heap. - */ -#define ARCH_DMA_MINALIGN L2_CACHE_BYTES - -/* use the cache line size for the L2, which is where it counts */ -#define SMP_CACHE_BYTES_SHIFT L2_CACHE_SHIFT -#define SMP_CACHE_BYTES L2_CACHE_BYTES -#define INTERNODE_CACHE_SHIFT L2_CACHE_SHIFT -#define INTERNODE_CACHE_BYTES L2_CACHE_BYTES - -/* Group together read-mostly things to avoid cache false sharing */ -#define __read_mostly __attribute__((__section__(".data..read_mostly"))) - -/* - * Originally we used small TLB pages for kernel data and grouped some - * things together as ro-after-init, enforcing the property at the end - * of initialization by making those pages read-only and non-coherent. - * This allowed better cache utilization since cache inclusion did not - * need to be maintained. However, to do this requires an extra TLB - * entry, which on balance is more of a performance hit than the - * non-coherence is a performance gain, so we now just make "read - * mostly" and "ro-after-init" be synonyms. We keep the attribute - * separate in case we change our minds at a future date. - */ -#define __ro_after_init __read_mostly - -#endif /* _ASM_TILE_CACHE_H */ diff --git a/arch/tile/include/asm/cacheflush.h b/arch/tile/include/asm/cacheflush.h deleted file mode 100644 index 92ee4c8a4f76..000000000000 --- a/arch/tile/include/asm/cacheflush.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_CACHEFLUSH_H -#define _ASM_TILE_CACHEFLUSH_H - -#include - -/* Keep includes the same across arches. */ -#include -#include -#include - -/* Caches are physically-indexed and so don't need special treatment */ -#define flush_cache_all() do { } while (0) -#define flush_cache_mm(mm) do { } while (0) -#define flush_cache_dup_mm(mm) do { } while (0) -#define flush_cache_range(vma, start, end) do { } while (0) -#define flush_cache_page(vma, vmaddr, pfn) do { } while (0) -#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 -#define flush_dcache_page(page) do { } while (0) -#define flush_dcache_mmap_lock(mapping) do { } while (0) -#define flush_dcache_mmap_unlock(mapping) do { } while (0) -#define flush_cache_vmap(start, end) do { } while (0) -#define flush_cache_vunmap(start, end) do { } while (0) -#define flush_icache_page(vma, pg) do { } while (0) -#define flush_icache_user_range(vma, pg, adr, len) do { } while (0) - -/* Flush the icache just on this cpu */ -extern void __flush_icache_range(unsigned long start, unsigned long end); - -/* Flush the entire icache on this cpu. */ -#define __flush_icache() __flush_icache_range(0, CHIP_L1I_CACHE_SIZE()) - -#ifdef CONFIG_SMP -/* - * When the kernel writes to its own text we need to do an SMP - * broadcast to make the L1I coherent everywhere. This includes - * module load and single step. - */ -extern void flush_icache_range(unsigned long start, unsigned long end); -#else -#define flush_icache_range __flush_icache_range -#endif - -/* - * An update to an executable user page requires icache flushing. - * We could carefully update only tiles that are running this process, - * and rely on the fact that we flush the icache on every context - * switch to avoid doing extra work here. But for now, I'll be - * conservative and just do a global icache flush. - */ -static inline void copy_to_user_page(struct vm_area_struct *vma, - struct page *page, unsigned long vaddr, - void *dst, void *src, int len) -{ - memcpy(dst, src, len); - if (vma->vm_flags & VM_EXEC) { - flush_icache_range((unsigned long) dst, - (unsigned long) dst + len); - } -} - -#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ - memcpy((dst), (src), (len)) - -/* Flush a VA range; pads to L2 cacheline boundaries. */ -static inline void __flush_buffer(void *buffer, size_t size) -{ - char *next = (char *)((long)buffer & -L2_CACHE_BYTES); - char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size); - while (next < finish) { - __insn_flush(next); - next += CHIP_FLUSH_STRIDE(); - } -} - -/* Flush & invalidate a VA range; pads to L2 cacheline boundaries. */ -static inline void __finv_buffer(void *buffer, size_t size) -{ - char *next = (char *)((long)buffer & -L2_CACHE_BYTES); - char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size); - while (next < finish) { - __insn_finv(next); - next += CHIP_FINV_STRIDE(); - } -} - - -/* - * Flush a locally-homecached VA range and wait for the evicted - * cachelines to hit memory. - */ -static inline void flush_buffer_local(void *buffer, size_t size) -{ - __flush_buffer(buffer, size); - mb_incoherent(); -} - -/* - * Flush and invalidate a locally-homecached VA range and wait for the - * evicted cachelines to hit memory. - */ -static inline void finv_buffer_local(void *buffer, size_t size) -{ - __finv_buffer(buffer, size); - mb_incoherent(); -} - -#ifdef __tilepro__ -/* Invalidate a VA range; pads to L2 cacheline boundaries. */ -static inline void __inv_buffer(void *buffer, size_t size) -{ - char *next = (char *)((long)buffer & -L2_CACHE_BYTES); - char *finish = (char *)L2_CACHE_ALIGN((long)buffer + size); - while (next < finish) { - __insn_inv(next); - next += CHIP_INV_STRIDE(); - } -} - -/* Invalidate a VA range and wait for it to be complete. */ -static inline void inv_buffer(void *buffer, size_t size) -{ - __inv_buffer(buffer, size); - mb(); -} -#endif - -/* - * Flush and invalidate a VA range that is homed remotely, waiting - * until the memory controller holds the flushed values. If "hfh" is - * true, we will do a more expensive flush involving additional loads - * to make sure we have touched all the possible home cpus of a buffer - * that is homed with "hash for home". - */ -void finv_buffer_remote(void *buffer, size_t size, int hfh); - -/* - * On SMP systems, when the scheduler does migration-cost autodetection, - * it needs a way to flush as much of the CPU's caches as possible: - * - * TODO: fill this in! - */ -static inline void sched_cacheflush(void) -{ -} - -#endif /* _ASM_TILE_CACHEFLUSH_H */ diff --git a/arch/tile/include/asm/checksum.h b/arch/tile/include/asm/checksum.h deleted file mode 100644 index b21a2fdec9f7..000000000000 --- a/arch/tile/include/asm/checksum.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_CHECKSUM_H -#define _ASM_TILE_CHECKSUM_H - -#include - -/* Allow us to provide a more optimized do_csum(). */ -__wsum do_csum(const unsigned char *buff, int len); -#define do_csum do_csum - -/* - * Return the sum of all the 16-bit subwords in a long. - * This sums two subwords on a 32-bit machine, and four on 64 bits. - * The implementation does two vector adds to capture any overflow. - */ -static inline unsigned int csum_long(unsigned long x) -{ - unsigned long ret; -#ifdef __tilegx__ - ret = __insn_v2sadu(x, 0); - ret = __insn_v2sadu(ret, 0); -#else - ret = __insn_sadh_u(x, 0); - ret = __insn_sadh_u(ret, 0); -#endif - return ret; -} - -#endif /* _ASM_TILE_CHECKSUM_H */ diff --git a/arch/tile/include/asm/cmpxchg.h b/arch/tile/include/asm/cmpxchg.h deleted file mode 100644 index 25d5899497be..000000000000 --- a/arch/tile/include/asm/cmpxchg.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * cmpxchg.h -- forked from asm/atomic.h with this copyright: - * - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - */ - -#ifndef _ASM_TILE_CMPXCHG_H -#define _ASM_TILE_CMPXCHG_H - -#ifndef __ASSEMBLY__ - -#include - -/* Nonexistent functions intended to cause compile errors. */ -extern void __xchg_called_with_bad_pointer(void) - __compiletime_error("Bad argument size for xchg"); -extern void __cmpxchg_called_with_bad_pointer(void) - __compiletime_error("Bad argument size for cmpxchg"); - -#ifndef __tilegx__ - -/* Note the _atomic_xxx() routines include a final mb(). */ -int _atomic_xchg(int *ptr, int n); -int _atomic_xchg_add(int *v, int i); -int _atomic_xchg_add_unless(int *v, int a, int u); -int _atomic_cmpxchg(int *ptr, int o, int n); -long long _atomic64_xchg(long long *v, long long n); -long long _atomic64_xchg_add(long long *v, long long i); -long long _atomic64_xchg_add_unless(long long *v, long long a, long long u); -long long _atomic64_cmpxchg(long long *v, long long o, long long n); - -#define xchg(ptr, n) \ - ({ \ - if (sizeof(*(ptr)) != 4) \ - __xchg_called_with_bad_pointer(); \ - smp_mb(); \ - (typeof(*(ptr)))_atomic_xchg((int *)(ptr), (int)(n)); \ - }) - -#define cmpxchg(ptr, o, n) \ - ({ \ - if (sizeof(*(ptr)) != 4) \ - __cmpxchg_called_with_bad_pointer(); \ - smp_mb(); \ - (typeof(*(ptr)))_atomic_cmpxchg((int *)ptr, (int)o, \ - (int)n); \ - }) - -#define xchg64(ptr, n) \ - ({ \ - if (sizeof(*(ptr)) != 8) \ - __xchg_called_with_bad_pointer(); \ - smp_mb(); \ - (typeof(*(ptr)))_atomic64_xchg((long long *)(ptr), \ - (long long)(n)); \ - }) - -#define cmpxchg64(ptr, o, n) \ - ({ \ - if (sizeof(*(ptr)) != 8) \ - __cmpxchg_called_with_bad_pointer(); \ - smp_mb(); \ - (typeof(*(ptr)))_atomic64_cmpxchg((long long *)ptr, \ - (long long)o, (long long)n); \ - }) - -#else - -#define xchg(ptr, n) \ - ({ \ - typeof(*(ptr)) __x; \ - smp_mb(); \ - switch (sizeof(*(ptr))) { \ - case 4: \ - __x = (typeof(__x))(unsigned long) \ - __insn_exch4((ptr), \ - (u32)(unsigned long)(n)); \ - break; \ - case 8: \ - __x = (typeof(__x)) \ - __insn_exch((ptr), (unsigned long)(n)); \ - break; \ - default: \ - __xchg_called_with_bad_pointer(); \ - break; \ - } \ - smp_mb(); \ - __x; \ - }) - -#define cmpxchg(ptr, o, n) \ - ({ \ - typeof(*(ptr)) __x; \ - __insn_mtspr(SPR_CMPEXCH_VALUE, (unsigned long)(o)); \ - smp_mb(); \ - switch (sizeof(*(ptr))) { \ - case 4: \ - __x = (typeof(__x))(unsigned long) \ - __insn_cmpexch4((ptr), \ - (u32)(unsigned long)(n)); \ - break; \ - case 8: \ - __x = (typeof(__x))__insn_cmpexch((ptr), \ - (long long)(n)); \ - break; \ - default: \ - __cmpxchg_called_with_bad_pointer(); \ - break; \ - } \ - smp_mb(); \ - __x; \ - }) - -#define xchg64 xchg -#define cmpxchg64 cmpxchg - -#endif - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_TILE_CMPXCHG_H */ diff --git a/arch/tile/include/asm/compat.h b/arch/tile/include/asm/compat.h deleted file mode 100644 index 769ff6ac0bf5..000000000000 --- a/arch/tile/include/asm/compat.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_COMPAT_H -#define _ASM_TILE_COMPAT_H - -/* - * Architecture specific compatibility types - */ -#include -#include - -#define COMPAT_USER_HZ 100 - -/* "long" and pointer-based types are different. */ -typedef s32 compat_long_t; -typedef u32 compat_ulong_t; -typedef u32 compat_size_t; -typedef s32 compat_ssize_t; -typedef s32 compat_off_t; -typedef s32 compat_time_t; -typedef s32 compat_clock_t; -typedef u32 compat_ino_t; -typedef u32 compat_caddr_t; -typedef u32 compat_uptr_t; - -/* Many types are "int" or otherwise the same. */ -typedef __kernel_pid_t compat_pid_t; -typedef __kernel_uid_t __compat_uid_t; -typedef __kernel_gid_t __compat_gid_t; -typedef __kernel_uid32_t __compat_uid32_t; -typedef __kernel_uid32_t __compat_gid32_t; -typedef __kernel_mode_t compat_mode_t; -typedef __kernel_dev_t compat_dev_t; -typedef __kernel_loff_t compat_loff_t; -typedef __kernel_ipc_pid_t compat_ipc_pid_t; -typedef __kernel_daddr_t compat_daddr_t; -typedef __kernel_fsid_t compat_fsid_t; -typedef __kernel_timer_t compat_timer_t; -typedef __kernel_key_t compat_key_t; -typedef int compat_int_t; -typedef s64 compat_s64; -typedef uint compat_uint_t; -typedef u64 compat_u64; - -/* We use the same register dump format in 32-bit images. */ -typedef unsigned long compat_elf_greg_t; -#define COMPAT_ELF_NGREG (sizeof(struct pt_regs) / sizeof(compat_elf_greg_t)) -typedef compat_elf_greg_t compat_elf_gregset_t[COMPAT_ELF_NGREG]; - -struct compat_timespec { - compat_time_t tv_sec; - s32 tv_nsec; -}; - -struct compat_timeval { - compat_time_t tv_sec; - s32 tv_usec; -}; - -#define compat_stat stat -#define compat_statfs statfs - -struct compat_sysctl { - unsigned int name; - int nlen; - unsigned int oldval; - unsigned int oldlenp; - unsigned int newval; - unsigned int newlen; - unsigned int __unused[4]; -}; - - -struct compat_flock { - short l_type; - short l_whence; - compat_off_t l_start; - compat_off_t l_len; - compat_pid_t l_pid; -}; - -#define F_GETLK64 12 /* using 'struct flock64' */ -#define F_SETLK64 13 -#define F_SETLKW64 14 - -struct compat_flock64 { - short l_type; - short l_whence; - compat_loff_t l_start; - compat_loff_t l_len; - compat_pid_t l_pid; -}; - -#define COMPAT_RLIM_INFINITY 0xffffffff - -#define _COMPAT_NSIG 64 -#define _COMPAT_NSIG_BPW 32 - -typedef u32 compat_sigset_word; - -#define COMPAT_OFF_T_MAX 0x7fffffff - -struct compat_ipc64_perm { - compat_key_t key; - __compat_uid32_t uid; - __compat_gid32_t gid; - __compat_uid32_t cuid; - __compat_gid32_t cgid; - unsigned short mode; - unsigned short __pad1; - unsigned short seq; - unsigned short __pad2; - compat_ulong_t unused1; - compat_ulong_t unused2; -}; - -struct compat_semid64_ds { - struct compat_ipc64_perm sem_perm; - compat_time_t sem_otime; - compat_ulong_t __unused1; - compat_time_t sem_ctime; - compat_ulong_t __unused2; - compat_ulong_t sem_nsems; - compat_ulong_t __unused3; - compat_ulong_t __unused4; -}; - -struct compat_msqid64_ds { - struct compat_ipc64_perm msg_perm; - compat_time_t msg_stime; - compat_ulong_t __unused1; - compat_time_t msg_rtime; - compat_ulong_t __unused2; - compat_time_t msg_ctime; - compat_ulong_t __unused3; - compat_ulong_t msg_cbytes; - compat_ulong_t msg_qnum; - compat_ulong_t msg_qbytes; - compat_pid_t msg_lspid; - compat_pid_t msg_lrpid; - compat_ulong_t __unused4; - compat_ulong_t __unused5; -}; - -struct compat_shmid64_ds { - struct compat_ipc64_perm shm_perm; - compat_size_t shm_segsz; - compat_time_t shm_atime; - compat_ulong_t __unused1; - compat_time_t shm_dtime; - compat_ulong_t __unused2; - compat_time_t shm_ctime; - compat_ulong_t __unused3; - compat_pid_t shm_cpid; - compat_pid_t shm_lpid; - compat_ulong_t shm_nattch; - compat_ulong_t __unused4; - compat_ulong_t __unused5; -}; - -/* - * A pointer passed in from user mode. This should not - * be used for syscall parameters, just declare them - * as pointers because the syscall entry code will have - * appropriately converted them already. - */ - -static inline void __user *compat_ptr(compat_uptr_t uptr) -{ - return (void __user *)(long)(s32)uptr; -} - -static inline compat_uptr_t ptr_to_compat(void __user *uptr) -{ - return (u32)(unsigned long)uptr; -} - -/* Sign-extend when storing a kernel pointer to a user's ptregs. */ -static inline unsigned long ptr_to_compat_reg(void __user *uptr) -{ - return (long)(int)(long __force)uptr; -} - -static inline void __user *arch_compat_alloc_user_space(long len) -{ - struct pt_regs *regs = task_pt_regs(current); - return (void __user *)regs->sp - len; -} - -static inline int is_compat_task(void) -{ - return current_thread_info()->status & TS_COMPAT; -} - -extern int compat_setup_rt_frame(struct ksignal *ksig, sigset_t *set, - struct pt_regs *regs); - -/* Compat syscalls. */ -struct compat_siginfo; -struct compat_sigaltstack; -long compat_sys_rt_sigreturn(void); -long compat_sys_truncate64(char __user *filename, u32 dummy, u32 low, u32 high); -long compat_sys_ftruncate64(unsigned int fd, u32 dummy, u32 low, u32 high); -long compat_sys_pread64(unsigned int fd, char __user *ubuf, size_t count, - u32 dummy, u32 low, u32 high); -long compat_sys_pwrite64(unsigned int fd, char __user *ubuf, size_t count, - u32 dummy, u32 low, u32 high); -long compat_sys_sync_file_range2(int fd, unsigned int flags, - u32 offset_lo, u32 offset_hi, - u32 nbytes_lo, u32 nbytes_hi); -long compat_sys_fallocate(int fd, int mode, - u32 offset_lo, u32 offset_hi, - u32 len_lo, u32 len_hi); -long compat_sys_llseek(unsigned int fd, unsigned int offset_high, - unsigned int offset_low, loff_t __user * result, - unsigned int origin); - -/* Assembly trampoline to avoid clobbering r0. */ -long _compat_sys_rt_sigreturn(void); - -#endif /* _ASM_TILE_COMPAT_H */ diff --git a/arch/tile/include/asm/current.h b/arch/tile/include/asm/current.h deleted file mode 100644 index da21acf020d3..000000000000 --- a/arch/tile/include/asm/current.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_CURRENT_H -#define _ASM_TILE_CURRENT_H - -#include - -struct task_struct; - -static inline struct task_struct *get_current(void) -{ - return current_thread_info()->task; -} -#define current get_current() - -/* Return a usable "task_struct" pointer even if the real one is corrupt. */ -struct task_struct *validate_current(void); - -#endif /* _ASM_TILE_CURRENT_H */ diff --git a/arch/tile/include/asm/delay.h b/arch/tile/include/asm/delay.h deleted file mode 100644 index 97b0e69e704e..000000000000 --- a/arch/tile/include/asm/delay.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_DELAY_H -#define _ASM_TILE_DELAY_H - -/* Undefined functions to get compile-time errors. */ -extern void __bad_udelay(void); -extern void __bad_ndelay(void); - -extern void __udelay(unsigned long usecs); -extern void __ndelay(unsigned long nsecs); -extern void __delay(unsigned long loops); - -#define udelay(n) (__builtin_constant_p(n) ? \ - ((n) > 20000 ? __bad_udelay() : __ndelay((n) * 1000)) : \ - __udelay(n)) - -#define ndelay(n) (__builtin_constant_p(n) ? \ - ((n) > 20000 ? __bad_ndelay() : __ndelay(n)) : \ - __ndelay(n)) - -#endif /* _ASM_TILE_DELAY_H */ diff --git a/arch/tile/include/asm/device.h b/arch/tile/include/asm/device.h deleted file mode 100644 index 1cf45422a0df..000000000000 --- a/arch/tile/include/asm/device.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * Arch specific extensions to struct device - */ - -#ifndef _ASM_TILE_DEVICE_H -#define _ASM_TILE_DEVICE_H - -struct dev_archdata { - /* Offset of the DMA address from the PA. */ - dma_addr_t dma_offset; - - /* - * Highest DMA address that can be generated by devices that - * have limited DMA capability, i.e. non 64-bit capable. - */ - dma_addr_t max_direct_dma_addr; -}; - -struct pdev_archdata { -}; - -#endif /* _ASM_TILE_DEVICE_H */ diff --git a/arch/tile/include/asm/div64.h b/arch/tile/include/asm/div64.h deleted file mode 100644 index a0a798344d5f..000000000000 --- a/arch/tile/include/asm/div64.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_TILE_DIV64_H -#define _ASM_TILE_DIV64_H - -#include - -#ifdef __tilegx__ -static inline u64 mul_u32_u32(u32 a, u32 b) -{ - return __insn_mul_lu_lu(a, b); -} -#define mul_u32_u32 mul_u32_u32 -#endif - -#include - -#endif /* _ASM_TILE_DIV64_H */ diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h deleted file mode 100644 index d25fce101fc0..000000000000 --- a/arch/tile/include/asm/dma-mapping.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_DMA_MAPPING_H -#define _ASM_TILE_DMA_MAPPING_H - -#include -#include -#include -#include - -#ifdef __tilegx__ -#define ARCH_HAS_DMA_GET_REQUIRED_MASK -#endif - -extern const struct dma_map_ops *tile_dma_map_ops; -extern const struct dma_map_ops *gx_pci_dma_map_ops; -extern const struct dma_map_ops *gx_legacy_pci_dma_map_ops; -extern const struct dma_map_ops *gx_hybrid_pci_dma_map_ops; - -static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus) -{ - return tile_dma_map_ops; -} - -static inline dma_addr_t get_dma_offset(struct device *dev) -{ - return dev->archdata.dma_offset; -} - -static inline void set_dma_offset(struct device *dev, dma_addr_t off) -{ - dev->archdata.dma_offset = off; -} - -#define HAVE_ARCH_DMA_SET_MASK 1 -int dma_set_mask(struct device *dev, u64 mask); - -#endif /* _ASM_TILE_DMA_MAPPING_H */ diff --git a/arch/tile/include/asm/dma.h b/arch/tile/include/asm/dma.h deleted file mode 100644 index 12a7ca16d164..000000000000 --- a/arch/tile/include/asm/dma.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_DMA_H -#define _ASM_TILE_DMA_H - -#include - -/* Needed by drivers/pci/quirks.c */ -#ifdef CONFIG_PCI -extern int isa_dma_bridge_buggy; -#endif - -#endif /* _ASM_TILE_DMA_H */ diff --git a/arch/tile/include/asm/elf.h b/arch/tile/include/asm/elf.h deleted file mode 100644 index e9d54a06736f..000000000000 --- a/arch/tile/include/asm/elf.h +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_ELF_H -#define _ASM_TILE_ELF_H - -/* - * ELF register definitions. - */ - -#include - -#include -#include -#include -#include - -typedef unsigned long elf_greg_t; - -#define ELF_NGREG (sizeof(struct pt_regs) / sizeof(elf_greg_t)) -typedef elf_greg_t elf_gregset_t[ELF_NGREG]; - -/* Provide a nominal data structure. */ -#define ELF_NFPREG 0 -typedef double elf_fpreg_t; -typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; - -#ifdef __tilegx__ -#define ELF_CLASS ELFCLASS64 -#else -#define ELF_CLASS ELFCLASS32 -#endif -#ifdef __BIG_ENDIAN__ -#define ELF_DATA ELFDATA2MSB -#else -#define ELF_DATA ELFDATA2LSB -#endif - -/* - * There seems to be a bug in how compat_binfmt_elf.c works: it - * #undefs ELF_ARCH, but it is then used in binfmt_elf.c for fill_note_info(). - * Hack around this by providing an enum value of ELF_ARCH. - */ -enum { ELF_ARCH = CHIP_ELF_TYPE() }; -#define ELF_ARCH ELF_ARCH - -/* - * This is used to ensure we don't load something for the wrong architecture. - */ -#define elf_check_arch(x) \ - ((x)->e_ident[EI_CLASS] == ELF_CLASS && \ - (x)->e_ident[EI_DATA] == ELF_DATA && \ - (x)->e_machine == CHIP_ELF_TYPE()) - -/* The module loader only handles a few relocation types. */ -#ifndef __tilegx__ -#define R_TILE_32 1 -#define R_TILE_JOFFLONG_X1 15 -#define R_TILE_IMM16_X0_LO 25 -#define R_TILE_IMM16_X1_LO 26 -#define R_TILE_IMM16_X0_HA 29 -#define R_TILE_IMM16_X1_HA 30 -#else -#define R_TILEGX_64 1 -#define R_TILEGX_JUMPOFF_X1 21 -#define R_TILEGX_IMM16_X0_HW0 36 -#define R_TILEGX_IMM16_X1_HW0 37 -#define R_TILEGX_IMM16_X0_HW1 38 -#define R_TILEGX_IMM16_X1_HW1 39 -#define R_TILEGX_IMM16_X0_HW2_LAST 48 -#define R_TILEGX_IMM16_X1_HW2_LAST 49 -#endif - -/* Use standard page size for core dumps. */ -#define ELF_EXEC_PAGESIZE PAGE_SIZE - -/* - * This is the location that an ET_DYN program is loaded if exec'ed. Typical - * use of this is to invoke "./ld.so someprog" to test out a new version of - * the loader. We need to make sure that it is out of the way of the program - * that it will "exec", and that there is sufficient room for the brk. - */ -#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) - -#define ELF_CORE_COPY_REGS(_dest, _regs) \ - memcpy((char *) &_dest, (char *) _regs, \ - sizeof(struct pt_regs)); - -/* No additional FP registers to copy. */ -#define ELF_CORE_COPY_FPREGS(t, fpu) 0 - -/* - * This yields a mask that user programs can use to figure out what - * instruction set this CPU supports. This could be done in user space, - * but it's not easy, and we've already done it here. - */ -#define ELF_HWCAP (0) - -/* - * This yields a string that ld.so will use to load implementation - * specific libraries for optimization. This is more specific in - * intent than poking at uname or /proc/cpuinfo. - */ -#define ELF_PLATFORM (NULL) - -extern void elf_plat_init(struct pt_regs *regs, unsigned long load_addr); - -#define ELF_PLAT_INIT(_r, load_addr) elf_plat_init(_r, load_addr) - -extern int dump_task_regs(struct task_struct *, elf_gregset_t *); -#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs) - -/* Tilera Linux has no personalities currently, so no need to do anything. */ -#define SET_PERSONALITY(ex) do { } while (0) - -#define ARCH_HAS_SETUP_ADDITIONAL_PAGES -/* Support auto-mapping of the user interrupt vectors. */ -struct linux_binprm; -extern int arch_setup_additional_pages(struct linux_binprm *bprm, - int executable_stack); -/* update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */ -#define ARCH_DLINFO \ -do { \ - NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_BASE); \ -} while (0) - -struct mm_struct; -extern unsigned long arch_randomize_brk(struct mm_struct *mm); -#define arch_randomize_brk arch_randomize_brk - -#ifdef CONFIG_COMPAT - -#define COMPAT_ELF_PLATFORM "tilegx-m32" - -/* - * "Compat" binaries have the same machine type, but 32-bit class, - * since they're not a separate machine type, but just a 32-bit - * variant of the standard 64-bit architecture. - */ -#define compat_elf_check_arch(x) \ - ((x)->e_ident[EI_CLASS] == ELFCLASS32 && \ - (x)->e_machine == CHIP_ELF_TYPE()) - -#define compat_start_thread(regs, ip, usp) do { \ - regs->pc = ptr_to_compat_reg((void *)(ip)); \ - regs->sp = ptr_to_compat_reg((void *)(usp)); \ - single_step_execve(); \ - } while (0) - -/* - * Use SET_PERSONALITY to indicate compatibility via TS_COMPAT. - */ -#undef SET_PERSONALITY -#define SET_PERSONALITY(ex) \ -do { \ - set_personality(PER_LINUX | (current->personality & (~PER_MASK))); \ - current_thread_info()->status &= ~TS_COMPAT; \ -} while (0) -#define COMPAT_SET_PERSONALITY(ex) \ -do { \ - set_personality(PER_LINUX | (current->personality & (~PER_MASK))); \ - current_thread_info()->status |= TS_COMPAT; \ -} while (0) - -#define COMPAT_ELF_ET_DYN_BASE (0xffffffff / 3 * 2) - -#endif /* CONFIG_COMPAT */ - -#define CORE_DUMP_USE_REGSET - -#endif /* _ASM_TILE_ELF_H */ diff --git a/arch/tile/include/asm/fixmap.h b/arch/tile/include/asm/fixmap.h deleted file mode 100644 index ffe2637aeb31..000000000000 --- a/arch/tile/include/asm/fixmap.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 1998 Ingo Molnar - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_FIXMAP_H -#define _ASM_TILE_FIXMAP_H - -#include - -#ifndef __ASSEMBLY__ -#include -#ifdef CONFIG_HIGHMEM -#include -#include -#endif - -/* - * Here we define all the compile-time 'special' virtual - * addresses. The point is to have a constant address at - * compile time, but to set the physical address only - * in the boot process. We allocate these special addresses - * from the end of supervisor virtual memory backwards. - * Also this lets us do fail-safe vmalloc(), we - * can guarantee that these special addresses and - * vmalloc()-ed addresses never overlap. - * - * these 'compile-time allocated' memory buffers are - * fixed-size 4k pages. (or larger if used with an increment - * higher than 1) use fixmap_set(idx,phys) to associate - * physical memory with fixmap indices. - * - * TLB entries of such buffers will not be flushed across - * task switches. - */ -enum fixed_addresses { -#ifdef __tilegx__ - /* - * TILEPro has unmapped memory above so the hole isn't needed, - * and in any case the hole pushes us over a single 16MB pmd. - */ - FIX_HOLE, -#endif -#ifdef CONFIG_HIGHMEM - FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ - FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, -#endif -#ifdef __tilegx__ /* see homecache.c */ - FIX_HOMECACHE_BEGIN, - FIX_HOMECACHE_END = FIX_HOMECACHE_BEGIN+(NR_CPUS)-1, -#endif - __end_of_permanent_fixed_addresses, - - /* - * Temporary boot-time mappings, used before ioremap() is functional. - * Not currently needed by the Tile architecture. - */ -#define NR_FIX_BTMAPS 0 -#if NR_FIX_BTMAPS - FIX_BTMAP_END = __end_of_permanent_fixed_addresses, - FIX_BTMAP_BEGIN = FIX_BTMAP_END + NR_FIX_BTMAPS - 1, - __end_of_fixed_addresses -#else - __end_of_fixed_addresses = __end_of_permanent_fixed_addresses -#endif -}; - -#define __FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT) -#define __FIXADDR_BOOT_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) -#define FIXADDR_START (FIXADDR_TOP + PAGE_SIZE - __FIXADDR_SIZE) -#define FIXADDR_BOOT_START (FIXADDR_TOP + PAGE_SIZE - __FIXADDR_BOOT_SIZE) - -#include - -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASM_TILE_FIXMAP_H */ diff --git a/arch/tile/include/asm/ftrace.h b/arch/tile/include/asm/ftrace.h deleted file mode 100644 index 738d239b792f..000000000000 --- a/arch/tile/include/asm/ftrace.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_FTRACE_H -#define _ASM_TILE_FTRACE_H - -#ifdef CONFIG_FUNCTION_TRACER - -#define MCOUNT_ADDR ((unsigned long)(__mcount)) -#define MCOUNT_INSN_SIZE 8 /* sizeof mcount call */ - -#ifndef __ASSEMBLY__ -extern void __mcount(void); - -#define ARCH_SUPPORTS_FTRACE_OPS 1 - -#ifdef CONFIG_DYNAMIC_FTRACE -static inline unsigned long ftrace_call_adjust(unsigned long addr) -{ - return addr; -} - -struct dyn_arch_ftrace { -}; -#endif /* CONFIG_DYNAMIC_FTRACE */ - -#endif /* __ASSEMBLY__ */ - -#endif /* CONFIG_FUNCTION_TRACER */ - -#endif /* _ASM_TILE_FTRACE_H */ diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h deleted file mode 100644 index 83c1e639b411..000000000000 --- a/arch/tile/include/asm/futex.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * These routines make two important assumptions: - * - * 1. atomic_t is really an int and can be freely cast back and forth - * (validated in __init_atomic_per_cpu). - * - * 2. userspace uses sys_cmpxchg() for all atomic operations, thus using - * the same locking convention that all the kernel atomic routines use. - */ - -#ifndef _ASM_TILE_FUTEX_H -#define _ASM_TILE_FUTEX_H - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -/* - * Support macros for futex operations. Do not use these macros directly. - * They assume "ret", "val", "oparg", and "uaddr" in the lexical context. - * __futex_cmpxchg() additionally assumes "oldval". - */ - -#ifdef __tilegx__ - -#define __futex_asm(OP) \ - asm("1: {" #OP " %1, %3, %4; movei %0, 0 }\n" \ - ".pushsection .fixup,\"ax\"\n" \ - "0: { movei %0, %5; j 9f }\n" \ - ".section __ex_table,\"a\"\n" \ - ".align 8\n" \ - ".quad 1b, 0b\n" \ - ".popsection\n" \ - "9:" \ - : "=r" (ret), "=r" (val), "+m" (*(uaddr)) \ - : "r" (uaddr), "r" (oparg), "i" (-EFAULT)) - -#define __futex_set() __futex_asm(exch4) -#define __futex_add() __futex_asm(fetchadd4) -#define __futex_or() __futex_asm(fetchor4) -#define __futex_andn() ({ oparg = ~oparg; __futex_asm(fetchand4); }) -#define __futex_cmpxchg() \ - ({ __insn_mtspr(SPR_CMPEXCH_VALUE, oldval); __futex_asm(cmpexch4); }) - -#define __futex_xor() \ - ({ \ - u32 oldval, n = oparg; \ - if ((ret = __get_user(oldval, uaddr)) == 0) { \ - do { \ - oparg = oldval ^ n; \ - __futex_cmpxchg(); \ - } while (ret == 0 && oldval != val); \ - } \ - }) - -/* No need to prefetch, since the atomic ops go to the home cache anyway. */ -#define __futex_prolog() - -#else - -#define __futex_call(FN) \ - { \ - struct __get_user gu = FN((u32 __force *)uaddr, lock, oparg); \ - val = gu.val; \ - ret = gu.err; \ - } - -#define __futex_set() __futex_call(__atomic32_xchg) -#define __futex_add() __futex_call(__atomic32_xchg_add) -#define __futex_or() __futex_call(__atomic32_fetch_or) -#define __futex_andn() __futex_call(__atomic32_fetch_andn) -#define __futex_xor() __futex_call(__atomic32_fetch_xor) - -#define __futex_cmpxchg() \ - { \ - struct __get_user gu = __atomic32_cmpxchg((u32 __force *)uaddr, \ - lock, oldval, oparg); \ - val = gu.val; \ - ret = gu.err; \ - } - -/* - * Find the lock pointer for the atomic calls to use, and issue a - * prefetch to the user address to bring it into cache. Similar to - * __atomic_setup(), but we can't do a read into the L1 since it might - * fault; instead we do a prefetch into the L2. - */ -#define __futex_prolog() \ - int *lock; \ - __insn_prefetch(uaddr); \ - lock = __atomic_hashed_lock((int __force *)uaddr) -#endif - -static inline int arch_futex_atomic_op_inuser(int op, u32 oparg, int *oval, - u32 __user *uaddr) -{ - int uninitialized_var(val), ret; - - __futex_prolog(); - - /* The 32-bit futex code makes this assumption, so validate it here. */ - BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int)); - - pagefault_disable(); - switch (op) { - case FUTEX_OP_SET: - __futex_set(); - break; - case FUTEX_OP_ADD: - __futex_add(); - break; - case FUTEX_OP_OR: - __futex_or(); - break; - case FUTEX_OP_ANDN: - __futex_andn(); - break; - case FUTEX_OP_XOR: - __futex_xor(); - break; - default: - ret = -ENOSYS; - break; - } - pagefault_enable(); - - if (!ret) - *oval = val; - - return ret; -} - -static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, - u32 oldval, u32 oparg) -{ - int ret, val; - - __futex_prolog(); - - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) - return -EFAULT; - - __futex_cmpxchg(); - - *uval = val; - return ret; -} - -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASM_TILE_FUTEX_H */ diff --git a/arch/tile/include/asm/hardirq.h b/arch/tile/include/asm/hardirq.h deleted file mode 100644 index 54110af23985..000000000000 --- a/arch/tile/include/asm/hardirq.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_HARDIRQ_H -#define _ASM_TILE_HARDIRQ_H - -#include -#include - -#include - -typedef struct { - unsigned int __softirq_pending; - long idle_timestamp; - - /* Hard interrupt statistics. */ - unsigned int irq_timer_count; - unsigned int irq_syscall_count; - unsigned int irq_resched_count; - unsigned int irq_hv_flush_count; - unsigned int irq_call_count; - unsigned int irq_hv_msg_count; - unsigned int irq_dev_intr_count; - -} ____cacheline_aligned irq_cpustat_t; - -DECLARE_PER_CPU(irq_cpustat_t, irq_stat); - -#define __ARCH_IRQ_STAT -#define __IRQ_STAT(cpu, member) (per_cpu(irq_stat, cpu).member) - -#include /* Standard mappings for irq_cpustat_t above */ - -#endif /* _ASM_TILE_HARDIRQ_H */ diff --git a/arch/tile/include/asm/hardwall.h b/arch/tile/include/asm/hardwall.h deleted file mode 100644 index 44d2765bde2b..000000000000 --- a/arch/tile/include/asm/hardwall.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Provide methods for access control of per-cpu resources like - * UDN, IDN, or IPI. - */ -#ifndef _ASM_TILE_HARDWALL_H -#define _ASM_TILE_HARDWALL_H - -#include - -/* /proc hooks for hardwall. */ -struct proc_dir_entry; -#ifdef CONFIG_HARDWALL -void proc_tile_hardwall_init(struct proc_dir_entry *root); -int proc_pid_hardwall(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task); -#else -static inline void proc_tile_hardwall_init(struct proc_dir_entry *root) {} -#endif -#endif /* _ASM_TILE_HARDWALL_H */ diff --git a/arch/tile/include/asm/highmem.h b/arch/tile/include/asm/highmem.h deleted file mode 100644 index 979579b38e57..000000000000 --- a/arch/tile/include/asm/highmem.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 1999 Gerhard Wichert, Siemens AG - * Gerhard.Wichert@pdb.siemens.de - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Used in CONFIG_HIGHMEM systems for memory pages which - * are not addressable by direct kernel virtual addresses. - * - */ - -#ifndef _ASM_TILE_HIGHMEM_H -#define _ASM_TILE_HIGHMEM_H - -#include -#include -#include -#include - -/* declarations for highmem.c */ -extern unsigned long highstart_pfn, highend_pfn; - -extern pte_t *pkmap_page_table; - -/* - * Ordering is: - * - * FIXADDR_TOP - * fixed_addresses - * FIXADDR_START - * temp fixed addresses - * FIXADDR_BOOT_START - * Persistent kmap area - * PKMAP_BASE - * VMALLOC_END - * Vmalloc area - * VMALLOC_START - * high_memory - */ -#define LAST_PKMAP_MASK (LAST_PKMAP-1) -#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT) -#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT)) - -void *kmap_high(struct page *page); -void kunmap_high(struct page *page); -void *kmap(struct page *page); -void kunmap(struct page *page); -void *kmap_fix_kpte(struct page *page, int finished); - -/* This macro is used only in map_new_virtual() to map "page". */ -#define kmap_prot page_to_kpgprot(page) - -void *kmap_atomic(struct page *page); -void __kunmap_atomic(void *kvaddr); -void *kmap_atomic_pfn(unsigned long pfn); -void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot); -void *kmap_atomic_prot(struct page *page, pgprot_t prot); -void kmap_atomic_fix_kpte(struct page *page, int finished); - -#define flush_cache_kmaps() do { } while (0) - -#endif /* _ASM_TILE_HIGHMEM_H */ diff --git a/arch/tile/include/asm/homecache.h b/arch/tile/include/asm/homecache.h deleted file mode 100644 index 7ddd1b8d6910..000000000000 --- a/arch/tile/include/asm/homecache.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Handle issues around the Tile "home cache" model of coherence. - */ - -#ifndef _ASM_TILE_HOMECACHE_H -#define _ASM_TILE_HOMECACHE_H - -#include -#include - -struct page; -struct task_struct; -struct vm_area_struct; -struct zone; - -/* - * Coherence point for the page is its memory controller. - * It is not present in any cache (L1 or L2). - */ -#define PAGE_HOME_UNCACHED -1 - -/* - * Is this page immutable (unwritable) and thus able to be cached more - * widely than would otherwise be possible? This means we have "nc" set. - */ -#define PAGE_HOME_IMMUTABLE -2 - -/* - * Each cpu considers its own cache to be the home for the page, - * which makes it incoherent. - */ -#define PAGE_HOME_INCOHERENT -3 - -/* Home for the page is distributed via hash-for-home. */ -#define PAGE_HOME_HASH -4 - -/* Support wrapper to use instead of explicit hv_flush_remote(). */ -extern void flush_remote(unsigned long cache_pfn, unsigned long cache_length, - const struct cpumask *cache_cpumask, - HV_VirtAddr tlb_va, unsigned long tlb_length, - unsigned long tlb_pgsize, - const struct cpumask *tlb_cpumask, - HV_Remote_ASID *asids, int asidcount); - -/* Set homing-related bits in a PTE (can also pass a pgprot_t). */ -extern pte_t pte_set_home(pte_t pte, int home); - -/* Do a cache eviction on the specified cpus. */ -extern void homecache_evict(const struct cpumask *mask); - -/* - * Change a kernel page's homecache. It must not be mapped in user space. - * If !CONFIG_HOMECACHE, only usable on LOWMEM, and can only be called when - * no other cpu can reference the page, and causes a full-chip cache/TLB flush. - */ -extern void homecache_change_page_home(struct page *, int order, int home); - -/* - * Flush a page out of whatever cache(s) it is in. - * This is more than just finv, since it properly handles waiting - * for the data to reach memory, but it can be quite - * heavyweight, particularly on incoherent or immutable memory. - */ -extern void homecache_finv_page(struct page *); - -/* - * Flush a page out of the specified home cache. - * Note that the specified home need not be the actual home of the page, - * as for example might be the case when coordinating with I/O devices. - */ -extern void homecache_finv_map_page(struct page *, int home); - -/* - * Allocate a page with the given GFP flags, home, and optionally - * node. These routines are actually just wrappers around the normal - * alloc_pages() / alloc_pages_node() functions, which set and clear - * a per-cpu variable to communicate with homecache_new_kernel_page(). - * If !CONFIG_HOMECACHE, uses homecache_change_page_home(). - */ -extern struct page *homecache_alloc_pages(gfp_t gfp_mask, - unsigned int order, int home); -extern struct page *homecache_alloc_pages_node(int nid, gfp_t gfp_mask, - unsigned int order, int home); -#define homecache_alloc_page(gfp_mask, home) \ - homecache_alloc_pages(gfp_mask, 0, home) - -/* - * These routines are just pass-throughs to free_pages() when - * we support full homecaching. If !CONFIG_HOMECACHE, then these - * routines use homecache_change_page_home() to reset the home - * back to the default before returning the page to the allocator. - */ -void __homecache_free_pages(struct page *, unsigned int order); -void homecache_free_pages(unsigned long addr, unsigned int order); -#define __homecache_free_page(page) __homecache_free_pages((page), 0) -#define homecache_free_page(page) homecache_free_pages((page), 0) - - -/* - * Report the page home for LOWMEM pages by examining their kernel PTE, - * or for highmem pages as the default home. - */ -extern int page_home(struct page *); - -#define homecache_migrate_kthread() do {} while (0) - -#define homecache_kpte_lock() 0 -#define homecache_kpte_unlock(flags) do {} while (0) - - -#endif /* _ASM_TILE_HOMECACHE_H */ diff --git a/arch/tile/include/asm/hugetlb.h b/arch/tile/include/asm/hugetlb.h deleted file mode 100644 index 2fac5be4de26..000000000000 --- a/arch/tile/include/asm/hugetlb.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_HUGETLB_H -#define _ASM_TILE_HUGETLB_H - -#include -#include - - -static inline int is_hugepage_only_range(struct mm_struct *mm, - unsigned long addr, - unsigned long len) { - return 0; -} - -/* - * If the arch doesn't supply something else, assume that hugepage - * size aligned regions are ok without further preparation. - */ -static inline int prepare_hugepage_range(struct file *file, - unsigned long addr, unsigned long len) -{ - struct hstate *h = hstate_file(file); - if (len & ~huge_page_mask(h)) - return -EINVAL; - if (addr & ~huge_page_mask(h)) - return -EINVAL; - return 0; -} - -static inline void hugetlb_free_pgd_range(struct mmu_gather *tlb, - unsigned long addr, unsigned long end, - unsigned long floor, - unsigned long ceiling) -{ - free_pgd_range(tlb, addr, end, floor, ceiling); -} - -static inline void set_huge_pte_at(struct mm_struct *mm, unsigned long addr, - pte_t *ptep, pte_t pte) -{ - set_pte(ptep, pte); -} - -static inline pte_t huge_ptep_get_and_clear(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) -{ - return ptep_get_and_clear(mm, addr, ptep); -} - -static inline void huge_ptep_clear_flush(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep) -{ - ptep_clear_flush(vma, addr, ptep); -} - -static inline int huge_pte_none(pte_t pte) -{ - return pte_none(pte); -} - -static inline pte_t huge_pte_wrprotect(pte_t pte) -{ - return pte_wrprotect(pte); -} - -static inline void huge_ptep_set_wrprotect(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) -{ - ptep_set_wrprotect(mm, addr, ptep); -} - -static inline int huge_ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep, - pte_t pte, int dirty) -{ - return ptep_set_access_flags(vma, addr, ptep, pte, dirty); -} - -static inline pte_t huge_ptep_get(pte_t *ptep) -{ - return *ptep; -} - -static inline void arch_clear_hugepage_flags(struct page *page) -{ -} - -#ifdef CONFIG_HUGETLB_SUPER_PAGES -static inline pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma, - struct page *page, int writable) -{ - size_t pagesize = huge_page_size(hstate_vma(vma)); - if (pagesize != PUD_SIZE && pagesize != PMD_SIZE) - entry = pte_mksuper(entry); - return entry; -} -#define arch_make_huge_pte arch_make_huge_pte - -/* Sizes to scale up page size for PTEs with HV_PTE_SUPER bit. */ -enum { - HUGE_SHIFT_PGDIR = 0, - HUGE_SHIFT_PMD = 1, - HUGE_SHIFT_PAGE = 2, - HUGE_SHIFT_ENTRIES -}; -extern int huge_shift[HUGE_SHIFT_ENTRIES]; -#endif - -#endif /* _ASM_TILE_HUGETLB_H */ diff --git a/arch/tile/include/asm/hv_driver.h b/arch/tile/include/asm/hv_driver.h deleted file mode 100644 index ad614de899b3..000000000000 --- a/arch/tile/include/asm/hv_driver.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * This header defines a wrapper interface for managing hypervisor - * device calls that will result in an interrupt at some later time. - * In particular, this provides wrappers for hv_preada() and - * hv_pwritea(). - */ - -#ifndef _ASM_TILE_HV_DRIVER_H -#define _ASM_TILE_HV_DRIVER_H - -#include - -struct hv_driver_cb; - -/* A callback to be invoked when an operation completes. */ -typedef void hv_driver_callback_t(struct hv_driver_cb *cb, __hv32 result); - -/* - * A structure to hold information about an outstanding call. - * The driver must allocate a separate structure for each call. - */ -struct hv_driver_cb { - hv_driver_callback_t *callback; /* Function to call on interrupt. */ - void *dev; /* Driver-specific state variable. */ -}; - -/* Wrapper for invoking hv_dev_preada(). */ -static inline int -tile_hv_dev_preada(int devhdl, __hv32 flags, __hv32 sgl_len, - HV_SGL sgl[/* sgl_len */], __hv64 offset, - struct hv_driver_cb *callback) -{ - return hv_dev_preada(devhdl, flags, sgl_len, sgl, - offset, (HV_IntArg)callback); -} - -/* Wrapper for invoking hv_dev_pwritea(). */ -static inline int -tile_hv_dev_pwritea(int devhdl, __hv32 flags, __hv32 sgl_len, - HV_SGL sgl[/* sgl_len */], __hv64 offset, - struct hv_driver_cb *callback) -{ - return hv_dev_pwritea(devhdl, flags, sgl_len, sgl, - offset, (HV_IntArg)callback); -} - - -#endif /* _ASM_TILE_HV_DRIVER_H */ diff --git a/arch/tile/include/asm/ide.h b/arch/tile/include/asm/ide.h deleted file mode 100644 index 3c6f2ed894ce..000000000000 --- a/arch/tile/include/asm/ide.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_IDE_H -#define _ASM_TILE_IDE_H - -/* For IDE on PCI */ -#define MAX_HWIFS 10 - -#define ide_default_io_ctl(base) (0) - -#include - -#endif /* _ASM_TILE_IDE_H */ diff --git a/arch/tile/include/asm/insn.h b/arch/tile/include/asm/insn.h deleted file mode 100644 index f78ba5c16722..000000000000 --- a/arch/tile/include/asm/insn.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright 2015 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ -#ifndef __ASM_TILE_INSN_H -#define __ASM_TILE_INSN_H - -#include - -static inline tilegx_bundle_bits NOP(void) -{ - return create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) | - create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | - create_Opcode_X0(RRR_0_OPCODE_X0) | - create_UnaryOpcodeExtension_X1(NOP_UNARY_OPCODE_X1) | - create_RRROpcodeExtension_X1(UNARY_RRR_0_OPCODE_X1) | - create_Opcode_X1(RRR_0_OPCODE_X1); -} - -static inline tilegx_bundle_bits tilegx_gen_branch(unsigned long pc, - unsigned long addr, - bool link) -{ - tilegx_bundle_bits opcode_x0, opcode_x1; - long pcrel_by_instr = (addr - pc) >> TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES; - - if (link) { - /* opcode: jal addr */ - opcode_x1 = - create_Opcode_X1(JUMP_OPCODE_X1) | - create_JumpOpcodeExtension_X1(JAL_JUMP_OPCODE_X1) | - create_JumpOff_X1(pcrel_by_instr); - } else { - /* opcode: j addr */ - opcode_x1 = - create_Opcode_X1(JUMP_OPCODE_X1) | - create_JumpOpcodeExtension_X1(J_JUMP_OPCODE_X1) | - create_JumpOff_X1(pcrel_by_instr); - } - - /* opcode: fnop */ - opcode_x0 = - create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) | - create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | - create_Opcode_X0(RRR_0_OPCODE_X0); - - return opcode_x1 | opcode_x0; -} - -#endif /* __ASM_TILE_INSN_H */ diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h deleted file mode 100644 index 30f4a210d148..000000000000 --- a/arch/tile/include/asm/io.h +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_IO_H -#define _ASM_TILE_IO_H - -#include -#include -#include - -/* Maximum PCI I/O space address supported. */ -#define IO_SPACE_LIMIT 0xffffffff - -/* - * Convert a physical pointer to a virtual kernel pointer for /dev/mem - * access. - */ -#define xlate_dev_mem_ptr(p) __va(p) - -/* - * Convert a virtual cached pointer to an uncached pointer. - */ -#define xlate_dev_kmem_ptr(p) p - -/* - * Change "struct page" to physical address. - */ -#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) - -/* - * Some places try to pass in an loff_t for PHYSADDR (?!), so we cast it to - * long before casting it to a pointer to avoid compiler warnings. - */ -#if CHIP_HAS_MMIO() -extern void __iomem *ioremap(resource_size_t offset, unsigned long size); -extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size, - pgprot_t pgprot); -extern void iounmap(volatile void __iomem *addr); -#else -#define ioremap(physaddr, size) ((void __iomem *)(unsigned long)(physaddr)) -#define iounmap(addr) ((void)0) -#endif - -#define ioremap_nocache(physaddr, size) ioremap(physaddr, size) -#define ioremap_wc(physaddr, size) ioremap(physaddr, size) -#define ioremap_wt(physaddr, size) ioremap(physaddr, size) -#define ioremap_uc(physaddr, size) ioremap(physaddr, size) -#define ioremap_fullcache(physaddr, size) ioremap(physaddr, size) - -#define mmiowb() - -/* Conversion between virtual and physical mappings. */ -#define mm_ptov(addr) ((void *)phys_to_virt(addr)) -#define mm_vtop(addr) ((unsigned long)virt_to_phys(addr)) - -#if CHIP_HAS_MMIO() - -/* - * We use inline assembly to guarantee that the compiler does not - * split an access into multiple byte-sized accesses as it might - * sometimes do if a register data structure is marked "packed". - * Obviously on tile we can't tolerate such an access being - * actually unaligned, but we want to avoid the case where the - * compiler conservatively would generate multiple accesses even - * for an aligned read or write. - */ - -static inline u8 __raw_readb(const volatile void __iomem *addr) -{ - return *(const volatile u8 __force *)addr; -} - -static inline u16 __raw_readw(const volatile void __iomem *addr) -{ - u16 ret; - asm volatile("ld2u %0, %1" : "=r" (ret) : "r" (addr)); - barrier(); - return le16_to_cpu(ret); -} - -static inline u32 __raw_readl(const volatile void __iomem *addr) -{ - u32 ret; - /* Sign-extend to conform to u32 ABI sign-extension convention. */ - asm volatile("ld4s %0, %1" : "=r" (ret) : "r" (addr)); - barrier(); - return le32_to_cpu(ret); -} - -static inline u64 __raw_readq(const volatile void __iomem *addr) -{ - u64 ret; - asm volatile("ld %0, %1" : "=r" (ret) : "r" (addr)); - barrier(); - return le64_to_cpu(ret); -} - -static inline void __raw_writeb(u8 val, volatile void __iomem *addr) -{ - *(volatile u8 __force *)addr = val; -} - -static inline void __raw_writew(u16 val, volatile void __iomem *addr) -{ - asm volatile("st2 %0, %1" :: "r" (addr), "r" (cpu_to_le16(val))); -} - -static inline void __raw_writel(u32 val, volatile void __iomem *addr) -{ - asm volatile("st4 %0, %1" :: "r" (addr), "r" (cpu_to_le32(val))); -} - -static inline void __raw_writeq(u64 val, volatile void __iomem *addr) -{ - asm volatile("st %0, %1" :: "r" (addr), "r" (cpu_to_le64(val))); -} - -/* - * The on-chip I/O hardware on tilegx is configured with VA=PA for the - * kernel's PA range. The low-level APIs and field names use "va" and - * "void *" nomenclature, to be consistent with the general notion - * that the addresses in question are virtualizable, but in the kernel - * context we are actually manipulating PA values. (In other contexts, - * e.g. access from user space, we do in fact use real virtual addresses - * in the va fields.) To allow readers of the code to understand what's - * happening, we direct their attention to this comment by using the - * following two functions that just duplicate __va() and __pa(). - */ -typedef unsigned long tile_io_addr_t; -static inline tile_io_addr_t va_to_tile_io_addr(void *va) -{ - BUILD_BUG_ON(sizeof(phys_addr_t) != sizeof(tile_io_addr_t)); - return __pa(va); -} -static inline void *tile_io_addr_to_va(tile_io_addr_t tile_io_addr) -{ - return __va(tile_io_addr); -} - -#else /* CHIP_HAS_MMIO() */ - -#ifdef CONFIG_PCI - -extern u8 _tile_readb(unsigned long addr); -extern u16 _tile_readw(unsigned long addr); -extern u32 _tile_readl(unsigned long addr); -extern u64 _tile_readq(unsigned long addr); -extern void _tile_writeb(u8 val, unsigned long addr); -extern void _tile_writew(u16 val, unsigned long addr); -extern void _tile_writel(u32 val, unsigned long addr); -extern void _tile_writeq(u64 val, unsigned long addr); - -#define __raw_readb(addr) _tile_readb((unsigned long)(addr)) -#define __raw_readw(addr) _tile_readw((unsigned long)(addr)) -#define __raw_readl(addr) _tile_readl((unsigned long)(addr)) -#define __raw_readq(addr) _tile_readq((unsigned long)(addr)) -#define __raw_writeb(val, addr) _tile_writeb(val, (unsigned long)(addr)) -#define __raw_writew(val, addr) _tile_writew(val, (unsigned long)(addr)) -#define __raw_writel(val, addr) _tile_writel(val, (unsigned long)(addr)) -#define __raw_writeq(val, addr) _tile_writeq(val, (unsigned long)(addr)) - -#else /* CONFIG_PCI */ - -/* - * The tilepro architecture does not support IOMEM unless PCI is enabled. - * Unfortunately we can't yet simply not declare these methods, - * since some generic code that compiles into the kernel, but - * we never run, uses them unconditionally. - */ - -static inline int iomem_panic(void) -{ - panic("readb/writeb and friends do not exist on tile without PCI"); - return 0; -} - -static inline u8 readb(unsigned long addr) -{ - return iomem_panic(); -} - -static inline u16 _readw(unsigned long addr) -{ - return iomem_panic(); -} - -static inline u32 readl(unsigned long addr) -{ - return iomem_panic(); -} - -static inline u64 readq(unsigned long addr) -{ - return iomem_panic(); -} - -static inline void writeb(u8 val, unsigned long addr) -{ - iomem_panic(); -} - -static inline void writew(u16 val, unsigned long addr) -{ - iomem_panic(); -} - -static inline void writel(u32 val, unsigned long addr) -{ - iomem_panic(); -} - -static inline void writeq(u64 val, unsigned long addr) -{ - iomem_panic(); -} - -#endif /* CONFIG_PCI */ - -#endif /* CHIP_HAS_MMIO() */ - -#define readb __raw_readb -#define readw __raw_readw -#define readl __raw_readl -#define readq __raw_readq -#define writeb __raw_writeb -#define writew __raw_writew -#define writel __raw_writel -#define writeq __raw_writeq - -#define readb_relaxed readb -#define readw_relaxed readw -#define readl_relaxed readl -#define readq_relaxed readq -#define writeb_relaxed writeb -#define writew_relaxed writew -#define writel_relaxed writel -#define writeq_relaxed writeq - -#define ioread8 readb -#define ioread16 readw -#define ioread32 readl -#define ioread64 readq -#define iowrite8 writeb -#define iowrite16 writew -#define iowrite32 writel -#define iowrite64 writeq - -#if CHIP_HAS_MMIO() || defined(CONFIG_PCI) - -static inline void memset_io(volatile void *dst, int val, size_t len) -{ - size_t x; - BUG_ON((unsigned long)dst & 0x3); - val = (val & 0xff) * 0x01010101; - for (x = 0; x < len; x += 4) - writel(val, dst + x); -} - -static inline void memcpy_fromio(void *dst, const volatile void __iomem *src, - size_t len) -{ - size_t x; - BUG_ON((unsigned long)src & 0x3); - for (x = 0; x < len; x += 4) - *(u32 *)(dst + x) = readl(src + x); -} - -static inline void memcpy_toio(volatile void __iomem *dst, const void *src, - size_t len) -{ - size_t x; - BUG_ON((unsigned long)dst & 0x3); - for (x = 0; x < len; x += 4) - writel(*(u32 *)(src + x), dst + x); -} - -#endif - -#if CHIP_HAS_MMIO() && defined(CONFIG_TILE_PCI_IO) - -static inline u8 inb(unsigned long addr) -{ - return readb((volatile void __iomem *) addr); -} - -static inline u16 inw(unsigned long addr) -{ - return readw((volatile void __iomem *) addr); -} - -static inline u32 inl(unsigned long addr) -{ - return readl((volatile void __iomem *) addr); -} - -static inline void outb(u8 b, unsigned long addr) -{ - writeb(b, (volatile void __iomem *) addr); -} - -static inline void outw(u16 b, unsigned long addr) -{ - writew(b, (volatile void __iomem *) addr); -} - -static inline void outl(u32 b, unsigned long addr) -{ - writel(b, (volatile void __iomem *) addr); -} - -static inline void insb(unsigned long addr, void *buffer, int count) -{ - if (count) { - u8 *buf = buffer; - do { - u8 x = inb(addr); - *buf++ = x; - } while (--count); - } -} - -static inline void insw(unsigned long addr, void *buffer, int count) -{ - if (count) { - u16 *buf = buffer; - do { - u16 x = inw(addr); - *buf++ = x; - } while (--count); - } -} - -static inline void insl(unsigned long addr, void *buffer, int count) -{ - if (count) { - u32 *buf = buffer; - do { - u32 x = inl(addr); - *buf++ = x; - } while (--count); - } -} - -static inline void outsb(unsigned long addr, const void *buffer, int count) -{ - if (count) { - const u8 *buf = buffer; - do { - outb(*buf++, addr); - } while (--count); - } -} - -static inline void outsw(unsigned long addr, const void *buffer, int count) -{ - if (count) { - const u16 *buf = buffer; - do { - outw(*buf++, addr); - } while (--count); - } -} - -static inline void outsl(unsigned long addr, const void *buffer, int count) -{ - if (count) { - const u32 *buf = buffer; - do { - outl(*buf++, addr); - } while (--count); - } -} - -extern void __iomem *ioport_map(unsigned long port, unsigned int len); -extern void ioport_unmap(void __iomem *addr); - -#else - -/* - * The TilePro architecture does not support IOPORT, even with PCI. - * Unfortunately we can't yet simply not declare these methods, - * since some generic code that compiles into the kernel, but - * we never run, uses them unconditionally. - */ - -static inline long ioport_panic(void) -{ -#ifdef __tilegx__ - panic("PCI IO space support is disabled. Configure the kernel with CONFIG_TILE_PCI_IO to enable it"); -#else - panic("inb/outb and friends do not exist on tile"); -#endif - return 0; -} - -static inline void __iomem *ioport_map(unsigned long port, unsigned int len) -{ - pr_info("ioport_map: mapping IO resources is unsupported on tile\n"); - return NULL; -} - -static inline void ioport_unmap(void __iomem *addr) -{ - ioport_panic(); -} - -static inline u8 inb(unsigned long addr) -{ - return ioport_panic(); -} - -static inline u16 inw(unsigned long addr) -{ - return ioport_panic(); -} - -static inline u32 inl(unsigned long addr) -{ - return ioport_panic(); -} - -static inline void outb(u8 b, unsigned long addr) -{ - ioport_panic(); -} - -static inline void outw(u16 b, unsigned long addr) -{ - ioport_panic(); -} - -static inline void outl(u32 b, unsigned long addr) -{ - ioport_panic(); -} - -static inline void insb(unsigned long addr, void *buffer, int count) -{ - ioport_panic(); -} - -static inline void insw(unsigned long addr, void *buffer, int count) -{ - ioport_panic(); -} - -static inline void insl(unsigned long addr, void *buffer, int count) -{ - ioport_panic(); -} - -static inline void outsb(unsigned long addr, const void *buffer, int count) -{ - ioport_panic(); -} - -static inline void outsw(unsigned long addr, const void *buffer, int count) -{ - ioport_panic(); -} - -static inline void outsl(unsigned long addr, const void *buffer, int count) -{ - ioport_panic(); -} - -#endif /* CHIP_HAS_MMIO() && defined(CONFIG_TILE_PCI_IO) */ - -#define inb_p(addr) inb(addr) -#define inw_p(addr) inw(addr) -#define inl_p(addr) inl(addr) -#define outb_p(x, addr) outb((x), (addr)) -#define outw_p(x, addr) outw((x), (addr)) -#define outl_p(x, addr) outl((x), (addr)) - -#define ioread16be(addr) be16_to_cpu(ioread16(addr)) -#define ioread32be(addr) be32_to_cpu(ioread32(addr)) -#define iowrite16be(v, addr) iowrite16(be16_to_cpu(v), (addr)) -#define iowrite32be(v, addr) iowrite32(be32_to_cpu(v), (addr)) - -#define ioread8_rep(p, dst, count) \ - insb((unsigned long) (p), (dst), (count)) -#define ioread16_rep(p, dst, count) \ - insw((unsigned long) (p), (dst), (count)) -#define ioread32_rep(p, dst, count) \ - insl((unsigned long) (p), (dst), (count)) - -#define iowrite8_rep(p, src, count) \ - outsb((unsigned long) (p), (src), (count)) -#define iowrite16_rep(p, src, count) \ - outsw((unsigned long) (p), (src), (count)) -#define iowrite32_rep(p, src, count) \ - outsl((unsigned long) (p), (src), (count)) - -#define virt_to_bus virt_to_phys -#define bus_to_virt phys_to_virt - -#endif /* _ASM_TILE_IO_H */ diff --git a/arch/tile/include/asm/irq.h b/arch/tile/include/asm/irq.h deleted file mode 100644 index 1fa1f2544ff9..000000000000 --- a/arch/tile/include/asm/irq.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_IRQ_H -#define _ASM_TILE_IRQ_H - -#include - -/* The hypervisor interface provides 32 IRQs. */ -#define NR_IRQS 32 - -/* IRQ numbers used for linux IPIs. */ -#define IRQ_RESCHEDULE 0 -/* Interrupts for dynamic allocation start at 1. Let the core allocate irq0 */ -#define NR_IRQS_LEGACY 1 - -#define irq_canonicalize(irq) (irq) - -void ack_bad_irq(unsigned int irq); - -/* - * Different ways of handling interrupts. Tile interrupts are always - * per-cpu; there is no global interrupt controller to implement - * enable/disable. Most onboard devices can send their interrupts to - * many tiles at the same time, and Tile-specific drivers know how to - * deal with this. - * - * However, generic devices (usually PCIE based, sometimes GPIO) - * expect that interrupts will fire on a single core at a time and - * that the irq can be enabled or disabled from any core at any time. - * We implement this by directing such interrupts to a single core. - * - * One added wrinkle is that PCI interrupts can be either - * hardware-cleared (legacy interrupts) or software cleared (MSI). - * Other generic device systems (GPIO) are always software-cleared. - * - * The enums below are used by drivers for onboard devices, including - * the internals of PCI root complex and GPIO. They allow the driver - * to tell the generic irq code what kind of interrupt is mapped to a - * particular IRQ number. - */ -enum { - /* per-cpu interrupt; use enable/disable_percpu_irq() to mask */ - TILE_IRQ_PERCPU, - /* global interrupt, hardware responsible for clearing. */ - TILE_IRQ_HW_CLEAR, - /* global interrupt, software responsible for clearing. */ - TILE_IRQ_SW_CLEAR, -}; - - -/* - * Paravirtualized drivers should call this when they dynamically - * allocate a new IRQ or discover an IRQ that was pre-allocated by the - * hypervisor for use with their particular device. This gives the - * IRQ subsystem an opportunity to do interrupt-type-specific - * initialization. - * - * ISSUE: We should modify this API so that registering anything - * except percpu interrupts also requires providing callback methods - * for enabling and disabling the interrupt. This would allow the - * generic IRQ code to proxy enable/disable_irq() calls back into the - * PCI subsystem, which in turn could enable or disable the interrupt - * at the PCI shim. - */ -void tile_irq_activate(unsigned int irq, int tile_irq_type); - -void setup_irq_regs(void); - -#ifdef __tilegx__ -void arch_trigger_cpumask_backtrace(const struct cpumask *mask, - bool exclude_self); -#define arch_trigger_cpumask_backtrace arch_trigger_cpumask_backtrace -#endif - -#endif /* _ASM_TILE_IRQ_H */ diff --git a/arch/tile/include/asm/irq_work.h b/arch/tile/include/asm/irq_work.h deleted file mode 100644 index 78d3b6a7b27a..000000000000 --- a/arch/tile/include/asm/irq_work.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __ASM_IRQ_WORK_H -#define __ASM_IRQ_WORK_H - -static inline bool arch_irq_work_has_interrupt(void) -{ -#ifdef CONFIG_SMP - extern bool self_interrupt_ok; - return self_interrupt_ok; -#else - return false; -#endif -} - -#endif /* __ASM_IRQ_WORK_H */ diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h deleted file mode 100644 index 60d62a292fce..000000000000 --- a/arch/tile/include/asm/irqflags.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_IRQFLAGS_H -#define _ASM_TILE_IRQFLAGS_H - -#include -#include - -/* - * The set of interrupts we want to allow when interrupts are nominally - * disabled. The remainder are effectively "NMI" interrupts from - * the point of view of the generic Linux code. Note that synchronous - * interrupts (aka "non-queued") are not blocked by the mask in any case. - */ -#define LINUX_MASKABLE_INTERRUPTS \ - (~((_AC(1,ULL) << INT_PERF_COUNT) | (_AC(1,ULL) << INT_AUX_PERF_COUNT))) - -#if CHIP_HAS_SPLIT_INTR_MASK() -/* The same macro, but for the two 32-bit SPRs separately. */ -#define LINUX_MASKABLE_INTERRUPTS_LO (-1) -#define LINUX_MASKABLE_INTERRUPTS_HI \ - (~((1 << (INT_PERF_COUNT - 32)) | (1 << (INT_AUX_PERF_COUNT - 32)))) -#endif - -#ifndef __ASSEMBLY__ - -/* NOTE: we can't include due to #include dependencies. */ -#include -#include - -/* - * Set and clear kernel interrupt masks. - * - * NOTE: __insn_mtspr() is a compiler builtin marked as a memory - * clobber. We rely on it being equivalent to a compiler barrier in - * this code since arch_local_irq_save() and friends must act as - * compiler barriers. This compiler semantic is baked into enough - * places that the compiler will maintain it going forward. - */ -#if CHIP_HAS_SPLIT_INTR_MASK() -#if INT_PERF_COUNT < 32 || INT_AUX_PERF_COUNT < 32 || INT_MEM_ERROR >= 32 -# error Fix assumptions about which word various interrupts are in -#endif -#define interrupt_mask_set(n) do { \ - int __n = (n); \ - int __mask = 1 << (__n & 0x1f); \ - if (__n < 32) \ - __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_0, __mask); \ - else \ - __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_1, __mask); \ -} while (0) -#define interrupt_mask_reset(n) do { \ - int __n = (n); \ - int __mask = 1 << (__n & 0x1f); \ - if (__n < 32) \ - __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_0, __mask); \ - else \ - __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_1, __mask); \ -} while (0) -#define interrupt_mask_check(n) ({ \ - int __n = (n); \ - (((__n < 32) ? \ - __insn_mfspr(SPR_INTERRUPT_MASK_K_0) : \ - __insn_mfspr(SPR_INTERRUPT_MASK_K_1)) \ - >> (__n & 0x1f)) & 1; \ -}) -#define interrupt_mask_set_mask(mask) do { \ - unsigned long long __m = (mask); \ - __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_0, (unsigned long)(__m)); \ - __insn_mtspr(SPR_INTERRUPT_MASK_SET_K_1, (unsigned long)(__m>>32)); \ -} while (0) -#define interrupt_mask_reset_mask(mask) do { \ - unsigned long long __m = (mask); \ - __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_0, (unsigned long)(__m)); \ - __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_1, (unsigned long)(__m>>32)); \ -} while (0) -#define interrupt_mask_save_mask() \ - (__insn_mfspr(SPR_INTERRUPT_MASK_SET_K_0) | \ - (((unsigned long long)__insn_mfspr(SPR_INTERRUPT_MASK_SET_K_1))<<32)) -#define interrupt_mask_restore_mask(mask) do { \ - unsigned long long __m = (mask); \ - __insn_mtspr(SPR_INTERRUPT_MASK_K_0, (unsigned long)(__m)); \ - __insn_mtspr(SPR_INTERRUPT_MASK_K_1, (unsigned long)(__m>>32)); \ -} while (0) -#else -#define interrupt_mask_set(n) \ - __insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (1UL << (n))) -#define interrupt_mask_reset(n) \ - __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K, (1UL << (n))) -#define interrupt_mask_check(n) \ - ((__insn_mfspr(SPR_INTERRUPT_MASK_K) >> (n)) & 1) -#define interrupt_mask_set_mask(mask) \ - __insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (mask)) -#define interrupt_mask_reset_mask(mask) \ - __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K, (mask)) -#define interrupt_mask_save_mask() \ - __insn_mfspr(SPR_INTERRUPT_MASK_K) -#define interrupt_mask_restore_mask(mask) \ - __insn_mtspr(SPR_INTERRUPT_MASK_K, (mask)) -#endif - -/* - * The set of interrupts we want active if irqs are enabled. - * Note that in particular, the tile timer interrupt comes and goes - * from this set, since we have no other way to turn off the timer. - * Likewise, INTCTRL_K is removed and re-added during device - * interrupts, as is the the hardwall UDN_FIREWALL interrupt. - * We use a low bit (MEM_ERROR) as our sentinel value and make sure it - * is always claimed as an "active interrupt" so we can query that bit - * to know our current state. - */ -DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask); -#define INITIAL_INTERRUPTS_ENABLED (1ULL << INT_MEM_ERROR) - -#ifdef CONFIG_DEBUG_PREEMPT -/* Due to inclusion issues, we can't rely on here. */ -extern unsigned int debug_smp_processor_id(void); -# define smp_processor_id() debug_smp_processor_id() -#endif - -/* Disable interrupts. */ -#define arch_local_irq_disable() \ - interrupt_mask_set_mask(LINUX_MASKABLE_INTERRUPTS) - -/* Disable all interrupts, including NMIs. */ -#define arch_local_irq_disable_all() \ - interrupt_mask_set_mask(-1ULL) - -/* - * Read the set of maskable interrupts. - * We avoid the preemption warning here via raw_cpu_ptr since even - * if irqs are already enabled, it's harmless to read the wrong cpu's - * enabled mask. - */ -#define arch_local_irqs_enabled() \ - (*raw_cpu_ptr(&interrupts_enabled_mask)) - -/* Re-enable all maskable interrupts. */ -#define arch_local_irq_enable() \ - interrupt_mask_reset_mask(arch_local_irqs_enabled()) - -/* Disable or enable interrupts based on flag argument. */ -#define arch_local_irq_restore(disabled) do { \ - if (disabled) \ - arch_local_irq_disable(); \ - else \ - arch_local_irq_enable(); \ -} while (0) - -/* Return true if "flags" argument means interrupts are disabled. */ -#define arch_irqs_disabled_flags(flags) ((flags) != 0) - -/* Return true if interrupts are currently disabled. */ -#define arch_irqs_disabled() interrupt_mask_check(INT_MEM_ERROR) - -/* Save whether interrupts are currently disabled. */ -#define arch_local_save_flags() arch_irqs_disabled() - -/* Save whether interrupts are currently disabled, then disable them. */ -#define arch_local_irq_save() ({ \ - unsigned long __flags = arch_local_save_flags(); \ - arch_local_irq_disable(); \ - __flags; }) - -/* Prevent the given interrupt from being enabled next time we enable irqs. */ -#define arch_local_irq_mask(interrupt) \ - this_cpu_and(interrupts_enabled_mask, ~(1ULL << (interrupt))) - -/* Prevent the given interrupt from being enabled immediately. */ -#define arch_local_irq_mask_now(interrupt) do { \ - arch_local_irq_mask(interrupt); \ - interrupt_mask_set(interrupt); \ -} while (0) - -/* Allow the given interrupt to be enabled next time we enable irqs. */ -#define arch_local_irq_unmask(interrupt) \ - this_cpu_or(interrupts_enabled_mask, (1ULL << (interrupt))) - -/* Allow the given interrupt to be enabled immediately, if !irqs_disabled. */ -#define arch_local_irq_unmask_now(interrupt) do { \ - arch_local_irq_unmask(interrupt); \ - if (!irqs_disabled()) \ - interrupt_mask_reset(interrupt); \ -} while (0) - -#else /* __ASSEMBLY__ */ - -/* We provide a somewhat more restricted set for assembly. */ - -#ifdef __tilegx__ - -#if INT_MEM_ERROR != 0 -# error Fix IRQS_DISABLED() macro -#endif - -/* Return 0 or 1 to indicate whether interrupts are currently disabled. */ -#define IRQS_DISABLED(tmp) \ - mfspr tmp, SPR_INTERRUPT_MASK_K; \ - andi tmp, tmp, 1 - -/* Load up a pointer to &interrupts_enabled_mask. */ -#define GET_INTERRUPTS_ENABLED_MASK_PTR(reg) \ - moveli reg, hw2_last(interrupts_enabled_mask); \ - shl16insli reg, reg, hw1(interrupts_enabled_mask); \ - shl16insli reg, reg, hw0(interrupts_enabled_mask); \ - add reg, reg, tp - -/* Disable interrupts. */ -#define IRQ_DISABLE(tmp0, tmp1) \ - moveli tmp0, hw2_last(LINUX_MASKABLE_INTERRUPTS); \ - shl16insli tmp0, tmp0, hw1(LINUX_MASKABLE_INTERRUPTS); \ - shl16insli tmp0, tmp0, hw0(LINUX_MASKABLE_INTERRUPTS); \ - mtspr SPR_INTERRUPT_MASK_SET_K, tmp0 - -/* Disable ALL synchronous interrupts (used by NMI entry). */ -#define IRQ_DISABLE_ALL(tmp) \ - movei tmp, -1; \ - mtspr SPR_INTERRUPT_MASK_SET_K, tmp - -/* Enable interrupts. */ -#define IRQ_ENABLE_LOAD(tmp0, tmp1) \ - GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0); \ - ld tmp0, tmp0 -#define IRQ_ENABLE_APPLY(tmp0, tmp1) \ - mtspr SPR_INTERRUPT_MASK_RESET_K, tmp0 - -#else /* !__tilegx__ */ - -/* - * Return 0 or 1 to indicate whether interrupts are currently disabled. - * Note that it's important that we use a bit from the "low" mask word, - * since when we are enabling, that is the word we write first, so if we - * are interrupted after only writing half of the mask, the interrupt - * handler will correctly observe that we have interrupts enabled, and - * will enable interrupts itself on return from the interrupt handler - * (making the original code's write of the "high" mask word idempotent). - */ -#define IRQS_DISABLED(tmp) \ - mfspr tmp, SPR_INTERRUPT_MASK_K_0; \ - shri tmp, tmp, INT_MEM_ERROR; \ - andi tmp, tmp, 1 - -/* Load up a pointer to &interrupts_enabled_mask. */ -#define GET_INTERRUPTS_ENABLED_MASK_PTR(reg) \ - moveli reg, lo16(interrupts_enabled_mask); \ - auli reg, reg, ha16(interrupts_enabled_mask); \ - add reg, reg, tp - -/* Disable interrupts. */ -#define IRQ_DISABLE(tmp0, tmp1) \ - { \ - movei tmp0, LINUX_MASKABLE_INTERRUPTS_LO; \ - moveli tmp1, lo16(LINUX_MASKABLE_INTERRUPTS_HI) \ - }; \ - { \ - mtspr SPR_INTERRUPT_MASK_SET_K_0, tmp0; \ - auli tmp1, tmp1, ha16(LINUX_MASKABLE_INTERRUPTS_HI) \ - }; \ - mtspr SPR_INTERRUPT_MASK_SET_K_1, tmp1 - -/* Disable ALL synchronous interrupts (used by NMI entry). */ -#define IRQ_DISABLE_ALL(tmp) \ - movei tmp, -1; \ - mtspr SPR_INTERRUPT_MASK_SET_K_0, tmp; \ - mtspr SPR_INTERRUPT_MASK_SET_K_1, tmp - -/* Enable interrupts. */ -#define IRQ_ENABLE_LOAD(tmp0, tmp1) \ - GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0); \ - { \ - lw tmp0, tmp0; \ - addi tmp1, tmp0, 4 \ - }; \ - lw tmp1, tmp1 -#define IRQ_ENABLE_APPLY(tmp0, tmp1) \ - mtspr SPR_INTERRUPT_MASK_RESET_K_0, tmp0; \ - mtspr SPR_INTERRUPT_MASK_RESET_K_1, tmp1 -#endif - -#define IRQ_ENABLE(tmp0, tmp1) \ - IRQ_ENABLE_LOAD(tmp0, tmp1); \ - IRQ_ENABLE_APPLY(tmp0, tmp1) - -/* - * Do the CPU's IRQ-state tracing from assembly code. We call a - * C function, but almost everywhere we do, we don't mind clobbering - * all the caller-saved registers. - */ -#ifdef CONFIG_TRACE_IRQFLAGS -# define TRACE_IRQS_ON jal trace_hardirqs_on -# define TRACE_IRQS_OFF jal trace_hardirqs_off -#else -# define TRACE_IRQS_ON -# define TRACE_IRQS_OFF -#endif - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_TILE_IRQFLAGS_H */ diff --git a/arch/tile/include/asm/jump_label.h b/arch/tile/include/asm/jump_label.h deleted file mode 100644 index cde7573f397b..000000000000 --- a/arch/tile/include/asm/jump_label.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2015 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_JUMP_LABEL_H -#define _ASM_TILE_JUMP_LABEL_H - -#include - -#define JUMP_LABEL_NOP_SIZE TILE_BUNDLE_SIZE_IN_BYTES - -static __always_inline bool arch_static_branch(struct static_key *key, - bool branch) -{ - asm_volatile_goto("1:\n\t" - "nop" "\n\t" - ".pushsection __jump_table, \"aw\"\n\t" - ".quad 1b, %l[l_yes], %0 + %1 \n\t" - ".popsection\n\t" - : : "i" (key), "i" (branch) : : l_yes); - return false; -l_yes: - return true; -} - -static __always_inline bool arch_static_branch_jump(struct static_key *key, - bool branch) -{ - asm_volatile_goto("1:\n\t" - "j %l[l_yes]" "\n\t" - ".pushsection __jump_table, \"aw\"\n\t" - ".quad 1b, %l[l_yes], %0 + %1 \n\t" - ".popsection\n\t" - : : "i" (key), "i" (branch) : : l_yes); - return false; -l_yes: - return true; -} - -typedef u64 jump_label_t; - -struct jump_entry { - jump_label_t code; - jump_label_t target; - jump_label_t key; -}; - -#endif /* _ASM_TILE_JUMP_LABEL_H */ diff --git a/arch/tile/include/asm/kdebug.h b/arch/tile/include/asm/kdebug.h deleted file mode 100644 index 5bbbfa904c2d..000000000000 --- a/arch/tile/include/asm/kdebug.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_KDEBUG_H -#define _ASM_TILE_KDEBUG_H - -#include - -enum die_val { - DIE_OOPS = 1, - DIE_BREAK, - DIE_SSTEPBP, - DIE_PAGE_FAULT, - DIE_COMPILED_BPT -}; - -#endif /* _ASM_TILE_KDEBUG_H */ diff --git a/arch/tile/include/asm/kexec.h b/arch/tile/include/asm/kexec.h deleted file mode 100644 index fc98ccfc98ac..000000000000 --- a/arch/tile/include/asm/kexec.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * based on kexec.h from other architectures in linux-2.6.18 - */ - -#ifndef _ASM_TILE_KEXEC_H -#define _ASM_TILE_KEXEC_H - -#include - -#ifndef __tilegx__ -/* Maximum physical address we can use pages from. */ -#define KEXEC_SOURCE_MEMORY_LIMIT TASK_SIZE -/* Maximum address we can reach in physical address mode. */ -#define KEXEC_DESTINATION_MEMORY_LIMIT TASK_SIZE -/* Maximum address we can use for the control code buffer. */ -#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE -#else -/* We need to limit the memory below PGDIR_SIZE since - * we only setup page table for [0, PGDIR_SIZE) before final kexec. - */ -/* Maximum physical address we can use pages from. */ -#define KEXEC_SOURCE_MEMORY_LIMIT PGDIR_SIZE -/* Maximum address we can reach in physical address mode. */ -#define KEXEC_DESTINATION_MEMORY_LIMIT PGDIR_SIZE -/* Maximum address we can use for the control code buffer. */ -#define KEXEC_CONTROL_MEMORY_LIMIT PGDIR_SIZE -#endif - -#define KEXEC_CONTROL_PAGE_SIZE PAGE_SIZE - -/* - * We don't bother to provide a unique identifier, since we can only - * reboot with a single type of kernel image anyway. - */ -#define KEXEC_ARCH KEXEC_ARCH_DEFAULT - -/* Use the tile override for the page allocator. */ -struct page *kimage_alloc_pages_arch(gfp_t gfp_mask, unsigned int order); -#define kimage_alloc_pages_arch kimage_alloc_pages_arch - -#define MAX_NOTE_BYTES 1024 - -/* Defined in arch/tile/kernel/relocate_kernel.S */ -extern const unsigned char relocate_new_kernel[]; -extern const unsigned long relocate_new_kernel_size; -extern void relocate_new_kernel_end(void); - -/* Provide a dummy definition to avoid build failures. */ -static inline void crash_setup_regs(struct pt_regs *n, struct pt_regs *o) -{ -} - -#endif /* _ASM_TILE_KEXEC_H */ diff --git a/arch/tile/include/asm/kgdb.h b/arch/tile/include/asm/kgdb.h deleted file mode 100644 index 280c181cf0db..000000000000 --- a/arch/tile/include/asm/kgdb.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * TILE-Gx KGDB support. - */ - -#ifndef __TILE_KGDB_H__ -#define __TILE_KGDB_H__ - -#include -#include - -#define GDB_SIZEOF_REG sizeof(unsigned long) - -/* - * TILE-Gx gdb is expecting the following register layout: - * 56 GPRs(R0 - R52, TP, SP, LR), 8 special GPRs(networks and ZERO), - * plus the PC and the faultnum. - * - * Even though kernel not use the 8 special GPRs, they need to be present - * in the registers sent for correct processing in the host-side gdb. - * - */ -#define DBG_MAX_REG_NUM (56+8+2) -#define NUMREGBYTES (DBG_MAX_REG_NUM * GDB_SIZEOF_REG) - -/* - * BUFMAX defines the maximum number of characters in inbound/outbound - * buffers at least NUMREGBYTES*2 are needed for register packets, - * Longer buffer is needed to list all threads. - */ -#define BUFMAX 2048 - -#define BREAK_INSTR_SIZE TILEGX_BUNDLE_SIZE_IN_BYTES - -/* - * Require cache flush for set/clear a software breakpoint or write memory. - */ -#define CACHE_FLUSH_IS_SAFE 1 - -/* - * The compiled-in breakpoint instruction can be used to "break" into - * the debugger via magic system request key (sysrq-G). - */ -static tile_bundle_bits compiled_bpt = TILEGX_BPT_BUNDLE | DIE_COMPILED_BPT; - -enum tilegx_regnum { - TILEGX_PC_REGNUM = TREG_LAST_GPR + 9, - TILEGX_FAULTNUM_REGNUM, -}; - -/* - * Generate a breakpoint exception to "break" into the debugger. - */ -static inline void arch_kgdb_breakpoint(void) -{ - asm volatile (".quad %0\n\t" - ::""(compiled_bpt)); -} - -#endif /* __TILE_KGDB_H__ */ diff --git a/arch/tile/include/asm/kmap_types.h b/arch/tile/include/asm/kmap_types.h deleted file mode 100644 index 92b28e3e9972..000000000000 --- a/arch/tile/include/asm/kmap_types.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_KMAP_TYPES_H -#define _ASM_TILE_KMAP_TYPES_H - -/* - * In 32-bit TILE Linux we have to balance the desire to have a lot of - * nested atomic mappings with the fact that large page sizes and many - * processors chew up address space quickly. In a typical - * 64-processor, 64KB-page layout build, making KM_TYPE_NR one larger - * adds 4MB of required address-space. For now we leave KM_TYPE_NR - * set to depth 8. - */ -#define KM_TYPE_NR 8 - -#endif /* _ASM_TILE_KMAP_TYPES_H */ diff --git a/arch/tile/include/asm/kprobes.h b/arch/tile/include/asm/kprobes.h deleted file mode 100644 index 4a8b1cadca24..000000000000 --- a/arch/tile/include/asm/kprobes.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * arch/tile/include/asm/kprobes.h - * - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_KPROBES_H -#define _ASM_TILE_KPROBES_H - -#include - -#ifdef CONFIG_KPROBES - -#include -#include -#include -#include - -#define __ARCH_WANT_KPROBES_INSN_SLOT -#define MAX_INSN_SIZE 2 - -#define kretprobe_blacklist_size 0 - -typedef tile_bundle_bits kprobe_opcode_t; - -#define flush_insn_slot(p) \ - flush_icache_range((unsigned long)p->addr, \ - (unsigned long)p->addr + \ - (MAX_INSN_SIZE * sizeof(kprobe_opcode_t))) - -struct kprobe; - -/* Architecture specific copy of original instruction. */ -struct arch_specific_insn { - kprobe_opcode_t *insn; -}; - -struct prev_kprobe { - struct kprobe *kp; - unsigned long status; - unsigned long saved_pc; -}; - -#define MAX_JPROBES_STACK_SIZE 128 -#define MAX_JPROBES_STACK_ADDR \ - (((unsigned long)current_thread_info()) + THREAD_SIZE - 32 \ - - sizeof(struct pt_regs)) - -#define MIN_JPROBES_STACK_SIZE(ADDR) \ - ((((ADDR) + MAX_JPROBES_STACK_SIZE) > MAX_JPROBES_STACK_ADDR) \ - ? MAX_JPROBES_STACK_ADDR - (ADDR) \ - : MAX_JPROBES_STACK_SIZE) - -/* per-cpu kprobe control block. */ -struct kprobe_ctlblk { - unsigned long kprobe_status; - unsigned long kprobe_saved_pc; - unsigned long jprobe_saved_sp; - struct prev_kprobe prev_kprobe; - struct pt_regs jprobe_saved_regs; - char jprobes_stack[MAX_JPROBES_STACK_SIZE]; -}; - -extern tile_bundle_bits breakpoint2_insn; -extern tile_bundle_bits breakpoint_insn; - -void arch_remove_kprobe(struct kprobe *); - -extern int kprobe_exceptions_notify(struct notifier_block *self, - unsigned long val, void *data); - -#endif /* CONFIG_KPROBES */ -#endif /* _ASM_TILE_KPROBES_H */ diff --git a/arch/tile/include/asm/linkage.h b/arch/tile/include/asm/linkage.h deleted file mode 100644 index e121c39751a7..000000000000 --- a/arch/tile/include/asm/linkage.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_LINKAGE_H -#define _ASM_TILE_LINKAGE_H - -#include - -#define __ALIGN .align 8 - -/* - * The STD_ENTRY and STD_ENDPROC macros put the function in a - * self-named .text.foo section, and if linker feedback collection - * is enabled, add a suitable call to the feedback collection code. - * STD_ENTRY_SECTION lets you specify a non-standard section name. - */ - -#define STD_ENTRY(name) \ - .pushsection .text.##name, "ax"; \ - ENTRY(name); \ - FEEDBACK_ENTER(name) - -#define STD_ENTRY_SECTION(name, section) \ - .pushsection section, "ax"; \ - ENTRY(name); \ - FEEDBACK_ENTER_EXPLICIT(name, section, .Lend_##name - name) - -#define STD_ENDPROC(name) \ - ENDPROC(name); \ - .Lend_##name:; \ - .popsection - -/* Create a file-static function entry set up for feedback gathering. */ -#define STD_ENTRY_LOCAL(name) \ - .pushsection .text.##name, "ax"; \ - ALIGN; \ - name:; \ - FEEDBACK_ENTER(name) - -#endif /* _ASM_TILE_LINKAGE_H */ diff --git a/arch/tile/include/asm/mmu.h b/arch/tile/include/asm/mmu.h deleted file mode 100644 index 0cab1182bde1..000000000000 --- a/arch/tile/include/asm/mmu.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_MMU_H -#define _ASM_TILE_MMU_H - -/* Capture any arch- and mm-specific information. */ -struct mm_context { - /* - * Written under the mmap_sem semaphore; read without the - * semaphore but atomically, but it is conservatively set. - */ - unsigned long priority_cached; - unsigned long vdso_base; -}; - -typedef struct mm_context mm_context_t; - -void leave_mm(int cpu); - -#endif /* _ASM_TILE_MMU_H */ diff --git a/arch/tile/include/asm/mmu_context.h b/arch/tile/include/asm/mmu_context.h deleted file mode 100644 index 45a4b4c424cf..000000000000 --- a/arch/tile/include/asm/mmu_context.h +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_MMU_CONTEXT_H -#define _ASM_TILE_MMU_CONTEXT_H - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -static inline int -init_new_context(struct task_struct *tsk, struct mm_struct *mm) -{ - return 0; -} - -/* - * Note that arch/tile/kernel/head_NN.S and arch/tile/mm/migrate_NN.S - * also call hv_install_context(). - */ -static inline void __install_page_table(pgd_t *pgdir, int asid, pgprot_t prot) -{ - /* FIXME: DIRECTIO should not always be set. FIXME. */ - int rc = hv_install_context(__pa(pgdir), prot, asid, - HV_CTX_DIRECTIO | CTX_PAGE_FLAG); - if (rc < 0) - panic("hv_install_context failed: %d", rc); -} - -static inline void install_page_table(pgd_t *pgdir, int asid) -{ - pte_t *ptep = virt_to_kpte((unsigned long)pgdir); - __install_page_table(pgdir, asid, *ptep); -} - -/* - * "Lazy" TLB mode is entered when we are switching to a kernel task, - * which borrows the mm of the previous task. The goal of this - * optimization is to avoid having to install a new page table. On - * early x86 machines (where the concept originated) you couldn't do - * anything short of a full page table install for invalidation, so - * handling a remote TLB invalidate required doing a page table - * re-install. Someone clearly decided that it was silly to keep - * doing this while in "lazy" TLB mode, so the optimization involves - * installing the swapper page table instead the first time one - * occurs, and clearing the cpu out of cpu_vm_mask, so the cpu running - * the kernel task doesn't need to take any more interrupts. At that - * point it's then necessary to explicitly reinstall it when context - * switching back to the original mm. - * - * On Tile, we have to do a page-table install whenever DMA is enabled, - * so in that case lazy mode doesn't help anyway. And more generally, - * we have efficient per-page TLB shootdown, and don't expect to spend - * that much time in kernel tasks in general, so just leaving the - * kernel task borrowing the old page table, but handling TLB - * shootdowns, is a reasonable thing to do. And importantly, this - * lets us use the hypervisor's internal APIs for TLB shootdown, which - * means we don't have to worry about having TLB shootdowns blocked - * when Linux is disabling interrupts; see the page migration code for - * an example of where it's important for TLB shootdowns to complete - * even when interrupts are disabled at the Linux level. - */ -static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *t) -{ -#if CHIP_HAS_TILE_DMA() - /* - * We have to do an "identity" page table switch in order to - * clear any pending DMA interrupts. - */ - if (current->thread.tile_dma_state.enabled) - install_page_table(mm->pgd, __this_cpu_read(current_asid)); -#endif -} - -static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, - struct task_struct *tsk) -{ - if (likely(prev != next)) { - - int cpu = smp_processor_id(); - - /* Pick new ASID. */ - int asid = __this_cpu_read(current_asid) + 1; - if (asid > max_asid) { - asid = min_asid; - local_flush_tlb(); - } - __this_cpu_write(current_asid, asid); - - /* Clear cpu from the old mm, and set it in the new one. */ - cpumask_clear_cpu(cpu, mm_cpumask(prev)); - cpumask_set_cpu(cpu, mm_cpumask(next)); - - /* Re-load page tables */ - install_page_table(next->pgd, asid); - - /* See how we should set the red/black cache info */ - check_mm_caching(prev, next); - - /* - * Since we're changing to a new mm, we have to flush - * the icache in case some physical page now being mapped - * has subsequently been repurposed and has new code. - */ - __flush_icache(); - - } -} - -static inline void activate_mm(struct mm_struct *prev_mm, - struct mm_struct *next_mm) -{ - switch_mm(prev_mm, next_mm, NULL); -} - -#define destroy_context(mm) do { } while (0) -#define deactivate_mm(tsk, mm) do { } while (0) - -#endif /* _ASM_TILE_MMU_CONTEXT_H */ diff --git a/arch/tile/include/asm/mmzone.h b/arch/tile/include/asm/mmzone.h deleted file mode 100644 index 804f1098b6cd..000000000000 --- a/arch/tile/include/asm/mmzone.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_MMZONE_H -#define _ASM_TILE_MMZONE_H - -extern struct pglist_data node_data[]; -#define NODE_DATA(nid) (&node_data[nid]) - -extern void get_memcfg_numa(void); - -#ifdef CONFIG_DISCONTIGMEM - -#include - -/* - * Generally, memory ranges are always doled out by the hypervisor in - * fixed-size, power-of-two increments. That would make computing the node - * very easy. We could just take a couple high bits of the PA, which - * denote the memory shim, and we'd be done. However, when we're doing - * memory striping, this may not be true; PAs with different high bit - * values might be in the same node. Thus, we keep a lookup table to - * translate the high bits of the PFN to the node number. - */ -extern int highbits_to_node[]; - -static inline int pfn_to_nid(unsigned long pfn) -{ - return highbits_to_node[__pfn_to_highbits(pfn)]; -} - -#define kern_addr_valid(kaddr) virt_addr_valid((void *)kaddr) - -static inline int pfn_valid(unsigned long pfn) -{ - int nid = pfn_to_nid(pfn); - - if (nid >= 0) - return (pfn < node_end_pfn(nid)); - return 0; -} - -/* Information on the NUMA nodes that we compute early */ -extern unsigned long node_start_pfn[]; -extern unsigned long node_end_pfn[]; -extern unsigned long node_memmap_pfn[]; -extern unsigned long node_percpu_pfn[]; -extern unsigned long node_free_pfn[]; -#ifdef CONFIG_HIGHMEM -extern unsigned long node_lowmem_end_pfn[]; -#endif -#ifdef CONFIG_PCI -extern unsigned long pci_reserve_start_pfn; -extern unsigned long pci_reserve_end_pfn; -#endif - -#endif /* CONFIG_DISCONTIGMEM */ - -#endif /* _ASM_TILE_MMZONE_H */ diff --git a/arch/tile/include/asm/module.h b/arch/tile/include/asm/module.h deleted file mode 100644 index 44ed07ccd3d2..000000000000 --- a/arch/tile/include/asm/module.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_MODULE_H -#define _ASM_TILE_MODULE_H - -#include - -#include - -/* We can't use modules built with different page sizes. */ -#if defined(CONFIG_PAGE_SIZE_16KB) -# define MODULE_PGSZ " 16KB" -#elif defined(CONFIG_PAGE_SIZE_64KB) -# define MODULE_PGSZ " 64KB" -#else -# define MODULE_PGSZ "" -#endif - -/* We don't really support no-SMP so tag if someone tries. */ -#ifdef CONFIG_SMP -#define MODULE_NOSMP "" -#else -#define MODULE_NOSMP " nosmp" -#endif - -#define MODULE_ARCH_VERMAGIC CHIP_ARCH_NAME MODULE_PGSZ MODULE_NOSMP - -#endif /* _ASM_TILE_MODULE_H */ diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h deleted file mode 100644 index 498a5f71245d..000000000000 --- a/arch/tile/include/asm/page.h +++ /dev/null @@ -1,345 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_PAGE_H -#define _ASM_TILE_PAGE_H - -#include -#include -#include - -/* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */ -#if defined(CONFIG_PAGE_SIZE_4KB) /* tilepro only */ -#define PAGE_SHIFT 12 -#define CTX_PAGE_FLAG HV_CTX_PG_SM_4K -#elif defined(CONFIG_PAGE_SIZE_16KB) -#define PAGE_SHIFT 14 -#define CTX_PAGE_FLAG HV_CTX_PG_SM_16K -#elif defined(CONFIG_PAGE_SIZE_64KB) -#define PAGE_SHIFT 16 -#define CTX_PAGE_FLAG HV_CTX_PG_SM_64K -#else -#error Page size not specified in Kconfig -#endif -#define HPAGE_SHIFT HV_LOG2_DEFAULT_PAGE_SIZE_LARGE - -#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) -#define HPAGE_SIZE (_AC(1, UL) << HPAGE_SHIFT) - -#define PAGE_MASK (~(PAGE_SIZE - 1)) -#define HPAGE_MASK (~(HPAGE_SIZE - 1)) - -/* - * If the Kconfig doesn't specify, set a maximum zone order that - * is enough so that we can create huge pages from small pages given - * the respective sizes of the two page types. See . - */ -#ifndef CONFIG_FORCE_MAX_ZONEORDER -#define CONFIG_FORCE_MAX_ZONEORDER (HPAGE_SHIFT - PAGE_SHIFT + 1) -#endif - -#ifndef __ASSEMBLY__ - -#include -#include - -struct page; - -static inline void clear_page(void *page) -{ - memset(page, 0, PAGE_SIZE); -} - -static inline void copy_page(void *to, void *from) -{ - memcpy(to, from, PAGE_SIZE); -} - -static inline void clear_user_page(void *page, unsigned long vaddr, - struct page *pg) -{ - clear_page(page); -} - -static inline void copy_user_page(void *to, void *from, unsigned long vaddr, - struct page *topage) -{ - copy_page(to, from); -} - -/* - * Hypervisor page tables are made of the same basic structure. - */ - -typedef HV_PTE pte_t; -typedef HV_PTE pgd_t; -typedef HV_PTE pgprot_t; - -/* - * User L2 page tables are managed as one L2 page table per page, - * because we use the page allocator for them. This keeps the allocation - * simple, but it's also inefficient, since L2 page tables are much smaller - * than pages (currently 2KB vs 64KB). So we should revisit this. - */ -typedef struct page *pgtable_t; - -/* Must be a macro since it is used to create constants. */ -#define __pgprot(val) hv_pte(val) - -/* Rarely-used initializers, typically with a "zero" value. */ -#define __pte(x) hv_pte(x) -#define __pgd(x) hv_pte(x) - -static inline u64 pgprot_val(pgprot_t pgprot) -{ - return hv_pte_val(pgprot); -} - -static inline u64 pte_val(pte_t pte) -{ - return hv_pte_val(pte); -} - -static inline u64 pgd_val(pgd_t pgd) -{ - return hv_pte_val(pgd); -} - -#ifdef __tilegx__ - -typedef HV_PTE pmd_t; - -#define __pmd(x) hv_pte(x) - -static inline u64 pmd_val(pmd_t pmd) -{ - return hv_pte_val(pmd); -} - -#endif - -static inline __attribute_const__ int get_order(unsigned long size) -{ - return BITS_PER_LONG - __builtin_clzl((size - 1) >> PAGE_SHIFT); -} - -#endif /* !__ASSEMBLY__ */ - -#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) - -#define HUGE_MAX_HSTATE 6 - -#ifdef CONFIG_HUGETLB_PAGE -#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA -#endif - -/* Allow overriding how much VA or PA the kernel will use. */ -#define MAX_PA_WIDTH CHIP_PA_WIDTH() -#define MAX_VA_WIDTH CHIP_VA_WIDTH() - -/* Each memory controller has PAs distinct in their high bits. */ -#define NR_PA_HIGHBIT_SHIFT (MAX_PA_WIDTH - CHIP_LOG_NUM_MSHIMS()) -#define NR_PA_HIGHBIT_VALUES (1 << CHIP_LOG_NUM_MSHIMS()) -#define __pa_to_highbits(pa) ((phys_addr_t)(pa) >> NR_PA_HIGHBIT_SHIFT) -#define __pfn_to_highbits(pfn) ((pfn) >> (NR_PA_HIGHBIT_SHIFT - PAGE_SHIFT)) - -#ifdef __tilegx__ - -/* - * We reserve the lower half of memory for user-space programs, and the - * upper half for system code. We re-map all of physical memory in the - * upper half, which takes a quarter of our VA space. Then we have - * the vmalloc regions. The supervisor code lives at the highest address, - * with the hypervisor above that. - * - * Loadable kernel modules are placed immediately after the static - * supervisor code, with each being allocated a 256MB region of - * address space, so we don't have to worry about the range of "jal" - * and other branch instructions. - * - * For now we keep life simple and just allocate one pmd (4GB) for vmalloc. - * Similarly, for now we don't play any struct page mapping games. - */ - -#if MAX_PA_WIDTH + 2 > MAX_VA_WIDTH -# error Too much PA to map with the VA available! -#endif - -#define PAGE_OFFSET (-(_AC(1, UL) << (MAX_VA_WIDTH - 1))) -#define KERNEL_HIGH_VADDR _AC(0xfffffff800000000, UL) /* high 32GB */ -#define FIXADDR_BASE (KERNEL_HIGH_VADDR - 0x300000000) /* 4 GB */ -#define FIXADDR_TOP (KERNEL_HIGH_VADDR - 0x200000000) /* 4 GB */ -#define _VMALLOC_START FIXADDR_TOP -#define MEM_SV_START (KERNEL_HIGH_VADDR - 0x100000000) /* 256 MB */ -#define MEM_MODULE_START (MEM_SV_START + (256*1024*1024)) /* 256 MB */ -#define MEM_MODULE_END (MEM_MODULE_START + (256*1024*1024)) - -#else /* !__tilegx__ */ - -/* - * A PAGE_OFFSET of 0xC0000000 means that the kernel has - * a virtual address space of one gigabyte, which limits the - * amount of physical memory you can use to about 768MB. - * If you want more physical memory than this then see the CONFIG_HIGHMEM - * option in the kernel configuration. - * - * The top 16MB chunk in the table below is unavailable to Linux. Since - * the kernel interrupt vectors must live at ether 0xfe000000 or 0xfd000000 - * (depending on whether the kernel is at PL2 or Pl1), we map all of the - * bottom of RAM at this address with a huge page table entry to minimize - * its ITLB footprint (as well as at PAGE_OFFSET). The last architected - * requirement is that user interrupt vectors live at 0xfc000000, so we - * make that range of memory available to user processes. The remaining - * regions are sized as shown; the first four addresses use the PL 1 - * values, and after that, we show "typical" values, since the actual - * addresses depend on kernel #defines. - * - * MEM_HV_START 0xfe000000 - * MEM_SV_START (kernel code) 0xfd000000 - * MEM_USER_INTRPT (user vector) 0xfc000000 - * FIX_KMAP_xxx 0xfa000000 (via NR_CPUS * KM_TYPE_NR) - * PKMAP_BASE 0xf9000000 (via LAST_PKMAP) - * VMALLOC_START 0xf7000000 (via VMALLOC_RESERVE) - * mapped LOWMEM 0xc0000000 - */ - -#define MEM_USER_INTRPT _AC(0xfc000000, UL) -#define MEM_SV_START _AC(0xfd000000, UL) -#define MEM_HV_START _AC(0xfe000000, UL) - -#define INTRPT_SIZE 0x4000 - -/* Tolerate page size larger than the architecture interrupt region size. */ -#if PAGE_SIZE > INTRPT_SIZE -#undef INTRPT_SIZE -#define INTRPT_SIZE PAGE_SIZE -#endif - -#define KERNEL_HIGH_VADDR MEM_USER_INTRPT -#define FIXADDR_TOP (KERNEL_HIGH_VADDR - PAGE_SIZE) - -#define PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) - -/* On 32-bit architectures we mix kernel modules in with other vmaps. */ -#define MEM_MODULE_START VMALLOC_START -#define MEM_MODULE_END VMALLOC_END - -#endif /* __tilegx__ */ - -#if !defined(__ASSEMBLY__) && !defined(VDSO_BUILD) - -#ifdef CONFIG_HIGHMEM - -/* Map kernel virtual addresses to page frames, in HPAGE_SIZE chunks. */ -extern unsigned long pbase_map[]; -extern void *vbase_map[]; - -static inline unsigned long kaddr_to_pfn(const volatile void *_kaddr) -{ - unsigned long kaddr = (unsigned long)_kaddr; - return pbase_map[kaddr >> HPAGE_SHIFT] + - ((kaddr & (HPAGE_SIZE - 1)) >> PAGE_SHIFT); -} - -static inline void *pfn_to_kaddr(unsigned long pfn) -{ - return vbase_map[__pfn_to_highbits(pfn)] + (pfn << PAGE_SHIFT); -} - -static inline phys_addr_t virt_to_phys(const volatile void *kaddr) -{ - unsigned long pfn = kaddr_to_pfn(kaddr); - return ((phys_addr_t)pfn << PAGE_SHIFT) + - ((unsigned long)kaddr & (PAGE_SIZE-1)); -} - -static inline void *phys_to_virt(phys_addr_t paddr) -{ - return pfn_to_kaddr(paddr >> PAGE_SHIFT) + (paddr & (PAGE_SIZE-1)); -} - -/* With HIGHMEM, we pack PAGE_OFFSET through high_memory with all valid VAs. */ -static inline int virt_addr_valid(const volatile void *kaddr) -{ - extern void *high_memory; /* copied from */ - return ((unsigned long)kaddr >= PAGE_OFFSET && kaddr < high_memory); -} - -#else /* !CONFIG_HIGHMEM */ - -static inline unsigned long kaddr_to_pfn(const volatile void *kaddr) -{ - return ((unsigned long)kaddr - PAGE_OFFSET) >> PAGE_SHIFT; -} - -static inline void *pfn_to_kaddr(unsigned long pfn) -{ - return (void *)((pfn << PAGE_SHIFT) + PAGE_OFFSET); -} - -static inline phys_addr_t virt_to_phys(const volatile void *kaddr) -{ - return (phys_addr_t)((unsigned long)kaddr - PAGE_OFFSET); -} - -static inline void *phys_to_virt(phys_addr_t paddr) -{ - return (void *)((unsigned long)paddr + PAGE_OFFSET); -} - -/* Check that the given address is within some mapped range of PAs. */ -#define virt_addr_valid(kaddr) pfn_valid(kaddr_to_pfn(kaddr)) - -#endif /* !CONFIG_HIGHMEM */ - -/* All callers are not consistent in how they call these functions. */ -#define __pa(kaddr) virt_to_phys((void *)(unsigned long)(kaddr)) -#define __va(paddr) phys_to_virt((phys_addr_t)(paddr)) - -extern int devmem_is_allowed(unsigned long pagenr); - -#ifdef CONFIG_FLATMEM -static inline int pfn_valid(unsigned long pfn) -{ - return pfn < max_mapnr; -} -#endif - -/* Provide as macros since these require some other headers included. */ -#define page_to_pa(page) ((phys_addr_t)(page_to_pfn(page)) << PAGE_SHIFT) -#define virt_to_page(kaddr) pfn_to_page(kaddr_to_pfn((void *)(kaddr))) -#define page_to_virt(page) pfn_to_kaddr(page_to_pfn(page)) - -/* - * The kernel text is mapped at MEM_SV_START as read-only. To allow - * modifying kernel text, it is also mapped at PAGE_OFFSET as read-write. - * This macro converts a kernel address to its writable kernel text mapping, - * which is used to modify the text code on a running kernel by kgdb, - * ftrace, kprobe, jump label, etc. - */ -#define ktext_writable_addr(kaddr) \ - ((unsigned long)(kaddr) - MEM_SV_START + PAGE_OFFSET) - -struct mm_struct; -extern pte_t *virt_to_pte(struct mm_struct *mm, unsigned long addr); -extern pte_t *virt_to_kpte(unsigned long kaddr); - -#endif /* !__ASSEMBLY__ */ - -#define VM_DATA_DEFAULT_FLAGS \ - (VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) - -#include - -#endif /* _ASM_TILE_PAGE_H */ diff --git a/arch/tile/include/asm/pci.h b/arch/tile/include/asm/pci.h deleted file mode 100644 index fe3de505b024..000000000000 --- a/arch/tile/include/asm/pci.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_PCI_H -#define _ASM_TILE_PCI_H - -#include -#include -#include - -#ifndef __tilegx__ - -/* - * Structure of a PCI controller (host bridge) - */ -struct pci_controller { - int index; /* PCI domain number */ - struct pci_bus *root_bus; - - int last_busno; - - int hv_cfg_fd[2]; /* config{0,1} fds for this PCIe controller */ - int hv_mem_fd; /* fd to Hypervisor for MMIO operations */ - - struct pci_ops *ops; - - int irq_base; /* Base IRQ from the Hypervisor */ - int plx_gen1; /* flag for PLX Gen 1 configuration */ - - /* Address ranges that are routed to this controller/bridge. */ - struct resource mem_resources[3]; -}; - -/* - * This flag tells if the platform is TILEmpower that needs - * special configuration for the PLX switch chip. - */ -extern int tile_plx_gen1; - -static inline void pci_iounmap(struct pci_dev *dev, void __iomem *addr) {} - -#define TILE_NUM_PCIE 2 - -/* - * The hypervisor maps the entirety of CPA-space as bus addresses, so - * bus addresses are physical addresses. The networking and block - * device layers use this boolean for bounce buffer decisions. - */ -#define PCI_DMA_BUS_IS_PHYS 1 - -/* generic pci stuff */ -#include - -#else - -#include -#include - -/** - * We reserve the hugepage-size address range at the top of the 64-bit address - * space to serve as the PCI window, emulating the BAR0 space of an endpoint - * device. This window is used by the chip-to-chip applications running on - * the RC node. The reason for carving out this window is that Mem-Maps that - * back up this window will not overlap with those that map the real physical - * memory. - */ -#define PCIE_HOST_BAR0_SIZE HPAGE_SIZE -#define PCIE_HOST_BAR0_START HPAGE_MASK - -/** - * The first PAGE_SIZE of the above "BAR" window is mapped to the - * gxpci_host_regs structure. - */ -#define PCIE_HOST_REGS_SIZE PAGE_SIZE - -/* - * This is the PCI address where the Mem-Map interrupt regions start. - * We use the 2nd to the last huge page of the 64-bit address space. - * The last huge page is used for the rootcomplex "bar", for C2C purpose. - */ -#define MEM_MAP_INTR_REGIONS_BASE (HPAGE_MASK - HPAGE_SIZE) - -/* - * Each Mem-Map interrupt region occupies 4KB. - */ -#define MEM_MAP_INTR_REGION_SIZE (1 << TRIO_MAP_MEM_LIM__ADDR_SHIFT) - -/* - * Allocate the PCI BAR window right below 4GB. - */ -#define TILE_PCI_BAR_WINDOW_TOP (1ULL << 32) - -/* - * Allocate 1GB for the PCI BAR window. - */ -#define TILE_PCI_BAR_WINDOW_SIZE (1 << 30) - -/* - * This is the highest bus address targeting the host memory that - * can be generated by legacy PCI devices with 32-bit or less - * DMA capability, dictated by the BAR window size and location. - */ -#define TILE_PCI_MAX_DIRECT_DMA_ADDRESS \ - (TILE_PCI_BAR_WINDOW_TOP - TILE_PCI_BAR_WINDOW_SIZE - 1) - -/* - * We shift the PCI bus range for all the physical memory up by the whole PA - * range. The corresponding CPA of an incoming PCI request will be the PCI - * address minus TILE_PCI_MEM_MAP_BASE_OFFSET. This also implies - * that the 64-bit capable devices will be given DMA addresses as - * the CPA plus TILE_PCI_MEM_MAP_BASE_OFFSET. To support 32-bit - * devices, we create a separate map region that handles the low - * 4GB. - * - * This design lets us avoid the "PCI hole" problem where the host bridge - * won't pass DMA traffic with target addresses that happen to fall within the - * BAR space. This enables us to use all the physical memory for DMA, instead - * of wasting the same amount of physical memory as the BAR window size. - */ -#define TILE_PCI_MEM_MAP_BASE_OFFSET (1ULL << CHIP_PA_WIDTH()) - -/* - * Start of the PCI memory resource, which starts at the end of the - * maximum system physical RAM address. - */ -#define TILE_PCI_MEM_START (1ULL << CHIP_PA_WIDTH()) - -/* - * Structure of a PCI controller (host bridge) on Gx. - */ -struct pci_controller { - - /* Pointer back to the TRIO that this PCIe port is connected to. */ - gxio_trio_context_t *trio; - int mac; /* PCIe mac index on the TRIO shim */ - int trio_index; /* Index of TRIO shim that contains the MAC. */ - - int pio_mem_index; /* PIO region index for memory access */ - -#ifdef CONFIG_TILE_PCI_IO - int pio_io_index; /* PIO region index for I/O space access */ -#endif - - /* - * Mem-Map regions for all the memory controllers so that Linux can - * map all of its physical memory space to the PCI bus. - */ - int mem_maps[MAX_NUMNODES]; - - int index; /* PCI domain number */ - struct pci_bus *root_bus; - - /* PCI I/O space resource for this controller. */ - struct resource io_space; - char io_space_name[32]; - - /* PCI memory space resource for this controller. */ - struct resource mem_space; - char mem_space_name[32]; - - uint64_t mem_offset; /* cpu->bus memory mapping offset. */ - - int first_busno; - - struct pci_ops *ops; - - /* Table that maps the INTx numbers to Linux irq numbers. */ - int irq_intx_table[4]; -}; - -extern struct pci_controller pci_controllers[TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES]; -extern gxio_trio_context_t trio_contexts[TILEGX_NUM_TRIO]; -extern int num_trio_shims; - -extern void pci_iounmap(struct pci_dev *dev, void __iomem *); - -/* - * The PCI address space does not equal the physical memory address - * space (we have an IOMMU). The IDE and SCSI device layers use this - * boolean for bounce buffer decisions. - */ -#define PCI_DMA_BUS_IS_PHYS 0 - -#endif /* __tilegx__ */ - -int __init tile_pci_init(void); -int __init pcibios_init(void); - -void pcibios_fixup_bus(struct pci_bus *bus); - -#define pci_domain_nr(bus) (((struct pci_controller *)(bus)->sysdata)->index) - -/* - * This decides whether to display the domain number in /proc. - */ -static inline int pci_proc_domain(struct pci_bus *bus) -{ - return 1; -} - -/* - * pcibios_assign_all_busses() tells whether or not the bus numbers - * should be reassigned, in case the BIOS didn't do it correctly, or - * in case we don't have a BIOS and we want to let Linux do it. - */ -static inline int pcibios_assign_all_busses(void) -{ - return 1; -} - -#define PCIBIOS_MIN_MEM 0 -/* Minimum PCI I/O address, starting at the page boundary. */ -#define PCIBIOS_MIN_IO PAGE_SIZE - -/* Use any cpu for PCI. */ -#define cpumask_of_pcibus(bus) cpu_online_mask - -#endif /* _ASM_TILE_PCI_H */ diff --git a/arch/tile/include/asm/percpu.h b/arch/tile/include/asm/percpu.h deleted file mode 100644 index 4f7ae39fa202..000000000000 --- a/arch/tile/include/asm/percpu.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_PERCPU_H -#define _ASM_TILE_PERCPU_H - -register unsigned long my_cpu_offset_reg asm("tp"); - -#ifdef CONFIG_PREEMPT -/* - * For full preemption, we can't just use the register variable - * directly, since we need barrier() to hazard against it, causing the - * compiler to reload anything computed from a previous "tp" value. - * But we also don't want to use volatile asm, since we'd like the - * compiler to be able to cache the value across multiple percpu reads. - * So we use a fake stack read as a hazard against barrier(). - * The 'U' constraint is like 'm' but disallows postincrement. - */ -static inline unsigned long __my_cpu_offset(void) -{ - unsigned long tp; - register unsigned long *sp asm("sp"); - asm("move %0, tp" : "=r" (tp) : "U" (*sp)); - return tp; -} -#define __my_cpu_offset __my_cpu_offset() -#else -/* - * We don't need to hazard against barrier() since "tp" doesn't ever - * change with PREEMPT_NONE, and with PREEMPT_VOLUNTARY it only - * changes at function call points, at which we are already re-reading - * the value of "tp" due to "my_cpu_offset_reg" being a global variable. - */ -#define __my_cpu_offset my_cpu_offset_reg -#endif - -#define set_my_cpu_offset(tp) (my_cpu_offset_reg = (tp)) - -#include - -#endif /* _ASM_TILE_PERCPU_H */ diff --git a/arch/tile/include/asm/perf_event.h b/arch/tile/include/asm/perf_event.h deleted file mode 100644 index 59c5b164e5b6..000000000000 --- a/arch/tile/include/asm/perf_event.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2014 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_PERF_EVENT_H -#define _ASM_TILE_PERF_EVENT_H - -#include -DECLARE_PER_CPU(u64, perf_irqs); - -unsigned long handle_syscall_link_address(void); -#endif /* _ASM_TILE_PERF_EVENT_H */ diff --git a/arch/tile/include/asm/pgalloc.h b/arch/tile/include/asm/pgalloc.h deleted file mode 100644 index 1b902508b664..000000000000 --- a/arch/tile/include/asm/pgalloc.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_PGALLOC_H -#define _ASM_TILE_PGALLOC_H - -#include -#include -#include -#include -#include -#include - -/* Bits for the size of the second-level page table. */ -#define L2_KERNEL_PGTABLE_SHIFT _HV_LOG2_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT) - -/* How big is a kernel L2 page table? */ -#define L2_KERNEL_PGTABLE_SIZE (1UL << L2_KERNEL_PGTABLE_SHIFT) - -/* We currently allocate user L2 page tables by page (unlike kernel L2s). */ -#if L2_KERNEL_PGTABLE_SHIFT < PAGE_SHIFT -#define L2_USER_PGTABLE_SHIFT PAGE_SHIFT -#else -#define L2_USER_PGTABLE_SHIFT L2_KERNEL_PGTABLE_SHIFT -#endif - -/* How many pages do we need, as an "order", for a user L2 page table? */ -#define L2_USER_PGTABLE_ORDER (L2_USER_PGTABLE_SHIFT - PAGE_SHIFT) - -static inline void set_pmd(pmd_t *pmdp, pmd_t pmd) -{ -#ifdef CONFIG_64BIT - set_pte(pmdp, pmd); -#else - set_pte(&pmdp->pud.pgd, pmd.pud.pgd); -#endif -} - -static inline void pmd_populate_kernel(struct mm_struct *mm, - pmd_t *pmd, pte_t *ptep) -{ - set_pmd(pmd, ptfn_pmd(HV_CPA_TO_PTFN(__pa(ptep)), - __pgprot(_PAGE_PRESENT))); -} - -static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, - pgtable_t page) -{ - set_pmd(pmd, ptfn_pmd(HV_CPA_TO_PTFN(PFN_PHYS(page_to_pfn(page))), - __pgprot(_PAGE_PRESENT))); -} - -/* - * Allocate and free page tables. - */ - -extern pgd_t *pgd_alloc(struct mm_struct *mm); -extern void pgd_free(struct mm_struct *mm, pgd_t *pgd); - -extern pgtable_t pgtable_alloc_one(struct mm_struct *mm, unsigned long address, - int order); -extern void pgtable_free(struct mm_struct *mm, struct page *pte, int order); - -static inline pgtable_t pte_alloc_one(struct mm_struct *mm, - unsigned long address) -{ - return pgtable_alloc_one(mm, address, L2_USER_PGTABLE_ORDER); -} - -static inline void pte_free(struct mm_struct *mm, struct page *pte) -{ - pgtable_free(mm, pte, L2_USER_PGTABLE_ORDER); -} - -#define pmd_pgtable(pmd) pmd_page(pmd) - -static inline pte_t * -pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address) -{ - return pfn_to_kaddr(page_to_pfn(pte_alloc_one(mm, address))); -} - -static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte) -{ - BUG_ON((unsigned long)pte & (PAGE_SIZE-1)); - pte_free(mm, virt_to_page(pte)); -} - -extern void __pgtable_free_tlb(struct mmu_gather *tlb, struct page *pte, - unsigned long address, int order); -static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte, - unsigned long address) -{ - __pgtable_free_tlb(tlb, pte, address, L2_USER_PGTABLE_ORDER); -} - -#define check_pgt_cache() do { } while (0) - -/* - * Get the small-page pte_t lowmem entry for a given pfn. - * This may or may not be in use, depending on whether the initial - * huge-page entry for the page has already been shattered. - */ -pte_t *get_prealloc_pte(unsigned long pfn); - -/* During init, we can shatter kernel huge pages if needed. */ -void shatter_pmd(pmd_t *pmd); - -/* After init, a more complex technique is required. */ -void shatter_huge_page(unsigned long addr); - -#ifdef __tilegx__ - -#define pud_populate(mm, pud, pmd) \ - pmd_populate_kernel((mm), (pmd_t *)(pud), (pte_t *)(pmd)) - -/* Bits for the size of the L1 (intermediate) page table. */ -#define L1_KERNEL_PGTABLE_SHIFT _HV_LOG2_L1_SIZE(HPAGE_SHIFT) - -/* How big is a kernel L2 page table? */ -#define L1_KERNEL_PGTABLE_SIZE (1UL << L1_KERNEL_PGTABLE_SHIFT) - -/* We currently allocate L1 page tables by page. */ -#if L1_KERNEL_PGTABLE_SHIFT < PAGE_SHIFT -#define L1_USER_PGTABLE_SHIFT PAGE_SHIFT -#else -#define L1_USER_PGTABLE_SHIFT L1_KERNEL_PGTABLE_SHIFT -#endif - -/* How many pages do we need, as an "order", for an L1 page table? */ -#define L1_USER_PGTABLE_ORDER (L1_USER_PGTABLE_SHIFT - PAGE_SHIFT) - -static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address) -{ - struct page *p = pgtable_alloc_one(mm, address, L1_USER_PGTABLE_ORDER); - return (pmd_t *)page_to_virt(p); -} - -static inline void pmd_free(struct mm_struct *mm, pmd_t *pmdp) -{ - pgtable_free(mm, virt_to_page(pmdp), L1_USER_PGTABLE_ORDER); -} - -static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp, - unsigned long address) -{ - __pgtable_free_tlb(tlb, virt_to_page(pmdp), address, - L1_USER_PGTABLE_ORDER); -} - -#endif /* __tilegx__ */ - -#endif /* _ASM_TILE_PGALLOC_H */ diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h deleted file mode 100644 index adfa21b18488..000000000000 --- a/arch/tile/include/asm/pgtable.h +++ /dev/null @@ -1,518 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * This file contains the functions and defines necessary to modify and use - * the TILE page table tree. - */ - -#ifndef _ASM_TILE_PGTABLE_H -#define _ASM_TILE_PGTABLE_H - -#include - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct mm_struct; -struct vm_area_struct; - -/* - * ZERO_PAGE is a global shared page that is always zero: used - * for zero-mapped memory areas etc.. - */ -extern unsigned long empty_zero_page[PAGE_SIZE/sizeof(unsigned long)]; -#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) - -extern pgd_t swapper_pg_dir[]; -extern pgprot_t swapper_pgprot; -extern struct kmem_cache *pgd_cache; -extern spinlock_t pgd_lock; -extern struct list_head pgd_list; - -/* - * The very last slots in the pgd_t are for addresses unusable by Linux - * (pgd_addr_invalid() returns true). So we use them for the list structure. - * The x86 code we are modelled on uses the page->private/index fields - * (older 2.6 kernels) or the lru list (newer 2.6 kernels), but since - * our pgds are so much smaller than a page, it seems a waste to - * spend a whole page on each pgd. - */ -#define PGD_LIST_OFFSET \ - ((PTRS_PER_PGD * sizeof(pgd_t)) - sizeof(struct list_head)) -#define pgd_to_list(pgd) \ - ((struct list_head *)((char *)(pgd) + PGD_LIST_OFFSET)) -#define list_to_pgd(list) \ - ((pgd_t *)((char *)(list) - PGD_LIST_OFFSET)) - -extern void pgtable_cache_init(void); -extern void paging_init(void); -extern void set_page_homes(void); - -#define FIRST_USER_ADDRESS 0UL - -#define _PAGE_PRESENT HV_PTE_PRESENT -#define _PAGE_HUGE_PAGE HV_PTE_PAGE -#define _PAGE_SUPER_PAGE HV_PTE_SUPER -#define _PAGE_READABLE HV_PTE_READABLE -#define _PAGE_WRITABLE HV_PTE_WRITABLE -#define _PAGE_EXECUTABLE HV_PTE_EXECUTABLE -#define _PAGE_ACCESSED HV_PTE_ACCESSED -#define _PAGE_DIRTY HV_PTE_DIRTY -#define _PAGE_GLOBAL HV_PTE_GLOBAL -#define _PAGE_USER HV_PTE_USER - -/* - * All the "standard" bits. Cache-control bits are managed elsewhere. - * This is used to test for valid level-2 page table pointers by checking - * all the bits, and to mask away the cache control bits for mprotect. - */ -#define _PAGE_ALL (\ - _PAGE_PRESENT | \ - _PAGE_HUGE_PAGE | \ - _PAGE_SUPER_PAGE | \ - _PAGE_READABLE | \ - _PAGE_WRITABLE | \ - _PAGE_EXECUTABLE | \ - _PAGE_ACCESSED | \ - _PAGE_DIRTY | \ - _PAGE_GLOBAL | \ - _PAGE_USER \ -) - -#define PAGE_NONE \ - __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) -#define PAGE_SHARED \ - __pgprot(_PAGE_PRESENT | _PAGE_READABLE | _PAGE_WRITABLE | \ - _PAGE_USER | _PAGE_ACCESSED) - -#define PAGE_SHARED_EXEC \ - __pgprot(_PAGE_PRESENT | _PAGE_READABLE | _PAGE_WRITABLE | \ - _PAGE_EXECUTABLE | _PAGE_USER | _PAGE_ACCESSED) -#define PAGE_COPY_NOEXEC \ - __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_READABLE) -#define PAGE_COPY_EXEC \ - __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | \ - _PAGE_READABLE | _PAGE_EXECUTABLE) -#define PAGE_COPY \ - PAGE_COPY_NOEXEC -#define PAGE_READONLY \ - __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_READABLE) -#define PAGE_READONLY_EXEC \ - __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | \ - _PAGE_READABLE | _PAGE_EXECUTABLE) - -#define _PAGE_KERNEL_RO \ - (_PAGE_PRESENT | _PAGE_GLOBAL | _PAGE_READABLE | _PAGE_ACCESSED) -#define _PAGE_KERNEL \ - (_PAGE_KERNEL_RO | _PAGE_WRITABLE | _PAGE_DIRTY) -#define _PAGE_KERNEL_EXEC (_PAGE_KERNEL_RO | _PAGE_EXECUTABLE) - -#define PAGE_KERNEL __pgprot(_PAGE_KERNEL) -#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL_RO) -#define PAGE_KERNEL_EXEC __pgprot(_PAGE_KERNEL_EXEC) - -#define page_to_kpgprot(p) PAGE_KERNEL - -/* - * We could tighten these up, but for now writable or executable - * implies readable. - */ -#define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY /* this is write-only, which we won't support */ -#define __P011 PAGE_COPY -#define __P100 PAGE_READONLY_EXEC -#define __P101 PAGE_READONLY_EXEC -#define __P110 PAGE_COPY_EXEC -#define __P111 PAGE_COPY_EXEC - -#define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY_EXEC -#define __S101 PAGE_READONLY_EXEC -#define __S110 PAGE_SHARED_EXEC -#define __S111 PAGE_SHARED_EXEC - -/* - * All the normal _PAGE_ALL bits are ignored for PMDs, except PAGE_PRESENT - * and PAGE_HUGE_PAGE, which must be one and zero, respectively. - * We set the ignored bits to zero. - */ -#define _PAGE_TABLE _PAGE_PRESENT - -/* Inherit the caching flags from the old protection bits. */ -#define pgprot_modify(oldprot, newprot) \ - (pgprot_t) { ((oldprot).val & ~_PAGE_ALL) | (newprot).val } - -/* Just setting the PFN to zero suffices. */ -#define pte_pgprot(x) hv_pte_set_pa((x), 0) - -/* - * For PTEs and PDEs, we must clear the Present bit first when - * clearing a page table entry, so clear the bottom half first and - * enforce ordering with a barrier. - */ -static inline void __pte_clear(pte_t *ptep) -{ -#ifdef __tilegx__ - ptep->val = 0; -#else - u32 *tmp = (u32 *)ptep; - tmp[0] = 0; - barrier(); - tmp[1] = 0; -#endif -} -#define pte_clear(mm, addr, ptep) __pte_clear(ptep) - -/* - * The following only work if pte_present() is true. - * Undefined behaviour if not.. - */ -#define pte_present hv_pte_get_present -#define pte_mknotpresent hv_pte_clear_present -#define pte_user hv_pte_get_user -#define pte_read hv_pte_get_readable -#define pte_dirty hv_pte_get_dirty -#define pte_young hv_pte_get_accessed -#define pte_write hv_pte_get_writable -#define pte_exec hv_pte_get_executable -#define pte_huge hv_pte_get_page -#define pte_super hv_pte_get_super -#define pte_rdprotect hv_pte_clear_readable -#define pte_exprotect hv_pte_clear_executable -#define pte_mkclean hv_pte_clear_dirty -#define pte_mkold hv_pte_clear_accessed -#define pte_wrprotect hv_pte_clear_writable -#define pte_mksmall hv_pte_clear_page -#define pte_mkread hv_pte_set_readable -#define pte_mkexec hv_pte_set_executable -#define pte_mkdirty hv_pte_set_dirty -#define pte_mkyoung hv_pte_set_accessed -#define pte_mkwrite hv_pte_set_writable -#define pte_mkhuge hv_pte_set_page -#define pte_mksuper hv_pte_set_super - -#define pte_special(pte) 0 -#define pte_mkspecial(pte) (pte) - -/* - * Use some spare bits in the PTE for user-caching tags. - */ -#define pte_set_forcecache hv_pte_set_client0 -#define pte_get_forcecache hv_pte_get_client0 -#define pte_clear_forcecache hv_pte_clear_client0 -#define pte_set_anyhome hv_pte_set_client1 -#define pte_get_anyhome hv_pte_get_client1 -#define pte_clear_anyhome hv_pte_clear_client1 - -/* - * A migrating PTE has PAGE_PRESENT clear but all the other bits preserved. - */ -#define pte_migrating hv_pte_get_migrating -#define pte_mkmigrate(x) hv_pte_set_migrating(hv_pte_clear_present(x)) -#define pte_donemigrate(x) hv_pte_set_present(hv_pte_clear_migrating(x)) - -#define pte_ERROR(e) \ - pr_err("%s:%d: bad pte 0x%016llx\n", __FILE__, __LINE__, pte_val(e)) -#define pgd_ERROR(e) \ - pr_err("%s:%d: bad pgd 0x%016llx\n", __FILE__, __LINE__, pgd_val(e)) - -/* Return PA and protection info for a given kernel VA. */ -int va_to_cpa_and_pte(void *va, phys_addr_t *cpa, pte_t *pte); - -/* - * __set_pte() ensures we write the 64-bit PTE with 32-bit words in - * the right order on 32-bit platforms and also allows us to write - * hooks to check valid PTEs, etc., if we want. - */ -void __set_pte(pte_t *ptep, pte_t pte); - -/* - * set_pte() sets the given PTE and also sanity-checks the - * requested PTE against the page homecaching. Unspecified parts - * of the PTE are filled in when it is written to memory, i.e. all - * caching attributes if "!forcecache", or the home cpu if "anyhome". - */ -extern void set_pte(pte_t *ptep, pte_t pte); -#define set_pte_at(mm, addr, ptep, pteval) set_pte(ptep, pteval) -#define set_pte_atomic(pteptr, pteval) set_pte(pteptr, pteval) - -#define pte_page(x) pfn_to_page(pte_pfn(x)) - -static inline int pte_none(pte_t pte) -{ - return !pte.val; -} - -static inline unsigned long pte_pfn(pte_t pte) -{ - return PFN_DOWN(hv_pte_get_pa(pte)); -} - -/* Set or get the remote cache cpu in a pgprot with remote caching. */ -extern pgprot_t set_remote_cache_cpu(pgprot_t prot, int cpu); -extern int get_remote_cache_cpu(pgprot_t prot); - -static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot) -{ - return hv_pte_set_pa(prot, PFN_PHYS(pfn)); -} - -/* Support for priority mappings. */ -extern void start_mm_caching(struct mm_struct *mm); -extern void check_mm_caching(struct mm_struct *prev, struct mm_struct *next); - -/* - * Encode and de-code a swap entry (see ). - * We put the swap file type+offset in the 32 high bits; - * I believe we can just leave the low bits clear. - */ -#define __swp_type(swp) ((swp).val & 0x1f) -#define __swp_offset(swp) ((swp).val >> 5) -#define __swp_entry(type, off) ((swp_entry_t) { (type) | ((off) << 5) }) -#define __pte_to_swp_entry(pte) ((swp_entry_t) { (pte).val >> 32 }) -#define __swp_entry_to_pte(swp) ((pte_t) { (((long long) ((swp).val)) << 32) }) - -/* - * Conversion functions: convert a page and protection to a page entry, - * and a page entry and page directory to the page they refer to. - */ - -#define mk_pte(page, pgprot) pfn_pte(page_to_pfn(page), (pgprot)) - -/* - * If we are doing an mprotect(), just accept the new vma->vm_page_prot - * value and combine it with the PFN from the old PTE to get a new PTE. - */ -static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) -{ - return pfn_pte(pte_pfn(pte), newprot); -} - -/* - * The pgd page can be thought of an array like this: pgd_t[PTRS_PER_PGD] - * - * This macro returns the index of the entry in the pgd page which would - * control the given virtual address. - */ -#define pgd_index(address) (((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1)) - -/* - * pgd_offset() returns a (pgd_t *) - * pgd_index() is used get the offset into the pgd page's array of pgd_t's. - */ -#define pgd_offset(mm, address) ((mm)->pgd + pgd_index(address)) - -/* - * A shortcut which implies the use of the kernel's pgd, instead - * of a process's. - */ -#define pgd_offset_k(address) pgd_offset(&init_mm, address) - -#define pte_offset_map(dir, address) pte_offset_kernel(dir, address) -#define pte_unmap(pte) do { } while (0) - -/* Clear a non-executable kernel PTE and flush it from the TLB. */ -#define kpte_clear_flush(ptep, vaddr) \ -do { \ - pte_clear(&init_mm, (vaddr), (ptep)); \ - local_flush_tlb_page(FLUSH_NONEXEC, (vaddr), PAGE_SIZE); \ -} while (0) - -/* - * The kernel page tables contain what we need, and we flush when we - * change specific page table entries. - */ -#define update_mmu_cache(vma, address, pte) do { } while (0) - -#ifdef CONFIG_FLATMEM -#define kern_addr_valid(addr) (1) -#endif /* CONFIG_FLATMEM */ - -extern void vmalloc_sync_all(void); - -#endif /* !__ASSEMBLY__ */ - -#ifdef __tilegx__ -#include -#else -#include -#endif - -#ifndef __ASSEMBLY__ - -static inline int pmd_none(pmd_t pmd) -{ - /* - * Only check low word on 32-bit platforms, since it might be - * out of sync with upper half. - */ - return (unsigned long)pmd_val(pmd) == 0; -} - -static inline int pmd_present(pmd_t pmd) -{ - return pmd_val(pmd) & _PAGE_PRESENT; -} - -static inline int pmd_bad(pmd_t pmd) -{ - return ((pmd_val(pmd) & _PAGE_ALL) != _PAGE_TABLE); -} - -static inline unsigned long pages_to_mb(unsigned long npg) -{ - return npg >> (20 - PAGE_SHIFT); -} - -/* - * The pmd can be thought of an array like this: pmd_t[PTRS_PER_PMD] - * - * This function returns the index of the entry in the pmd which would - * control the given virtual address. - */ -static inline unsigned long pmd_index(unsigned long address) -{ - return (address >> PMD_SHIFT) & (PTRS_PER_PMD - 1); -} - -#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG -static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, - unsigned long address, - pmd_t *pmdp) -{ - return ptep_test_and_clear_young(vma, address, pmdp_ptep(pmdp)); -} - -#define __HAVE_ARCH_PMDP_SET_WRPROTECT -static inline void pmdp_set_wrprotect(struct mm_struct *mm, - unsigned long address, pmd_t *pmdp) -{ - ptep_set_wrprotect(mm, address, pmdp_ptep(pmdp)); -} - - -#define __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR -static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, - unsigned long address, - pmd_t *pmdp) -{ - return pte_pmd(ptep_get_and_clear(mm, address, pmdp_ptep(pmdp))); -} - -static inline void __set_pmd(pmd_t *pmdp, pmd_t pmdval) -{ - set_pte(pmdp_ptep(pmdp), pmd_pte(pmdval)); -} - -#define set_pmd_at(mm, addr, pmdp, pmdval) __set_pmd(pmdp, pmdval) - -/* Create a pmd from a PTFN. */ -static inline pmd_t ptfn_pmd(unsigned long ptfn, pgprot_t prot) -{ - return pte_pmd(hv_pte_set_ptfn(prot, ptfn)); -} - -/* Return the page-table frame number (ptfn) that a pmd_t points at. */ -#define pmd_ptfn(pmd) hv_pte_get_ptfn(pmd_pte(pmd)) - -/* - * A given kernel pmd_t maps to a specific virtual address (either a - * kernel huge page or a kernel pte_t table). Since kernel pte_t - * tables can be aligned at sub-page granularity, this function can - * return non-page-aligned pointers, despite its name. - */ -static inline unsigned long pmd_page_vaddr(pmd_t pmd) -{ - phys_addr_t pa = - (phys_addr_t)pmd_ptfn(pmd) << HV_LOG2_PAGE_TABLE_ALIGN; - return (unsigned long)__va(pa); -} - -/* - * A pmd_t points to the base of a huge page or to a pte_t array. - * If a pte_t array, since we can have multiple per page, we don't - * have a one-to-one mapping of pmd_t's to pages. However, this is - * OK for pte_lockptr(), since we just end up with potentially one - * lock being used for several pte_t arrays. - */ -#define pmd_page(pmd) pfn_to_page(PFN_DOWN(HV_PTFN_TO_CPA(pmd_ptfn(pmd)))) - -static inline void pmd_clear(pmd_t *pmdp) -{ - __pte_clear(pmdp_ptep(pmdp)); -} - -#define pmd_mknotpresent(pmd) pte_pmd(pte_mknotpresent(pmd_pte(pmd))) -#define pmd_young(pmd) pte_young(pmd_pte(pmd)) -#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd))) -#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd))) -#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd))) -#define pmd_write(pmd) pte_write(pmd_pte(pmd)) -#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd))) -#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd))) -#define pmd_huge_page(pmd) pte_huge(pmd_pte(pmd)) -#define pmd_mkhuge(pmd) pte_pmd(pte_mkhuge(pmd_pte(pmd))) - -#define pfn_pmd(pfn, pgprot) pte_pmd(pfn_pte((pfn), (pgprot))) -#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd)) -#define mk_pmd(page, pgprot) pfn_pmd(page_to_pfn(page), (pgprot)) - -static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) -{ - return pfn_pmd(pmd_pfn(pmd), newprot); -} - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -#define pmd_trans_huge pmd_huge_page -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ - -/* - * The pte page can be thought of an array like this: pte_t[PTRS_PER_PTE] - * - * This macro returns the index of the entry in the pte page which would - * control the given virtual address. - */ -static inline unsigned long pte_index(unsigned long address) -{ - return (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); -} - -static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address) -{ - return (pte_t *)pmd_page_vaddr(*pmd) + pte_index(address); -} - -#include - -/* Support /proc/NN/pgtable API. */ -struct seq_file; -int arch_proc_pgtable_show(struct seq_file *m, struct mm_struct *mm, - unsigned long vaddr, unsigned long pagesize, - pte_t *ptep, void **datap); - -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASM_TILE_PGTABLE_H */ diff --git a/arch/tile/include/asm/pgtable_32.h b/arch/tile/include/asm/pgtable_32.h deleted file mode 100644 index 5f8c615cb5e9..000000000000 --- a/arch/tile/include/asm/pgtable_32.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - */ - -#ifndef _ASM_TILE_PGTABLE_32_H -#define _ASM_TILE_PGTABLE_32_H - -/* - * The level-1 index is defined by the huge page size. A PGD is composed - * of PTRS_PER_PGD pgd_t's and is the top level of the page table. - */ -#define PGDIR_SHIFT HPAGE_SHIFT -#define PGDIR_SIZE HPAGE_SIZE -#define PGDIR_MASK (~(PGDIR_SIZE-1)) -#define PTRS_PER_PGD _HV_L1_ENTRIES(HPAGE_SHIFT) -#define PGD_INDEX(va) _HV_L1_INDEX(va, HPAGE_SHIFT) -#define SIZEOF_PGD _HV_L1_SIZE(HPAGE_SHIFT) - -/* - * The level-2 index is defined by the difference between the huge - * page size and the normal page size. A PTE is composed of - * PTRS_PER_PTE pte_t's and is the bottom level of the page table. - * Note that the hypervisor docs use PTE for what we call pte_t, so - * this nomenclature is somewhat confusing. - */ -#define PTRS_PER_PTE _HV_L2_ENTRIES(HPAGE_SHIFT, PAGE_SHIFT) -#define PTE_INDEX(va) _HV_L2_INDEX(va, HPAGE_SHIFT, PAGE_SHIFT) -#define SIZEOF_PTE _HV_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT) - -#ifndef __ASSEMBLY__ - -/* - * Right now we initialize only a single pte table. It can be extended - * easily, subsequent pte tables have to be allocated in one physical - * chunk of RAM. - * - * HOWEVER, if we are using an allocation scheme with slop after the - * end of the page table (e.g. where our L2 page tables are 2KB but - * our pages are 64KB and we are allocating via the page allocator) - * we can't extend it easily. - */ -#define LAST_PKMAP PTRS_PER_PTE - -#define PKMAP_BASE ((FIXADDR_BOOT_START - PAGE_SIZE*LAST_PKMAP) & PGDIR_MASK) - -#ifdef CONFIG_HIGHMEM -# define _VMALLOC_END (PKMAP_BASE & ~(HPAGE_SIZE-1)) -#else -# define _VMALLOC_END (FIXADDR_START & ~(HPAGE_SIZE-1)) -#endif - -/* - * Align the vmalloc area to an L2 page table, and leave a guard page - * at the beginning and end. The vmalloc code also puts in an internal - * guard page between each allocation. - */ -#define VMALLOC_END (_VMALLOC_END - PAGE_SIZE) -extern unsigned long VMALLOC_RESERVE /* = CONFIG_VMALLOC_RESERVE */; -#define _VMALLOC_START (_VMALLOC_END - VMALLOC_RESERVE) -#define VMALLOC_START (_VMALLOC_START + PAGE_SIZE) - -/* This is the maximum possible amount of lowmem. */ -#define MAXMEM (_VMALLOC_START - PAGE_OFFSET) - -/* We have no pmd or pud since we are strictly a two-level page table */ -#define __ARCH_USE_5LEVEL_HACK -#include - -static inline int pud_huge_page(pud_t pud) { return 0; } - -/* We don't define any pgds for these addresses. */ -static inline int pgd_addr_invalid(unsigned long addr) -{ - return addr >= MEM_HV_START; -} - -/* - * Provide versions of these routines that can be used safely when - * the hypervisor may be asynchronously modifying dirty/accessed bits. - * ptep_get_and_clear() matches the generic one but we provide it to - * be parallel with the 64-bit code. - */ -#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG -#define __HAVE_ARCH_PTEP_SET_WRPROTECT - -extern int ptep_test_and_clear_young(struct vm_area_struct *, - unsigned long addr, pte_t *); -extern void ptep_set_wrprotect(struct mm_struct *, - unsigned long addr, pte_t *); - -#define __HAVE_ARCH_PTEP_GET_AND_CLEAR -static inline pte_t ptep_get_and_clear(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) -{ - pte_t pte = *ptep; - pte_clear(_mm, addr, ptep); - return pte; -} - -/* - * pmds are wrappers around pgds, which are the same as ptes. - * It's often convenient to "cast" back and forth and use the pte methods, - * which are the methods supplied by the hypervisor. - */ -#define pmd_pte(pmd) ((pmd).pud.pgd) -#define pmdp_ptep(pmdp) (&(pmdp)->pud.pgd) -#define pte_pmd(pte) ((pmd_t){ { (pte) } }) - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_TILE_PGTABLE_32_H */ diff --git a/arch/tile/include/asm/pgtable_64.h b/arch/tile/include/asm/pgtable_64.h deleted file mode 100644 index 96fe58b45118..000000000000 --- a/arch/tile/include/asm/pgtable_64.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - */ - -#ifndef _ASM_TILE_PGTABLE_64_H -#define _ASM_TILE_PGTABLE_64_H - -/* The level-0 page table breaks the address space into 32-bit chunks. */ -#define PGDIR_SHIFT HV_LOG2_L1_SPAN -#define PGDIR_SIZE HV_L1_SPAN -#define PGDIR_MASK (~(PGDIR_SIZE-1)) -#define PTRS_PER_PGD HV_L0_ENTRIES -#define PGD_INDEX(va) HV_L0_INDEX(va) -#define SIZEOF_PGD HV_L0_SIZE - -/* - * The level-1 index is defined by the huge page size. A PMD is composed - * of PTRS_PER_PMD pgd_t's and is the middle level of the page table. - */ -#define PMD_SHIFT HPAGE_SHIFT -#define PMD_SIZE HPAGE_SIZE -#define PMD_MASK (~(PMD_SIZE-1)) -#define PTRS_PER_PMD _HV_L1_ENTRIES(HPAGE_SHIFT) -#define PMD_INDEX(va) _HV_L1_INDEX(va, HPAGE_SHIFT) -#define SIZEOF_PMD _HV_L1_SIZE(HPAGE_SHIFT) - -/* - * The level-2 index is defined by the difference between the huge - * page size and the normal page size. A PTE is composed of - * PTRS_PER_PTE pte_t's and is the bottom level of the page table. - * Note that the hypervisor docs use PTE for what we call pte_t, so - * this nomenclature is somewhat confusing. - */ -#define PTRS_PER_PTE _HV_L2_ENTRIES(HPAGE_SHIFT, PAGE_SHIFT) -#define PTE_INDEX(va) _HV_L2_INDEX(va, HPAGE_SHIFT, PAGE_SHIFT) -#define SIZEOF_PTE _HV_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT) - -/* - * Align the vmalloc area to an L2 page table. Omit guard pages at - * the beginning and end for simplicity (particularly in the per-cpu - * memory allocation code). The vmalloc code puts in an internal - * guard page between each allocation. - */ -#define _VMALLOC_END MEM_SV_START -#define VMALLOC_END _VMALLOC_END -#define VMALLOC_START _VMALLOC_START - -#ifndef __ASSEMBLY__ - -/* We have no pud since we are a three-level page table. */ -#define __ARCH_USE_5LEVEL_HACK -#include - -/* - * pmds are the same as pgds and ptes, so converting is a no-op. - */ -#define pmd_pte(pmd) (pmd) -#define pmdp_ptep(pmdp) (pmdp) -#define pte_pmd(pte) (pte) - -#define pud_pte(pud) ((pud).pgd) - -static inline int pud_none(pud_t pud) -{ - return pud_val(pud) == 0; -} - -static inline int pud_present(pud_t pud) -{ - return pud_val(pud) & _PAGE_PRESENT; -} - -static inline int pud_huge_page(pud_t pud) -{ - return pud_val(pud) & _PAGE_HUGE_PAGE; -} - -#define pmd_ERROR(e) \ - pr_err("%s:%d: bad pmd 0x%016llx\n", __FILE__, __LINE__, pmd_val(e)) - -static inline void pud_clear(pud_t *pudp) -{ - __pte_clear(&pudp->pgd); -} - -static inline int pud_bad(pud_t pud) -{ - return ((pud_val(pud) & _PAGE_ALL) != _PAGE_TABLE); -} - -/* Return the page-table frame number (ptfn) that a pud_t points at. */ -#define pud_ptfn(pud) hv_pte_get_ptfn((pud).pgd) - -/* Return the page frame number (pfn) that a pud_t points at. */ -#define pud_pfn(pud) pte_pfn(pud_pte(pud)) - -/* - * A given kernel pud_t maps to a kernel pmd_t table at a specific - * virtual address. Since kernel pmd_t tables can be aligned at - * sub-page granularity, this macro can return non-page-aligned - * pointers, despite its name. - */ -#define pud_page_vaddr(pud) \ - (__va((phys_addr_t)pud_ptfn(pud) << HV_LOG2_PAGE_TABLE_ALIGN)) - -/* - * A pud_t points to a pmd_t array. Since we can have multiple per - * page, we don't have a one-to-one mapping of pud_t's to pages. - */ -#define pud_page(pud) pfn_to_page(PFN_DOWN(HV_PTFN_TO_CPA(pud_ptfn(pud)))) - -static inline unsigned long pud_index(unsigned long address) -{ - return (address >> PUD_SHIFT) & (PTRS_PER_PUD - 1); -} - -#define pmd_offset(pud, address) \ - ((pmd_t *)pud_page_vaddr(*(pud)) + pmd_index(address)) - -/* Normalize an address to having the correct high bits set. */ -#define pgd_addr_normalize pgd_addr_normalize -static inline unsigned long pgd_addr_normalize(unsigned long addr) -{ - return ((long)addr << (CHIP_WORD_SIZE() - CHIP_VA_WIDTH())) >> - (CHIP_WORD_SIZE() - CHIP_VA_WIDTH()); -} - -/* We don't define any pgds for these addresses. */ -static inline int pgd_addr_invalid(unsigned long addr) -{ - return addr >= KERNEL_HIGH_VADDR || addr != pgd_addr_normalize(addr); -} - -/* - * Use atomic instructions to provide atomicity against the hypervisor. - */ -#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG -static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep) -{ - return (__insn_fetchand(&ptep->val, ~HV_PTE_ACCESSED) >> - HV_PTE_INDEX_ACCESSED) & 0x1; -} - -#define __HAVE_ARCH_PTEP_SET_WRPROTECT -static inline void ptep_set_wrprotect(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) -{ - __insn_fetchand(&ptep->val, ~HV_PTE_WRITABLE); -} - -#define __HAVE_ARCH_PTEP_GET_AND_CLEAR -static inline pte_t ptep_get_and_clear(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) -{ - return hv_pte(__insn_exch(&ptep->val, 0UL)); -} - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_TILE_PGTABLE_64_H */ diff --git a/arch/tile/include/asm/pmc.h b/arch/tile/include/asm/pmc.h deleted file mode 100644 index 7ae3956d9008..000000000000 --- a/arch/tile/include/asm/pmc.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2014 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_PMC_H -#define _ASM_TILE_PMC_H - -#include - -#define TILE_BASE_COUNTERS 2 - -/* Bitfields below are derived from SPR PERF_COUNT_CTL*/ -#ifndef __tilegx__ -/* PERF_COUNT_CTL on TILEPro */ -#define TILE_CTL_EXCL_USER (1 << 7) /* exclude user level */ -#define TILE_CTL_EXCL_KERNEL (1 << 8) /* exclude kernel level */ -#define TILE_CTL_EXCL_HV (1 << 9) /* exclude hypervisor level */ - -#define TILE_SEL_MASK 0x7f /* 7 bits for event SEL, - COUNT_0_SEL */ -#define TILE_PLM_MASK 0x780 /* 4 bits priv level msks, - COUNT_0_MASK*/ -#define TILE_EVENT_MASK (TILE_SEL_MASK | TILE_PLM_MASK) - -#else /* __tilegx__*/ -/* PERF_COUNT_CTL on TILEGx*/ -#define TILE_CTL_EXCL_USER (1 << 10) /* exclude user level */ -#define TILE_CTL_EXCL_KERNEL (1 << 11) /* exclude kernel level */ -#define TILE_CTL_EXCL_HV (1 << 12) /* exclude hypervisor level */ - -#define TILE_SEL_MASK 0x3f /* 6 bits for event SEL, - COUNT_0_SEL*/ -#define TILE_BOX_MASK 0x1c0 /* 3 bits box msks, - COUNT_0_BOX */ -#define TILE_PLM_MASK 0x3c00 /* 4 bits priv level msks, - COUNT_0_MASK */ -#define TILE_EVENT_MASK (TILE_SEL_MASK | TILE_BOX_MASK | TILE_PLM_MASK) -#endif /* __tilegx__*/ - -/* Takes register and fault number. Returns error to disable the interrupt. */ -typedef int (*perf_irq_t)(struct pt_regs *, int); - -int userspace_perf_handler(struct pt_regs *regs, int fault); - -perf_irq_t reserve_pmc_hardware(perf_irq_t new_perf_irq); -void release_pmc_hardware(void); - -unsigned long pmc_get_overflow(void); -void pmc_ack_overflow(unsigned long status); - -void unmask_pmc_interrupts(void); -void mask_pmc_interrupts(void); - -#endif /* _ASM_TILE_PMC_H */ diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h deleted file mode 100644 index f71e5206650b..000000000000 --- a/arch/tile/include/asm/processor.h +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_PROCESSOR_H -#define _ASM_TILE_PROCESSOR_H - -#include - -#ifndef __ASSEMBLY__ - -/* - * NOTE: we don't include or as one - * normally would, due to #include dependencies. - */ -#include -#include -#include - -#include - -struct task_struct; -struct thread_struct; - -typedef struct { - unsigned long seg; -} mm_segment_t; - -/* - * Default implementation of macro that returns current - * instruction pointer ("program counter"). - */ -void *current_text_addr(void); - -#if CHIP_HAS_TILE_DMA() -/* Capture the state of a suspended DMA. */ -struct tile_dma_state { - int enabled; - unsigned long src; - unsigned long dest; - unsigned long strides; - unsigned long chunk_size; - unsigned long src_chunk; - unsigned long dest_chunk; - unsigned long byte; - unsigned long status; -}; - -/* - * A mask of the DMA status register for selecting only the 'running' - * and 'done' bits. - */ -#define DMA_STATUS_MASK \ - (SPR_DMA_STATUS__RUNNING_MASK | SPR_DMA_STATUS__DONE_MASK) -#endif - -/* - * Track asynchronous TLB events (faults and access violations) - * that occur while we are in kernel mode from DMA or the SN processor. - */ -struct async_tlb { - short fault_num; /* original fault number; 0 if none */ - char is_fault; /* was it a fault (vs an access violation) */ - char is_write; /* for fault: was it caused by a write? */ - unsigned long address; /* what address faulted? */ -}; - -#ifdef CONFIG_HARDWALL -struct hardwall_info; -struct hardwall_task { - /* Which hardwall is this task tied to? (or NULL if none) */ - struct hardwall_info *info; - /* Chains this task into the list at info->task_head. */ - struct list_head list; -}; -#ifdef __tilepro__ -#define HARDWALL_TYPES 1 /* udn */ -#else -#define HARDWALL_TYPES 3 /* udn, idn, and ipi */ -#endif -#endif - -struct thread_struct { - /* kernel stack pointer */ - unsigned long ksp; - /* kernel PC */ - unsigned long pc; - /* starting user stack pointer (for page migration) */ - unsigned long usp0; - /* pid of process that created this one */ - pid_t creator_pid; -#if CHIP_HAS_TILE_DMA() - /* DMA info for suspended threads (byte == 0 means no DMA state) */ - struct tile_dma_state tile_dma_state; -#endif - /* User EX_CONTEXT registers */ - unsigned long ex_context[2]; - /* User SYSTEM_SAVE registers */ - unsigned long system_save[4]; - /* User interrupt mask */ - unsigned long long interrupt_mask; - /* User interrupt-control 0 state */ - unsigned long intctrl_0; - /* Any other miscellaneous processor state bits */ - unsigned long proc_status; -#if !CHIP_HAS_FIXED_INTVEC_BASE() - /* Interrupt base for PL0 interrupts */ - unsigned long interrupt_vector_base; -#endif - /* Tile cache retry fifo high-water mark */ - unsigned long tile_rtf_hwm; -#if CHIP_HAS_DSTREAM_PF() - /* Data stream prefetch control */ - unsigned long dstream_pf; -#endif -#ifdef CONFIG_HARDWALL - /* Hardwall information for various resources. */ - struct hardwall_task hardwall[HARDWALL_TYPES]; -#endif -#if CHIP_HAS_TILE_DMA() - /* Async DMA TLB fault information */ - struct async_tlb dma_async_tlb; -#endif -}; - -#endif /* !__ASSEMBLY__ */ - -/* - * Start with "sp" this many bytes below the top of the kernel stack. - * This allows us to be cache-aware when handling the initial save - * of the pt_regs value to the stack. - */ -#define STACK_TOP_DELTA 64 - -/* - * When entering the kernel via a fault, start with the top of the - * pt_regs structure this many bytes below the top of the page. - * This aligns the pt_regs structure optimally for cache-line access. - */ -#ifdef __tilegx__ -#define KSTK_PTREGS_GAP 48 -#else -#define KSTK_PTREGS_GAP 56 -#endif - -#ifndef __ASSEMBLY__ - -#ifdef __tilegx__ -#define TASK_SIZE_MAX (_AC(1, UL) << (MAX_VA_WIDTH - 1)) -#else -#define TASK_SIZE_MAX PAGE_OFFSET -#endif - -/* TASK_SIZE and related variables are always checked in "current" context. */ -#ifdef CONFIG_COMPAT -#define COMPAT_TASK_SIZE (1UL << 31) -#define TASK_SIZE ((current_thread_info()->status & TS_COMPAT) ?\ - COMPAT_TASK_SIZE : TASK_SIZE_MAX) -#else -#define TASK_SIZE TASK_SIZE_MAX -#endif - -#define VDSO_BASE ((unsigned long)current->active_mm->context.vdso_base) -#define VDSO_SYM(x) (VDSO_BASE + (unsigned long)(x)) - -#define STACK_TOP TASK_SIZE - -/* STACK_TOP_MAX is used temporarily in execve and should not check COMPAT. */ -#define STACK_TOP_MAX TASK_SIZE_MAX - -/* - * This decides where the kernel will search for a free chunk of vm - * space during mmap's, if it is using bottom-up mapping. - */ -#define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) - -#define HAVE_ARCH_PICK_MMAP_LAYOUT - -#define INIT_THREAD { \ - .ksp = (unsigned long)init_stack + THREAD_SIZE - STACK_TOP_DELTA, \ - .interrupt_mask = -1ULL \ -} - -/* Kernel stack top for the task that first boots on this cpu. */ -DECLARE_PER_CPU(unsigned long, boot_sp); - -/* PC to boot from on this cpu. */ -DECLARE_PER_CPU(unsigned long, boot_pc); - -/* Do necessary setup to start up a newly executed thread. */ -static inline void start_thread(struct pt_regs *regs, - unsigned long pc, unsigned long usp) -{ - regs->pc = pc; - regs->sp = usp; - single_step_execve(); -} - -/* Free all resources held by a thread. */ -static inline void release_thread(struct task_struct *dead_task) -{ - /* Nothing for now */ -} - -extern void prepare_exit_to_usermode(struct pt_regs *regs, u32 flags); - -unsigned long get_wchan(struct task_struct *p); - -/* Return initial ksp value for given task. */ -#define task_ksp0(task) \ - ((unsigned long)(task)->stack + THREAD_SIZE - STACK_TOP_DELTA) - -/* Return some info about the user process TASK. */ -#define task_pt_regs(task) \ - ((struct pt_regs *)(task_ksp0(task) - KSTK_PTREGS_GAP) - 1) -#define current_pt_regs() \ - ((struct pt_regs *)((stack_pointer | (THREAD_SIZE - 1)) - \ - STACK_TOP_DELTA - (KSTK_PTREGS_GAP - 1)) - 1) -#define task_sp(task) (task_pt_regs(task)->sp) -#define task_pc(task) (task_pt_regs(task)->pc) -/* Aliases for pc and sp (used in fs/proc/array.c) */ -#define KSTK_EIP(task) task_pc(task) -#define KSTK_ESP(task) task_sp(task) - -/* Fine-grained unaligned JIT support */ -#define GET_UNALIGN_CTL(tsk, adr) get_unalign_ctl((tsk), (adr)) -#define SET_UNALIGN_CTL(tsk, val) set_unalign_ctl((tsk), (val)) - -extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr); -extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val); - -/* Standard format for printing registers and other word-size data. */ -#ifdef __tilegx__ -# define REGFMT "0x%016lx" -#else -# define REGFMT "0x%08lx" -#endif - -/* - * Do some slow action (e.g. read a slow SPR). - * Note that this must also have compiler-barrier semantics since - * it may be used in a busy loop reading memory. - */ -static inline void cpu_relax(void) -{ - __insn_mfspr(SPR_PASS); - barrier(); -} - -/* Info on this processor (see fs/proc/cpuinfo.c) */ -struct seq_operations; -extern const struct seq_operations cpuinfo_op; - -/* Provide information about the chip model. */ -extern char chip_model[64]; - -/* Data on which physical memory controller corresponds to which NUMA node. */ -extern int node_controller[]; - -/* Does the heap allocator return hash-for-home pages by default? */ -extern int hash_default; - -/* Should kernel stack pages be hash-for-home? */ -extern int kstack_hash; - -/* Does MAP_ANONYMOUS return hash-for-home pages by default? */ -#define uheap_hash hash_default - - -/* Are we using huge pages in the TLB for kernel data? */ -extern int kdata_huge; - -/* Support standard Linux prefetching. */ -#define ARCH_HAS_PREFETCH -#define prefetch(x) __builtin_prefetch(x) -#define PREFETCH_STRIDE CHIP_L2_LINE_SIZE() - -/* Bring a value into the L1D, faulting the TLB if necessary. */ -#ifdef __tilegx__ -#define prefetch_L1(x) __insn_prefetch_l1_fault((void *)(x)) -#else -#define prefetch_L1(x) __insn_prefetch_L1((void *)(x)) -#endif - -#else /* __ASSEMBLY__ */ - -/* Do some slow action (e.g. read a slow SPR). */ -#define CPU_RELAX mfspr zero, SPR_PASS - -#endif /* !__ASSEMBLY__ */ - -/* Assembly code assumes that the PL is in the low bits. */ -#if SPR_EX_CONTEXT_1_1__PL_SHIFT != 0 -# error Fix assembly assumptions about PL -#endif - -/* We sometimes use these macros for EX_CONTEXT_0_1 as well. */ -#if SPR_EX_CONTEXT_1_1__PL_SHIFT != SPR_EX_CONTEXT_0_1__PL_SHIFT || \ - SPR_EX_CONTEXT_1_1__PL_RMASK != SPR_EX_CONTEXT_0_1__PL_RMASK || \ - SPR_EX_CONTEXT_1_1__ICS_SHIFT != SPR_EX_CONTEXT_0_1__ICS_SHIFT || \ - SPR_EX_CONTEXT_1_1__ICS_RMASK != SPR_EX_CONTEXT_0_1__ICS_RMASK -# error Fix assumptions that EX1 macros work for both PL0 and PL1 -#endif - -/* Allow pulling apart and recombining the PL and ICS bits in EX_CONTEXT. */ -#define EX1_PL(ex1) \ - (((ex1) >> SPR_EX_CONTEXT_1_1__PL_SHIFT) & SPR_EX_CONTEXT_1_1__PL_RMASK) -#define EX1_ICS(ex1) \ - (((ex1) >> SPR_EX_CONTEXT_1_1__ICS_SHIFT) & SPR_EX_CONTEXT_1_1__ICS_RMASK) -#define PL_ICS_EX1(pl, ics) \ - (((pl) << SPR_EX_CONTEXT_1_1__PL_SHIFT) | \ - ((ics) << SPR_EX_CONTEXT_1_1__ICS_SHIFT)) - -/* - * Provide symbolic constants for PLs. - */ -#define USER_PL 0 -#if CONFIG_KERNEL_PL == 2 -#define GUEST_PL 1 -#endif -#define KERNEL_PL CONFIG_KERNEL_PL - -/* SYSTEM_SAVE_K_0 holds the current cpu number ORed with ksp0. */ -#ifdef __tilegx__ -#define CPU_SHIFT 48 -#if CHIP_VA_WIDTH() > CPU_SHIFT -# error Too many VA bits! -#endif -#define MAX_CPU_ID ((1 << (64 - CPU_SHIFT)) - 1) -#define raw_smp_processor_id() \ - ((int)(__insn_mfspr(SPR_SYSTEM_SAVE_K_0) >> CPU_SHIFT)) -#define get_current_ksp0() \ - ((unsigned long)(((long)__insn_mfspr(SPR_SYSTEM_SAVE_K_0) << \ - (64 - CPU_SHIFT)) >> (64 - CPU_SHIFT))) -#define next_current_ksp0(task) ({ \ - unsigned long __ksp0 = task_ksp0(task) & ((1UL << CPU_SHIFT) - 1); \ - unsigned long __cpu = (long)raw_smp_processor_id() << CPU_SHIFT; \ - __ksp0 | __cpu; \ -}) -#else -#define LOG2_NR_CPU_IDS 6 -#define MAX_CPU_ID ((1 << LOG2_NR_CPU_IDS) - 1) -#define raw_smp_processor_id() \ - ((int)__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & MAX_CPU_ID) -#define get_current_ksp0() \ - (__insn_mfspr(SPR_SYSTEM_SAVE_K_0) & ~MAX_CPU_ID) -#define next_current_ksp0(task) ({ \ - unsigned long __ksp0 = task_ksp0(task); \ - int __cpu = raw_smp_processor_id(); \ - BUG_ON(__ksp0 & MAX_CPU_ID); \ - __ksp0 | __cpu; \ -}) -#endif -#if CONFIG_NR_CPUS > (MAX_CPU_ID + 1) -# error Too many cpus! -#endif - -#endif /* _ASM_TILE_PROCESSOR_H */ diff --git a/arch/tile/include/asm/ptrace.h b/arch/tile/include/asm/ptrace.h deleted file mode 100644 index b9620c077abc..000000000000 --- a/arch/tile/include/asm/ptrace.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ -#ifndef _ASM_TILE_PTRACE_H -#define _ASM_TILE_PTRACE_H - -#include - -#ifndef __ASSEMBLY__ -/* Benefit from consistent use of "long" on all chips. */ -typedef unsigned long pt_reg_t; -#endif - -#include - -#define PTRACE_O_MASK_TILE (PTRACE_O_TRACEMIGRATE) -#define PT_TRACE_MIGRATE PT_EVENT_FLAG(PTRACE_EVENT_MIGRATE) - -/* Flag bits in pt_regs.flags */ -#define PT_FLAGS_DISABLE_IRQ 1 /* on return to kernel, disable irqs */ -#define PT_FLAGS_CALLER_SAVES 2 /* caller-save registers are valid */ -#define PT_FLAGS_RESTORE_REGS 4 /* restore callee-save regs on return */ - -#ifndef __ASSEMBLY__ - -#define regs_return_value(regs) ((regs)->regs[0]) -#define instruction_pointer(regs) ((regs)->pc) -#define profile_pc(regs) instruction_pointer(regs) -#define user_stack_pointer(regs) ((regs)->sp) - -/* Does the process account for user or for system time? */ -#define user_mode(regs) (EX1_PL((regs)->ex1) < KERNEL_PL) - -/* Fill in a struct pt_regs with the current kernel registers. */ -struct pt_regs *get_pt_regs(struct pt_regs *); - -/* Trace the current syscall. */ -extern int do_syscall_trace_enter(struct pt_regs *regs); -extern void do_syscall_trace_exit(struct pt_regs *regs); - -#define arch_has_single_step() (1) - -/* - * A structure for all single-stepper state. - * - * Also update defines in assembler section if it changes - */ -struct single_step_state { - /* the page to which we will write hacked-up bundles */ - void __user *buffer; - - union { - int flags; - struct { - unsigned long is_enabled:1, update:1, update_reg:6; - }; - }; - - unsigned long orig_pc; /* the original PC */ - unsigned long next_pc; /* return PC if no branch (PC + 1) */ - unsigned long branch_next_pc; /* return PC if we did branch/jump */ - unsigned long update_value; /* value to restore to update_target */ -}; - -/* Single-step the instruction at regs->pc */ -extern void single_step_once(struct pt_regs *regs); - -/* Clean up after execve(). */ -extern void single_step_execve(void); - -struct task_struct; - -extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs); - -#ifdef __tilegx__ -/* We need this since sigval_t has a user pointer in it, for GETSIGINFO etc. */ -#define __ARCH_WANT_COMPAT_SYS_PTRACE -#endif - -#endif /* !__ASSEMBLY__ */ - -#define SINGLESTEP_STATE_MASK_IS_ENABLED 0x1 -#define SINGLESTEP_STATE_MASK_UPDATE 0x2 -#define SINGLESTEP_STATE_TARGET_LB 2 -#define SINGLESTEP_STATE_TARGET_UB 7 - -#endif /* _ASM_TILE_PTRACE_H */ diff --git a/arch/tile/include/asm/sections.h b/arch/tile/include/asm/sections.h deleted file mode 100644 index 50343bfe7936..000000000000 --- a/arch/tile/include/asm/sections.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_SECTIONS_H -#define _ASM_TILE_SECTIONS_H - -#define arch_is_kernel_data arch_is_kernel_data - -#include - -extern char vdso_start[], vdso_end[]; -#ifdef CONFIG_COMPAT -extern char vdso32_start[], vdso32_end[]; -#endif - -/* Not exactly sections, but PC comparison points in the code. */ -extern char __rt_sigreturn[], __rt_sigreturn_end[]; -#ifdef __tilegx__ -extern char __start_unalign_asm_code[], __end_unalign_asm_code[]; -#else -extern char sys_cmpxchg[], __sys_cmpxchg_end[]; -extern char __sys_cmpxchg_grab_lock[]; -extern char __start_atomic_asm_code[], __end_atomic_asm_code[]; -#endif - -/* Handle the discontiguity between _sdata and _text. */ -static inline int arch_is_kernel_data(unsigned long addr) -{ - return addr >= (unsigned long)_sdata && - addr < (unsigned long)_end; -} - -#endif /* _ASM_TILE_SECTIONS_H */ diff --git a/arch/tile/include/asm/setup.h b/arch/tile/include/asm/setup.h deleted file mode 100644 index 2a0347af0702..000000000000 --- a/arch/tile/include/asm/setup.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ -#ifndef _ASM_TILE_SETUP_H -#define _ASM_TILE_SETUP_H - - -#include -#include -#include - -/* - * Reserved space for vmalloc and iomap - defined in asm/page.h - */ -#define MAXMEM_PFN PFN_DOWN(MAXMEM) - -int tile_console_write(const char *buf, int count); - -#ifdef CONFIG_EARLY_PRINTK -void early_panic(const char *fmt, ...); -#else -#define early_panic panic -#endif - -/* Init-time routine to do tile-specific per-cpu setup. */ -void setup_cpu(int boot); - -/* User-level DMA management functions */ -void grant_dma_mpls(void); -void restrict_dma_mpls(void); - -#ifdef CONFIG_HARDWALL -/* User-level network management functions */ -void reset_network_state(void); -struct task_struct; -void hardwall_switch_tasks(struct task_struct *prev, struct task_struct *next); -void hardwall_deactivate_all(struct task_struct *task); -int hardwall_ipi_valid(int cpu); - -/* Hook hardwall code into changes in affinity. */ -#define arch_set_cpus_allowed(p, new_mask) do { \ - if (!cpumask_equal(&p->cpus_allowed, new_mask)) \ - hardwall_deactivate_all(p); \ -} while (0) -#endif - -#endif /* _ASM_TILE_SETUP_H */ diff --git a/arch/tile/include/asm/sigframe.h b/arch/tile/include/asm/sigframe.h deleted file mode 100644 index 994d3d30205f..000000000000 --- a/arch/tile/include/asm/sigframe.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_SIGFRAME_H -#define _ASM_TILE_SIGFRAME_H - -/* Indicate that syscall return should not examine r0 */ -#define INT_SWINT_1_SIGRETURN (~0) - -#ifndef __ASSEMBLY__ - -#include - -struct rt_sigframe { - unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; /* caller save area */ - struct siginfo info; - struct ucontext uc; -}; - -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASM_TILE_SIGFRAME_H */ diff --git a/arch/tile/include/asm/signal.h b/arch/tile/include/asm/signal.h deleted file mode 100644 index 10e183de96d3..000000000000 --- a/arch/tile/include/asm/signal.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ -#ifndef _ASM_TILE_SIGNAL_H -#define _ASM_TILE_SIGNAL_H - -#include - -#if !defined(__ASSEMBLY__) -struct pt_regs; -int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); -int setup_sigcontext(struct sigcontext __user *, struct pt_regs *); -void do_signal(struct pt_regs *regs); -void signal_fault(const char *type, struct pt_regs *, - void __user *frame, int sig); -void trace_unhandled_signal(const char *type, struct pt_regs *regs, - unsigned long address, int signo); -#endif -#endif /* _ASM_TILE_SIGNAL_H */ diff --git a/arch/tile/include/asm/smp.h b/arch/tile/include/asm/smp.h deleted file mode 100644 index 735e7f144733..000000000000 --- a/arch/tile/include/asm/smp.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_SMP_H -#define _ASM_TILE_SMP_H - -#ifdef CONFIG_SMP - -#include -#include -#include -#include - -/* Set up this tile to support receiving hypervisor messages */ -void init_messaging(void); - -/* Set up this tile to support receiving device interrupts and IPIs. */ -void init_per_tile_IRQs(void); - -/* Send a message to processors specified in mask */ -void send_IPI_many(const struct cpumask *mask, int tag); - -/* Send a message to all but the sending processor */ -void send_IPI_allbutself(int tag); - -/* Send a message to a specific processor */ -void send_IPI_single(int dest, int tag); - -/* Process an IPI message */ -void evaluate_message(int tag); - -/* Boot a secondary cpu */ -void online_secondary(void); - -/* Topology of the supervisor tile grid, and coordinates of boot processor */ -extern HV_Topology smp_topology; - -/* Accessors for grid size */ -#define smp_height (smp_topology.height) -#define smp_width (smp_topology.width) - -/* Convenience functions for converting cpu <-> coords. */ -static inline int cpu_x(int cpu) -{ - return cpu % smp_width; -} -static inline int cpu_y(int cpu) -{ - return cpu / smp_width; -} -static inline int xy_to_cpu(int x, int y) -{ - return y * smp_width + x; -} - -/* Hypervisor message tags sent via the tile send_IPI*() routines. */ -#define MSG_TAG_START_CPU 1 -#define MSG_TAG_STOP_CPU 2 -#define MSG_TAG_CALL_FUNCTION_MANY 3 -#define MSG_TAG_CALL_FUNCTION_SINGLE 4 -#define MSG_TAG_IRQ_WORK 5 - -/* Hook for the generic smp_call_function_many() routine. */ -static inline void arch_send_call_function_ipi_mask(struct cpumask *mask) -{ - send_IPI_many(mask, MSG_TAG_CALL_FUNCTION_MANY); -} - -/* Hook for the generic smp_call_function_single() routine. */ -static inline void arch_send_call_function_single_ipi(int cpu) -{ - send_IPI_single(cpu, MSG_TAG_CALL_FUNCTION_SINGLE); -} - -/* Print out the boot string describing which cpus were disabled. */ -void print_disabled_cpus(void); - -#else /* !CONFIG_SMP */ - -#define smp_master_cpu 0 -#define smp_height 1 -#define smp_width 1 -#define cpu_x(cpu) 0 -#define cpu_y(cpu) 0 -#define xy_to_cpu(x, y) 0 - -#endif /* !CONFIG_SMP */ - - -/* Which cpus may be used as the lotar in a page table entry. */ -extern struct cpumask cpu_lotar_map; -#define cpu_is_valid_lotar(cpu) cpumask_test_cpu((cpu), &cpu_lotar_map) - -/* Which processors are used for hash-for-home mapping */ -extern struct cpumask hash_for_home_map; - -/* Which cpus can have their cache flushed by hv_flush_remote(). */ -extern struct cpumask cpu_cacheable_map; -#define cpu_cacheable(cpu) cpumask_test_cpu((cpu), &cpu_cacheable_map) - -/* Convert an HV_LOTAR value into a cpu. */ -static inline int hv_lotar_to_cpu(HV_LOTAR lotar) -{ - return HV_LOTAR_X(lotar) + (HV_LOTAR_Y(lotar) * smp_width); -} - -/* - * Extension of functionality when you just want - * to express a mask or suppression or inclusion region without - * being too concerned about exactly which cpus are valid in that region. - */ -int bitmap_parselist_crop(const char *bp, unsigned long *maskp, int nmaskbits); - -#define cpulist_parse_crop(buf, dst) \ - __cpulist_parse_crop((buf), (dst), NR_CPUS) -static inline int __cpulist_parse_crop(const char *buf, struct cpumask *dstp, - int nbits) -{ - return bitmap_parselist_crop(buf, cpumask_bits(dstp), nbits); -} - -/* Initialize the IPI subsystem. */ -void ipi_init(void); - -/* Function for start-cpu message to cause us to jump to. */ -extern unsigned long start_cpu_function_addr; - -#endif /* _ASM_TILE_SMP_H */ diff --git a/arch/tile/include/asm/spinlock.h b/arch/tile/include/asm/spinlock.h deleted file mode 100644 index 1a8bd4740c28..000000000000 --- a/arch/tile/include/asm/spinlock.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_SPINLOCK_H -#define _ASM_TILE_SPINLOCK_H - -#ifdef __tilegx__ -#include -#else -#include -#endif - -#endif /* _ASM_TILE_SPINLOCK_H */ diff --git a/arch/tile/include/asm/spinlock_32.h b/arch/tile/include/asm/spinlock_32.h deleted file mode 100644 index fb5313d77315..000000000000 --- a/arch/tile/include/asm/spinlock_32.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * 32-bit SMP spinlocks. - */ - -#ifndef _ASM_TILE_SPINLOCK_32_H -#define _ASM_TILE_SPINLOCK_32_H - -#include -#include -#include - -/* - * We only use even ticket numbers so the '1' inserted by a tns is - * an unambiguous "ticket is busy" flag. - */ -#define TICKET_QUANTUM 2 - - -/* - * SMP ticket spinlocks, allowing only a single CPU anywhere - * - * (the type definitions are in asm/spinlock_types.h) - */ -static inline int arch_spin_is_locked(arch_spinlock_t *lock) -{ - /* - * Note that even if a new ticket is in the process of being - * acquired, so lock->next_ticket is 1, it's still reasonable - * to claim the lock is held, since it will be momentarily - * if not already. There's no need to wait for a "valid" - * lock->next_ticket to become available. - * Use READ_ONCE() to ensure that calling this in a loop is OK. - */ - int curr = READ_ONCE(lock->current_ticket); - int next = READ_ONCE(lock->next_ticket); - - return next != curr; -} - -void arch_spin_lock(arch_spinlock_t *lock); - -int arch_spin_trylock(arch_spinlock_t *lock); - -static inline void arch_spin_unlock(arch_spinlock_t *lock) -{ - /* For efficiency, overlap fetching the old ticket with the wmb(). */ - int old_ticket = lock->current_ticket; - wmb(); /* guarantee anything modified under the lock is visible */ - lock->current_ticket = old_ticket + TICKET_QUANTUM; -} - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * We use a "tns/store-back" technique on a single word to manage - * the lock state, looping around to retry if the tns returns 1. - */ - -/* Internal layout of the word; do not use. */ -#define _WR_NEXT_SHIFT 8 -#define _WR_CURR_SHIFT 16 -#define _WR_WIDTH 8 -#define _RD_COUNT_SHIFT 24 -#define _RD_COUNT_WIDTH 8 - -/** - * arch_read_lock() - acquire a read lock. - */ -void arch_read_lock(arch_rwlock_t *rwlock); - -/** - * arch_write_lock() - acquire a write lock. - */ -void arch_write_lock(arch_rwlock_t *rwlock); - -/** - * arch_read_trylock() - try to acquire a read lock. - */ -int arch_read_trylock(arch_rwlock_t *rwlock); - -/** - * arch_write_trylock() - try to acquire a write lock. - */ -int arch_write_trylock(arch_rwlock_t *rwlock); - -/** - * arch_read_unlock() - release a read lock. - */ -void arch_read_unlock(arch_rwlock_t *rwlock); - -/** - * arch_write_unlock() - release a write lock. - */ -void arch_write_unlock(arch_rwlock_t *rwlock); - -#endif /* _ASM_TILE_SPINLOCK_32_H */ diff --git a/arch/tile/include/asm/spinlock_64.h b/arch/tile/include/asm/spinlock_64.h deleted file mode 100644 index 5b616ef642a8..000000000000 --- a/arch/tile/include/asm/spinlock_64.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * 64-bit SMP ticket spinlocks, allowing only a single CPU anywhere - * (the type definitions are in asm/spinlock_types.h) - */ - -#ifndef _ASM_TILE_SPINLOCK_64_H -#define _ASM_TILE_SPINLOCK_64_H - -#include - -/* Shifts and masks for the various fields in "lock". */ -#define __ARCH_SPIN_CURRENT_SHIFT 17 -#define __ARCH_SPIN_NEXT_MASK 0x7fff -#define __ARCH_SPIN_NEXT_OVERFLOW 0x8000 - -/* - * Return the "current" portion of a ticket lock value, - * i.e. the number that currently owns the lock. - */ -static inline u32 arch_spin_current(u32 val) -{ - return val >> __ARCH_SPIN_CURRENT_SHIFT; -} - -/* - * Return the "next" portion of a ticket lock value, - * i.e. the number that the next task to try to acquire the lock will get. - */ -static inline u32 arch_spin_next(u32 val) -{ - return val & __ARCH_SPIN_NEXT_MASK; -} - -/* The lock is locked if a task would have to wait to get it. */ -static inline int arch_spin_is_locked(arch_spinlock_t *lock) -{ - /* Use READ_ONCE() to ensure that calling this in a loop is OK. */ - u32 val = READ_ONCE(lock->lock); - return arch_spin_current(val) != arch_spin_next(val); -} - -/* Bump the current ticket so the next task owns the lock. */ -static inline void arch_spin_unlock(arch_spinlock_t *lock) -{ - wmb(); /* guarantee anything modified under the lock is visible */ - __insn_fetchadd4(&lock->lock, 1U << __ARCH_SPIN_CURRENT_SHIFT); -} - -void arch_spin_lock_slow(arch_spinlock_t *lock, u32 val); - -/* Grab the "next" ticket number and bump it atomically. - * If the current ticket is not ours, go to the slow path. - * We also take the slow path if the "next" value overflows. - */ -static inline void arch_spin_lock(arch_spinlock_t *lock) -{ - u32 val = __insn_fetchadd4(&lock->lock, 1); - u32 ticket = val & (__ARCH_SPIN_NEXT_MASK | __ARCH_SPIN_NEXT_OVERFLOW); - if (unlikely(arch_spin_current(val) != ticket)) - arch_spin_lock_slow(lock, ticket); -} - -/* Try to get the lock, and return whether we succeeded. */ -int arch_spin_trylock(arch_spinlock_t *lock); - -/* - * Read-write spinlocks, allowing multiple readers - * but only one writer. - * - * We use fetchadd() for readers, and fetchor() with the sign bit - * for writers. - */ - -#define __WRITE_LOCK_BIT (1 << 31) - -static inline int arch_write_val_locked(int val) -{ - return val < 0; /* Optimize "val & __WRITE_LOCK_BIT". */ -} - -extern void __read_lock_failed(arch_rwlock_t *rw); - -static inline void arch_read_lock(arch_rwlock_t *rw) -{ - u32 val = __insn_fetchaddgez4(&rw->lock, 1); - if (unlikely(arch_write_val_locked(val))) - __read_lock_failed(rw); -} - -extern void __write_lock_failed(arch_rwlock_t *rw, u32 val); - -static inline void arch_write_lock(arch_rwlock_t *rw) -{ - u32 val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT); - if (unlikely(val != 0)) - __write_lock_failed(rw, val); -} - -static inline void arch_read_unlock(arch_rwlock_t *rw) -{ - __insn_mf(); - __insn_fetchadd4(&rw->lock, -1); -} - -static inline void arch_write_unlock(arch_rwlock_t *rw) -{ - __insn_mf(); - __insn_exch4(&rw->lock, 0); /* Avoid waiting in the write buffer. */ -} - -static inline int arch_read_trylock(arch_rwlock_t *rw) -{ - return !arch_write_val_locked(__insn_fetchaddgez4(&rw->lock, 1)); -} - -static inline int arch_write_trylock(arch_rwlock_t *rw) -{ - u32 val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT); - if (likely(val == 0)) - return 1; - if (!arch_write_val_locked(val)) - __insn_fetchand4(&rw->lock, ~__WRITE_LOCK_BIT); - return 0; -} - -#endif /* _ASM_TILE_SPINLOCK_64_H */ diff --git a/arch/tile/include/asm/spinlock_types.h b/arch/tile/include/asm/spinlock_types.h deleted file mode 100644 index a71f59b49c50..000000000000 --- a/arch/tile/include/asm/spinlock_types.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_SPINLOCK_TYPES_H -#define _ASM_TILE_SPINLOCK_TYPES_H - -#ifndef __LINUX_SPINLOCK_TYPES_H -# error "please don't include this file directly" -#endif - -#ifdef __tilegx__ - -/* Low 15 bits are "next"; high 15 bits are "current". */ -typedef struct arch_spinlock { - unsigned int lock; -} arch_spinlock_t; - -#define __ARCH_SPIN_LOCK_UNLOCKED { 0 } - -/* High bit is "writer owns"; low 31 bits are a count of readers. */ -typedef struct arch_rwlock { - unsigned int lock; -} arch_rwlock_t; - -#define __ARCH_RW_LOCK_UNLOCKED { 0 } - -#else - -typedef struct arch_spinlock { - /* Next ticket number to hand out. */ - int next_ticket; - /* The ticket number that currently owns this lock. */ - int current_ticket; -} arch_spinlock_t; - -#define __ARCH_SPIN_LOCK_UNLOCKED { 0, 0 } - -/* - * Byte 0 for tns (only the low bit is used), byte 1 for ticket-lock "next", - * byte 2 for ticket-lock "current", byte 3 for reader count. - */ -typedef struct arch_rwlock { - unsigned int lock; -} arch_rwlock_t; - -#define __ARCH_RW_LOCK_UNLOCKED { 0 } - -#endif -#endif /* _ASM_TILE_SPINLOCK_TYPES_H */ diff --git a/arch/tile/include/asm/stack.h b/arch/tile/include/asm/stack.h deleted file mode 100644 index 3573325e340b..000000000000 --- a/arch/tile/include/asm/stack.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_STACK_H -#define _ASM_TILE_STACK_H - -#include -#include -#include - -#include -#include -#include - -/* Everything we need to keep track of a backtrace iteration */ -struct KBacktraceIterator { - BacktraceIterator it; - struct task_struct *task; /* task we are backtracing */ - int end; /* iteration complete. */ - int new_context; /* new context is starting */ - int profile; /* profiling, so stop on async intrpt */ - int verbose; /* printk extra info (don't want to - * do this for profiling) */ - int is_current; /* backtracing current task */ -}; - -/* Iteration methods for kernel backtraces */ - -/* - * Initialize a KBacktraceIterator from a task_struct, and optionally from - * a set of registers. If the registers are omitted, the process is - * assumed to be descheduled, and registers are read from the process's - * thread_struct and stack. "verbose" means to printk some additional - * information about fault handlers as we pass them on the stack. - */ -extern void KBacktraceIterator_init(struct KBacktraceIterator *kbt, - struct task_struct *, struct pt_regs *); - -/* Initialize iterator based on current stack. */ -extern void KBacktraceIterator_init_current(struct KBacktraceIterator *kbt); - -/* Helper method for above. */ -extern void _KBacktraceIterator_init_current(struct KBacktraceIterator *kbt, - ulong pc, ulong lr, ulong sp, ulong r52); - -/* No more frames? */ -extern int KBacktraceIterator_end(struct KBacktraceIterator *kbt); - -/* Advance to the next frame. */ -extern void KBacktraceIterator_next(struct KBacktraceIterator *kbt); - -/* Dump just the contents of the pt_regs structure. */ -extern void tile_show_regs(struct pt_regs *); - -/* - * Dump stack given complete register info. Use only from the - * architecture-specific code; show_stack() - * and dump_stack() are architecture-independent entry points. - */ -extern void tile_show_stack(struct KBacktraceIterator *); - -#endif /* _ASM_TILE_STACK_H */ diff --git a/arch/tile/include/asm/string.h b/arch/tile/include/asm/string.h deleted file mode 100644 index 92b271bd9ebd..000000000000 --- a/arch/tile/include/asm/string.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_STRING_H -#define _ASM_TILE_STRING_H - -#define __HAVE_ARCH_MEMCHR -#define __HAVE_ARCH_MEMSET -#define __HAVE_ARCH_MEMCPY -#define __HAVE_ARCH_MEMMOVE -#define __HAVE_ARCH_STRCHR -#define __HAVE_ARCH_STRLEN -#define __HAVE_ARCH_STRNLEN - -extern __kernel_size_t strlen(const char *); -extern __kernel_size_t strnlen(const char *, __kernel_size_t); -extern char *strchr(const char *s, int c); -extern void *memchr(const void *s, int c, size_t n); -extern void *memset(void *, int, __kernel_size_t); -extern void *memcpy(void *, const void *, __kernel_size_t); -extern void *memmove(void *, const void *, __kernel_size_t); - -#endif /* _ASM_TILE_STRING_H */ diff --git a/arch/tile/include/asm/switch_to.h b/arch/tile/include/asm/switch_to.h deleted file mode 100644 index 34ee72705521..000000000000 --- a/arch/tile/include/asm/switch_to.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_SWITCH_TO_H -#define _ASM_TILE_SWITCH_TO_H - -#include - -/* - * switch_to(n) should switch tasks to task nr n, first - * checking that n isn't the current task, in which case it does nothing. - * The number of callee-saved registers saved on the kernel stack - * is defined here for use in copy_thread() and must agree with __switch_to(). - */ -#define CALLEE_SAVED_FIRST_REG 30 -#define CALLEE_SAVED_REGS_COUNT 24 /* r30 to r52, plus an empty to align */ - -#ifndef __ASSEMBLY__ - -struct task_struct; - -/* - * Pause the DMA engine and static network before task switching. - */ -#define prepare_arch_switch(next) _prepare_arch_switch(next) -void _prepare_arch_switch(struct task_struct *next); - -struct task_struct; -#define switch_to(prev, next, last) ((last) = _switch_to((prev), (next))) -extern struct task_struct *_switch_to(struct task_struct *prev, - struct task_struct *next); - -/* Helper function for _switch_to(). */ -extern struct task_struct *__switch_to(struct task_struct *prev, - struct task_struct *next, - unsigned long new_system_save_k_0); - -/* Address that switched-away from tasks are at. */ -extern unsigned long get_switch_to_pc(void); - -/* - * Kernel threads can check to see if they need to migrate their - * stack whenever they return from a context switch; for user - * threads, we defer until they are returning to user-space. - * We defer homecache migration until the runqueue lock is released. - */ -#define finish_arch_post_lock_switch() do { \ - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_SWITCH | \ - (current->pid << _SIM_CONTROL_OPERATOR_BITS)); \ - if (current->mm == NULL && !kstack_hash && \ - current_thread_info()->homecache_cpu != raw_smp_processor_id()) \ - homecache_migrate_kthread(); \ -} while (0) - -/* Support function for forking a new task. */ -void ret_from_fork(void); - -/* Support function for forking a new kernel thread. */ -void ret_from_kernel_thread(void *fn, void *arg); - -/* Called from ret_from_xxx() when a new process starts up. */ -struct task_struct *sim_notify_fork(struct task_struct *prev); - -#endif /* !__ASSEMBLY__ */ - -#endif /* _ASM_TILE_SWITCH_TO_H */ diff --git a/arch/tile/include/asm/syscall.h b/arch/tile/include/asm/syscall.h deleted file mode 100644 index 373d73064ea1..000000000000 --- a/arch/tile/include/asm/syscall.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * See asm-generic/syscall.h for descriptions of what we must do here. - */ - -#ifndef _ASM_TILE_SYSCALL_H -#define _ASM_TILE_SYSCALL_H - -#include -#include -#include -#include -#include - -/* The array of function pointers for syscalls. */ -extern void *sys_call_table[]; -#ifdef CONFIG_COMPAT -extern void *compat_sys_call_table[]; -#endif - -/* - * Only the low 32 bits of orig_r0 are meaningful, so we return int. - * This importantly ignores the high bits on 64-bit, so comparisons - * sign-extend the low 32 bits. - */ -static inline int syscall_get_nr(struct task_struct *t, struct pt_regs *regs) -{ - return regs->regs[TREG_SYSCALL_NR]; -} - -static inline void syscall_rollback(struct task_struct *task, - struct pt_regs *regs) -{ - regs->regs[0] = regs->orig_r0; -} - -static inline long syscall_get_error(struct task_struct *task, - struct pt_regs *regs) -{ - unsigned long error = regs->regs[0]; - return IS_ERR_VALUE(error) ? error : 0; -} - -static inline long syscall_get_return_value(struct task_struct *task, - struct pt_regs *regs) -{ - return regs->regs[0]; -} - -static inline void syscall_set_return_value(struct task_struct *task, - struct pt_regs *regs, - int error, long val) -{ - if (error) { - /* R0 is the passed-in negative error, R1 is positive. */ - regs->regs[0] = error; - regs->regs[1] = -error; - } else { - /* R1 set to zero to indicate no error. */ - regs->regs[0] = val; - regs->regs[1] = 0; - } -} - -static inline void syscall_get_arguments(struct task_struct *task, - struct pt_regs *regs, - unsigned int i, unsigned int n, - unsigned long *args) -{ - BUG_ON(i + n > 6); - memcpy(args, ®s[i], n * sizeof(args[0])); -} - -static inline void syscall_set_arguments(struct task_struct *task, - struct pt_regs *regs, - unsigned int i, unsigned int n, - const unsigned long *args) -{ - BUG_ON(i + n > 6); - memcpy(®s[i], args, n * sizeof(args[0])); -} - -/* - * We don't care about endianness (__AUDIT_ARCH_LE bit) here because - * tile has the same system calls both on little- and big- endian. - */ -static inline int syscall_get_arch(void) -{ - if (is_compat_task()) - return AUDIT_ARCH_TILEGX32; - -#ifdef CONFIG_TILEGX - return AUDIT_ARCH_TILEGX; -#else - return AUDIT_ARCH_TILEPRO; -#endif -} - -#endif /* _ASM_TILE_SYSCALL_H */ diff --git a/arch/tile/include/asm/syscalls.h b/arch/tile/include/asm/syscalls.h deleted file mode 100644 index 07b298450ef2..000000000000 --- a/arch/tile/include/asm/syscalls.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * syscalls.h - Linux syscall interfaces (arch-specific) - * - * Copyright (c) 2008 Jaswinder Singh Rajput - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_SYSCALLS_H -#define _ASM_TILE_SYSCALLS_H - -#include -#include -#include -#include -#include - -/* - * Note that by convention, any syscall which requires the current - * register set takes an additional "struct pt_regs *" pointer; a - * _sys_xxx() trampoline in intvec*.S just sets up the pointer and - * jumps to sys_xxx(). - */ - -/* kernel/sys.c */ -ssize_t sys32_readahead(int fd, u32 offset_lo, u32 offset_hi, u32 count); -long sys32_fadvise64(int fd, u32 offset_lo, u32 offset_hi, - u32 len, int advice); -int sys32_fadvise64_64(int fd, u32 offset_lo, u32 offset_hi, - u32 len_lo, u32 len_hi, int advice); -long sys_cacheflush(unsigned long addr, unsigned long len, - unsigned long flags); -#ifndef __tilegx__ /* No mmap() in the 32-bit kernel. */ -#define sys_mmap sys_mmap -#endif - -#ifndef __tilegx__ -/* mm/fault.c */ -long sys_cmpxchg_badaddr(unsigned long address); -#endif - -#ifdef CONFIG_COMPAT -/* These four are not defined for 64-bit, but serve as "compat" syscalls. */ -long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg); -long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf); -long sys_truncate64(const char __user *path, loff_t length); -long sys_ftruncate64(unsigned int fd, loff_t length); -#endif - -/* Provide versions of standard syscalls that use current_pt_regs(). */ -long sys_rt_sigreturn(void); -#define sys_rt_sigreturn sys_rt_sigreturn - -/* These are the intvec*.S trampolines. */ -long _sys_rt_sigreturn(void); -long _sys_clone(unsigned long clone_flags, unsigned long newsp, - void __user *parent_tid, void __user *child_tid); - -#include - -#endif /* _ASM_TILE_SYSCALLS_H */ diff --git a/arch/tile/include/asm/thread_info.h b/arch/tile/include/asm/thread_info.h deleted file mode 100644 index 2adcacd85749..000000000000 --- a/arch/tile/include/asm/thread_info.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (C) 2002 David Howells (dhowells@redhat.com) - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_THREAD_INFO_H -#define _ASM_TILE_THREAD_INFO_H - -#include -#include -#ifndef __ASSEMBLY__ - -/* - * Low level task data that assembly code needs immediate access to. - * The structure is placed at the bottom of the supervisor stack. - */ -struct thread_info { - struct task_struct *task; /* main task structure */ - unsigned long flags; /* low level flags */ - unsigned long status; /* thread-synchronous flags */ - __u32 homecache_cpu; /* CPU we are homecached on */ - __u32 cpu; /* current CPU */ - int preempt_count; /* 0 => preemptable, - <0 => BUG */ - - mm_segment_t addr_limit; /* thread address space - (KERNEL_DS or USER_DS) */ - struct single_step_state *step_state; /* single step state - (if non-zero) */ - int align_ctl; /* controls unaligned access */ -#ifdef __tilegx__ - unsigned long unalign_jit_tmp[4]; /* temp r0..r3 storage */ - void __user *unalign_jit_base; /* unalign fixup JIT base */ -#endif - bool in_backtrace; /* currently doing backtrace? */ -}; - -/* - * macros/functions for gaining access to the thread information structure. - */ -#define INIT_THREAD_INFO(tsk) \ -{ \ - .task = &tsk, \ - .flags = 0, \ - .cpu = 0, \ - .preempt_count = INIT_PREEMPT_COUNT, \ - .addr_limit = KERNEL_DS, \ - .step_state = NULL, \ - .align_ctl = 0, \ -} - -#endif /* !__ASSEMBLY__ */ - -#if PAGE_SIZE < 8192 -#define THREAD_SIZE_ORDER (13 - PAGE_SHIFT) -#else -#define THREAD_SIZE_ORDER (0) -#endif -#define THREAD_SIZE_PAGES (1 << THREAD_SIZE_ORDER) - -#define THREAD_SIZE (PAGE_SIZE << THREAD_SIZE_ORDER) -#define LOG2_THREAD_SIZE (PAGE_SHIFT + THREAD_SIZE_ORDER) - -#define STACK_WARN (THREAD_SIZE/8) - -#ifndef __ASSEMBLY__ - -void arch_release_thread_stack(unsigned long *stack); - -/* How to get the thread information struct from C. */ -register unsigned long stack_pointer __asm__("sp"); - -#define current_thread_info() \ - ((struct thread_info *)(stack_pointer & -THREAD_SIZE)) - -/* Sit on a nap instruction until interrupted. */ -extern void smp_nap(void); - -/* Enable interrupts racelessly and nap forever: helper for arch_cpu_idle(). */ -extern void _cpu_idle(void); - -#else /* __ASSEMBLY__ */ - -/* - * How to get the thread information struct from assembly. - * Note that we use different macros since different architectures - * have different semantics in their "mm" instruction and we would - * like to guarantee that the macro expands to exactly one instruction. - */ -#ifdef __tilegx__ -#define EXTRACT_THREAD_INFO(reg) mm reg, zero, LOG2_THREAD_SIZE, 63 -#else -#define GET_THREAD_INFO(reg) mm reg, sp, zero, LOG2_THREAD_SIZE, 31 -#endif - -#endif /* !__ASSEMBLY__ */ - -/* - * Thread information flags that various assembly files may need to access. - * Keep flags accessed frequently in low bits, particular since it makes - * it easier to build constants in assembly. - */ -#define TIF_SIGPENDING 0 /* signal pending */ -#define TIF_NEED_RESCHED 1 /* rescheduling necessary */ -#define TIF_SINGLESTEP 2 /* restore singlestep on return to - user mode */ -#define TIF_ASYNC_TLB 3 /* got an async TLB fault in kernel */ -#define TIF_SYSCALL_TRACE 4 /* syscall trace active */ -#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ -#define TIF_SECCOMP 6 /* secure computing */ -#define TIF_MEMDIE 7 /* OOM killer at work */ -#define TIF_NOTIFY_RESUME 8 /* callback before returning to user */ -#define TIF_SYSCALL_TRACEPOINT 9 /* syscall tracepoint instrumentation */ -#define TIF_POLLING_NRFLAG 10 /* idle is polling for TIF_NEED_RESCHED */ -#define TIF_NOHZ 11 /* in adaptive nohz mode */ - -#define _TIF_SIGPENDING (1< -#else -#include -#endif diff --git a/arch/tile/include/asm/tile-desc_32.h b/arch/tile/include/asm/tile-desc_32.h deleted file mode 100644 index f09c5c43b0b2..000000000000 --- a/arch/tile/include/asm/tile-desc_32.h +++ /dev/null @@ -1,553 +0,0 @@ -/* TILEPro opcode information. - * - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * - * - * - * - */ - -#ifndef opcode_tilepro_h -#define opcode_tilepro_h - -#include - - -enum -{ - TILEPRO_MAX_OPERANDS = 5 /* mm */ -}; - -typedef enum -{ - TILEPRO_OPC_BPT, - TILEPRO_OPC_INFO, - TILEPRO_OPC_INFOL, - TILEPRO_OPC_J, - TILEPRO_OPC_JAL, - TILEPRO_OPC_MOVE, - TILEPRO_OPC_MOVE_SN, - TILEPRO_OPC_MOVEI, - TILEPRO_OPC_MOVEI_SN, - TILEPRO_OPC_MOVELI, - TILEPRO_OPC_MOVELI_SN, - TILEPRO_OPC_MOVELIS, - TILEPRO_OPC_PREFETCH, - TILEPRO_OPC_RAISE, - TILEPRO_OPC_ADD, - TILEPRO_OPC_ADD_SN, - TILEPRO_OPC_ADDB, - TILEPRO_OPC_ADDB_SN, - TILEPRO_OPC_ADDBS_U, - TILEPRO_OPC_ADDBS_U_SN, - TILEPRO_OPC_ADDH, - TILEPRO_OPC_ADDH_SN, - TILEPRO_OPC_ADDHS, - TILEPRO_OPC_ADDHS_SN, - TILEPRO_OPC_ADDI, - TILEPRO_OPC_ADDI_SN, - TILEPRO_OPC_ADDIB, - TILEPRO_OPC_ADDIB_SN, - TILEPRO_OPC_ADDIH, - TILEPRO_OPC_ADDIH_SN, - TILEPRO_OPC_ADDLI, - TILEPRO_OPC_ADDLI_SN, - TILEPRO_OPC_ADDLIS, - TILEPRO_OPC_ADDS, - TILEPRO_OPC_ADDS_SN, - TILEPRO_OPC_ADIFFB_U, - TILEPRO_OPC_ADIFFB_U_SN, - TILEPRO_OPC_ADIFFH, - TILEPRO_OPC_ADIFFH_SN, - TILEPRO_OPC_AND, - TILEPRO_OPC_AND_SN, - TILEPRO_OPC_ANDI, - TILEPRO_OPC_ANDI_SN, - TILEPRO_OPC_AULI, - TILEPRO_OPC_AVGB_U, - TILEPRO_OPC_AVGB_U_SN, - TILEPRO_OPC_AVGH, - TILEPRO_OPC_AVGH_SN, - TILEPRO_OPC_BBNS, - TILEPRO_OPC_BBNS_SN, - TILEPRO_OPC_BBNST, - TILEPRO_OPC_BBNST_SN, - TILEPRO_OPC_BBS, - TILEPRO_OPC_BBS_SN, - TILEPRO_OPC_BBST, - TILEPRO_OPC_BBST_SN, - TILEPRO_OPC_BGEZ, - TILEPRO_OPC_BGEZ_SN, - TILEPRO_OPC_BGEZT, - TILEPRO_OPC_BGEZT_SN, - TILEPRO_OPC_BGZ, - TILEPRO_OPC_BGZ_SN, - TILEPRO_OPC_BGZT, - TILEPRO_OPC_BGZT_SN, - TILEPRO_OPC_BITX, - TILEPRO_OPC_BITX_SN, - TILEPRO_OPC_BLEZ, - TILEPRO_OPC_BLEZ_SN, - TILEPRO_OPC_BLEZT, - TILEPRO_OPC_BLEZT_SN, - TILEPRO_OPC_BLZ, - TILEPRO_OPC_BLZ_SN, - TILEPRO_OPC_BLZT, - TILEPRO_OPC_BLZT_SN, - TILEPRO_OPC_BNZ, - TILEPRO_OPC_BNZ_SN, - TILEPRO_OPC_BNZT, - TILEPRO_OPC_BNZT_SN, - TILEPRO_OPC_BYTEX, - TILEPRO_OPC_BYTEX_SN, - TILEPRO_OPC_BZ, - TILEPRO_OPC_BZ_SN, - TILEPRO_OPC_BZT, - TILEPRO_OPC_BZT_SN, - TILEPRO_OPC_CLZ, - TILEPRO_OPC_CLZ_SN, - TILEPRO_OPC_CRC32_32, - TILEPRO_OPC_CRC32_32_SN, - TILEPRO_OPC_CRC32_8, - TILEPRO_OPC_CRC32_8_SN, - TILEPRO_OPC_CTZ, - TILEPRO_OPC_CTZ_SN, - TILEPRO_OPC_DRAIN, - TILEPRO_OPC_DTLBPR, - TILEPRO_OPC_DWORD_ALIGN, - TILEPRO_OPC_DWORD_ALIGN_SN, - TILEPRO_OPC_FINV, - TILEPRO_OPC_FLUSH, - TILEPRO_OPC_FNOP, - TILEPRO_OPC_ICOH, - TILEPRO_OPC_ILL, - TILEPRO_OPC_INTHB, - TILEPRO_OPC_INTHB_SN, - TILEPRO_OPC_INTHH, - TILEPRO_OPC_INTHH_SN, - TILEPRO_OPC_INTLB, - TILEPRO_OPC_INTLB_SN, - TILEPRO_OPC_INTLH, - TILEPRO_OPC_INTLH_SN, - TILEPRO_OPC_INV, - TILEPRO_OPC_IRET, - TILEPRO_OPC_JALB, - TILEPRO_OPC_JALF, - TILEPRO_OPC_JALR, - TILEPRO_OPC_JALRP, - TILEPRO_OPC_JB, - TILEPRO_OPC_JF, - TILEPRO_OPC_JR, - TILEPRO_OPC_JRP, - TILEPRO_OPC_LB, - TILEPRO_OPC_LB_SN, - TILEPRO_OPC_LB_U, - TILEPRO_OPC_LB_U_SN, - TILEPRO_OPC_LBADD, - TILEPRO_OPC_LBADD_SN, - TILEPRO_OPC_LBADD_U, - TILEPRO_OPC_LBADD_U_SN, - TILEPRO_OPC_LH, - TILEPRO_OPC_LH_SN, - TILEPRO_OPC_LH_U, - TILEPRO_OPC_LH_U_SN, - TILEPRO_OPC_LHADD, - TILEPRO_OPC_LHADD_SN, - TILEPRO_OPC_LHADD_U, - TILEPRO_OPC_LHADD_U_SN, - TILEPRO_OPC_LNK, - TILEPRO_OPC_LNK_SN, - TILEPRO_OPC_LW, - TILEPRO_OPC_LW_SN, - TILEPRO_OPC_LW_NA, - TILEPRO_OPC_LW_NA_SN, - TILEPRO_OPC_LWADD, - TILEPRO_OPC_LWADD_SN, - TILEPRO_OPC_LWADD_NA, - TILEPRO_OPC_LWADD_NA_SN, - TILEPRO_OPC_MAXB_U, - TILEPRO_OPC_MAXB_U_SN, - TILEPRO_OPC_MAXH, - TILEPRO_OPC_MAXH_SN, - TILEPRO_OPC_MAXIB_U, - TILEPRO_OPC_MAXIB_U_SN, - TILEPRO_OPC_MAXIH, - TILEPRO_OPC_MAXIH_SN, - TILEPRO_OPC_MF, - TILEPRO_OPC_MFSPR, - TILEPRO_OPC_MINB_U, - TILEPRO_OPC_MINB_U_SN, - TILEPRO_OPC_MINH, - TILEPRO_OPC_MINH_SN, - TILEPRO_OPC_MINIB_U, - TILEPRO_OPC_MINIB_U_SN, - TILEPRO_OPC_MINIH, - TILEPRO_OPC_MINIH_SN, - TILEPRO_OPC_MM, - TILEPRO_OPC_MNZ, - TILEPRO_OPC_MNZ_SN, - TILEPRO_OPC_MNZB, - TILEPRO_OPC_MNZB_SN, - TILEPRO_OPC_MNZH, - TILEPRO_OPC_MNZH_SN, - TILEPRO_OPC_MTSPR, - TILEPRO_OPC_MULHH_SS, - TILEPRO_OPC_MULHH_SS_SN, - TILEPRO_OPC_MULHH_SU, - TILEPRO_OPC_MULHH_SU_SN, - TILEPRO_OPC_MULHH_UU, - TILEPRO_OPC_MULHH_UU_SN, - TILEPRO_OPC_MULHHA_SS, - TILEPRO_OPC_MULHHA_SS_SN, - TILEPRO_OPC_MULHHA_SU, - TILEPRO_OPC_MULHHA_SU_SN, - TILEPRO_OPC_MULHHA_UU, - TILEPRO_OPC_MULHHA_UU_SN, - TILEPRO_OPC_MULHHSA_UU, - TILEPRO_OPC_MULHHSA_UU_SN, - TILEPRO_OPC_MULHL_SS, - TILEPRO_OPC_MULHL_SS_SN, - TILEPRO_OPC_MULHL_SU, - TILEPRO_OPC_MULHL_SU_SN, - TILEPRO_OPC_MULHL_US, - TILEPRO_OPC_MULHL_US_SN, - TILEPRO_OPC_MULHL_UU, - TILEPRO_OPC_MULHL_UU_SN, - TILEPRO_OPC_MULHLA_SS, - TILEPRO_OPC_MULHLA_SS_SN, - TILEPRO_OPC_MULHLA_SU, - TILEPRO_OPC_MULHLA_SU_SN, - TILEPRO_OPC_MULHLA_US, - TILEPRO_OPC_MULHLA_US_SN, - TILEPRO_OPC_MULHLA_UU, - TILEPRO_OPC_MULHLA_UU_SN, - TILEPRO_OPC_MULHLSA_UU, - TILEPRO_OPC_MULHLSA_UU_SN, - TILEPRO_OPC_MULLL_SS, - TILEPRO_OPC_MULLL_SS_SN, - TILEPRO_OPC_MULLL_SU, - TILEPRO_OPC_MULLL_SU_SN, - TILEPRO_OPC_MULLL_UU, - TILEPRO_OPC_MULLL_UU_SN, - TILEPRO_OPC_MULLLA_SS, - TILEPRO_OPC_MULLLA_SS_SN, - TILEPRO_OPC_MULLLA_SU, - TILEPRO_OPC_MULLLA_SU_SN, - TILEPRO_OPC_MULLLA_UU, - TILEPRO_OPC_MULLLA_UU_SN, - TILEPRO_OPC_MULLLSA_UU, - TILEPRO_OPC_MULLLSA_UU_SN, - TILEPRO_OPC_MVNZ, - TILEPRO_OPC_MVNZ_SN, - TILEPRO_OPC_MVZ, - TILEPRO_OPC_MVZ_SN, - TILEPRO_OPC_MZ, - TILEPRO_OPC_MZ_SN, - TILEPRO_OPC_MZB, - TILEPRO_OPC_MZB_SN, - TILEPRO_OPC_MZH, - TILEPRO_OPC_MZH_SN, - TILEPRO_OPC_NAP, - TILEPRO_OPC_NOP, - TILEPRO_OPC_NOR, - TILEPRO_OPC_NOR_SN, - TILEPRO_OPC_OR, - TILEPRO_OPC_OR_SN, - TILEPRO_OPC_ORI, - TILEPRO_OPC_ORI_SN, - TILEPRO_OPC_PACKBS_U, - TILEPRO_OPC_PACKBS_U_SN, - TILEPRO_OPC_PACKHB, - TILEPRO_OPC_PACKHB_SN, - TILEPRO_OPC_PACKHS, - TILEPRO_OPC_PACKHS_SN, - TILEPRO_OPC_PACKLB, - TILEPRO_OPC_PACKLB_SN, - TILEPRO_OPC_PCNT, - TILEPRO_OPC_PCNT_SN, - TILEPRO_OPC_RL, - TILEPRO_OPC_RL_SN, - TILEPRO_OPC_RLI, - TILEPRO_OPC_RLI_SN, - TILEPRO_OPC_S1A, - TILEPRO_OPC_S1A_SN, - TILEPRO_OPC_S2A, - TILEPRO_OPC_S2A_SN, - TILEPRO_OPC_S3A, - TILEPRO_OPC_S3A_SN, - TILEPRO_OPC_SADAB_U, - TILEPRO_OPC_SADAB_U_SN, - TILEPRO_OPC_SADAH, - TILEPRO_OPC_SADAH_SN, - TILEPRO_OPC_SADAH_U, - TILEPRO_OPC_SADAH_U_SN, - TILEPRO_OPC_SADB_U, - TILEPRO_OPC_SADB_U_SN, - TILEPRO_OPC_SADH, - TILEPRO_OPC_SADH_SN, - TILEPRO_OPC_SADH_U, - TILEPRO_OPC_SADH_U_SN, - TILEPRO_OPC_SB, - TILEPRO_OPC_SBADD, - TILEPRO_OPC_SEQ, - TILEPRO_OPC_SEQ_SN, - TILEPRO_OPC_SEQB, - TILEPRO_OPC_SEQB_SN, - TILEPRO_OPC_SEQH, - TILEPRO_OPC_SEQH_SN, - TILEPRO_OPC_SEQI, - TILEPRO_OPC_SEQI_SN, - TILEPRO_OPC_SEQIB, - TILEPRO_OPC_SEQIB_SN, - TILEPRO_OPC_SEQIH, - TILEPRO_OPC_SEQIH_SN, - TILEPRO_OPC_SH, - TILEPRO_OPC_SHADD, - TILEPRO_OPC_SHL, - TILEPRO_OPC_SHL_SN, - TILEPRO_OPC_SHLB, - TILEPRO_OPC_SHLB_SN, - TILEPRO_OPC_SHLH, - TILEPRO_OPC_SHLH_SN, - TILEPRO_OPC_SHLI, - TILEPRO_OPC_SHLI_SN, - TILEPRO_OPC_SHLIB, - TILEPRO_OPC_SHLIB_SN, - TILEPRO_OPC_SHLIH, - TILEPRO_OPC_SHLIH_SN, - TILEPRO_OPC_SHR, - TILEPRO_OPC_SHR_SN, - TILEPRO_OPC_SHRB, - TILEPRO_OPC_SHRB_SN, - TILEPRO_OPC_SHRH, - TILEPRO_OPC_SHRH_SN, - TILEPRO_OPC_SHRI, - TILEPRO_OPC_SHRI_SN, - TILEPRO_OPC_SHRIB, - TILEPRO_OPC_SHRIB_SN, - TILEPRO_OPC_SHRIH, - TILEPRO_OPC_SHRIH_SN, - TILEPRO_OPC_SLT, - TILEPRO_OPC_SLT_SN, - TILEPRO_OPC_SLT_U, - TILEPRO_OPC_SLT_U_SN, - TILEPRO_OPC_SLTB, - TILEPRO_OPC_SLTB_SN, - TILEPRO_OPC_SLTB_U, - TILEPRO_OPC_SLTB_U_SN, - TILEPRO_OPC_SLTE, - TILEPRO_OPC_SLTE_SN, - TILEPRO_OPC_SLTE_U, - TILEPRO_OPC_SLTE_U_SN, - TILEPRO_OPC_SLTEB, - TILEPRO_OPC_SLTEB_SN, - TILEPRO_OPC_SLTEB_U, - TILEPRO_OPC_SLTEB_U_SN, - TILEPRO_OPC_SLTEH, - TILEPRO_OPC_SLTEH_SN, - TILEPRO_OPC_SLTEH_U, - TILEPRO_OPC_SLTEH_U_SN, - TILEPRO_OPC_SLTH, - TILEPRO_OPC_SLTH_SN, - TILEPRO_OPC_SLTH_U, - TILEPRO_OPC_SLTH_U_SN, - TILEPRO_OPC_SLTI, - TILEPRO_OPC_SLTI_SN, - TILEPRO_OPC_SLTI_U, - TILEPRO_OPC_SLTI_U_SN, - TILEPRO_OPC_SLTIB, - TILEPRO_OPC_SLTIB_SN, - TILEPRO_OPC_SLTIB_U, - TILEPRO_OPC_SLTIB_U_SN, - TILEPRO_OPC_SLTIH, - TILEPRO_OPC_SLTIH_SN, - TILEPRO_OPC_SLTIH_U, - TILEPRO_OPC_SLTIH_U_SN, - TILEPRO_OPC_SNE, - TILEPRO_OPC_SNE_SN, - TILEPRO_OPC_SNEB, - TILEPRO_OPC_SNEB_SN, - TILEPRO_OPC_SNEH, - TILEPRO_OPC_SNEH_SN, - TILEPRO_OPC_SRA, - TILEPRO_OPC_SRA_SN, - TILEPRO_OPC_SRAB, - TILEPRO_OPC_SRAB_SN, - TILEPRO_OPC_SRAH, - TILEPRO_OPC_SRAH_SN, - TILEPRO_OPC_SRAI, - TILEPRO_OPC_SRAI_SN, - TILEPRO_OPC_SRAIB, - TILEPRO_OPC_SRAIB_SN, - TILEPRO_OPC_SRAIH, - TILEPRO_OPC_SRAIH_SN, - TILEPRO_OPC_SUB, - TILEPRO_OPC_SUB_SN, - TILEPRO_OPC_SUBB, - TILEPRO_OPC_SUBB_SN, - TILEPRO_OPC_SUBBS_U, - TILEPRO_OPC_SUBBS_U_SN, - TILEPRO_OPC_SUBH, - TILEPRO_OPC_SUBH_SN, - TILEPRO_OPC_SUBHS, - TILEPRO_OPC_SUBHS_SN, - TILEPRO_OPC_SUBS, - TILEPRO_OPC_SUBS_SN, - TILEPRO_OPC_SW, - TILEPRO_OPC_SWADD, - TILEPRO_OPC_SWINT0, - TILEPRO_OPC_SWINT1, - TILEPRO_OPC_SWINT2, - TILEPRO_OPC_SWINT3, - TILEPRO_OPC_TBLIDXB0, - TILEPRO_OPC_TBLIDXB0_SN, - TILEPRO_OPC_TBLIDXB1, - TILEPRO_OPC_TBLIDXB1_SN, - TILEPRO_OPC_TBLIDXB2, - TILEPRO_OPC_TBLIDXB2_SN, - TILEPRO_OPC_TBLIDXB3, - TILEPRO_OPC_TBLIDXB3_SN, - TILEPRO_OPC_TNS, - TILEPRO_OPC_TNS_SN, - TILEPRO_OPC_WH64, - TILEPRO_OPC_XOR, - TILEPRO_OPC_XOR_SN, - TILEPRO_OPC_XORI, - TILEPRO_OPC_XORI_SN, - TILEPRO_OPC_NONE -} tilepro_mnemonic; - - - - -typedef enum -{ - TILEPRO_PIPELINE_X0, - TILEPRO_PIPELINE_X1, - TILEPRO_PIPELINE_Y0, - TILEPRO_PIPELINE_Y1, - TILEPRO_PIPELINE_Y2, -} tilepro_pipeline; - -#define tilepro_is_x_pipeline(p) ((int)(p) <= (int)TILEPRO_PIPELINE_X1) - -typedef enum -{ - TILEPRO_OP_TYPE_REGISTER, - TILEPRO_OP_TYPE_IMMEDIATE, - TILEPRO_OP_TYPE_ADDRESS, - TILEPRO_OP_TYPE_SPR -} tilepro_operand_type; - -struct tilepro_operand -{ - /* Is this operand a register, immediate or address? */ - tilepro_operand_type type; - - /* The default relocation type for this operand. */ - signed int default_reloc : 16; - - /* How many bits is this value? (used for range checking) */ - unsigned int num_bits : 5; - - /* Is the value signed? (used for range checking) */ - unsigned int is_signed : 1; - - /* Is this operand a source register? */ - unsigned int is_src_reg : 1; - - /* Is this operand written? (i.e. is it a destination register) */ - unsigned int is_dest_reg : 1; - - /* Is this operand PC-relative? */ - unsigned int is_pc_relative : 1; - - /* By how many bits do we right shift the value before inserting? */ - unsigned int rightshift : 2; - - /* Return the bits for this operand to be ORed into an existing bundle. */ - tilepro_bundle_bits (*insert) (int op); - - /* Extract this operand and return it. */ - unsigned int (*extract) (tilepro_bundle_bits bundle); -}; - - -extern const struct tilepro_operand tilepro_operands[]; - -/* One finite-state machine per pipe for rapid instruction decoding. */ -extern const unsigned short * const -tilepro_bundle_decoder_fsms[TILEPRO_NUM_PIPELINE_ENCODINGS]; - - -struct tilepro_opcode -{ - /* The opcode mnemonic, e.g. "add" */ - const char *name; - - /* The enum value for this mnemonic. */ - tilepro_mnemonic mnemonic; - - /* A bit mask of which of the five pipes this instruction - is compatible with: - X0 0x01 - X1 0x02 - Y0 0x04 - Y1 0x08 - Y2 0x10 */ - unsigned char pipes; - - /* How many operands are there? */ - unsigned char num_operands; - - /* Which register does this write implicitly, or TREG_ZERO if none? */ - unsigned char implicitly_written_register; - - /* Can this be bundled with other instructions (almost always true). */ - unsigned char can_bundle; - - /* The description of the operands. Each of these is an - * index into the tilepro_operands[] table. */ - unsigned char operands[TILEPRO_NUM_PIPELINE_ENCODINGS][TILEPRO_MAX_OPERANDS]; - -}; - -extern const struct tilepro_opcode tilepro_opcodes[]; - - -/* Used for non-textual disassembly into structs. */ -struct tilepro_decoded_instruction -{ - const struct tilepro_opcode *opcode; - const struct tilepro_operand *operands[TILEPRO_MAX_OPERANDS]; - int operand_values[TILEPRO_MAX_OPERANDS]; -}; - - -/* Disassemble a bundle into a struct for machine processing. */ -extern int parse_insn_tilepro(tilepro_bundle_bits bits, - unsigned int pc, - struct tilepro_decoded_instruction - decoded[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE]); - - -/* Given a set of bundle bits and a specific pipe, returns which - * instruction the bundle contains in that pipe. - */ -extern const struct tilepro_opcode * -find_opcode(tilepro_bundle_bits bits, tilepro_pipeline pipe); - - - -#endif /* opcode_tilepro_h */ diff --git a/arch/tile/include/asm/tile-desc_64.h b/arch/tile/include/asm/tile-desc_64.h deleted file mode 100644 index 1819efcba54d..000000000000 --- a/arch/tile/include/asm/tile-desc_64.h +++ /dev/null @@ -1,483 +0,0 @@ -/* TILE-Gx opcode information. - * - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * - * - * - * - */ - -#ifndef opcode_tile_h -#define opcode_tile_h - -#include - - -enum -{ - TILEGX_MAX_OPERANDS = 4 /* bfexts */ -}; - -typedef enum -{ - TILEGX_OPC_BPT, - TILEGX_OPC_INFO, - TILEGX_OPC_INFOL, - TILEGX_OPC_MOVE, - TILEGX_OPC_MOVEI, - TILEGX_OPC_MOVELI, - TILEGX_OPC_PREFETCH, - TILEGX_OPC_PREFETCH_ADD_L1, - TILEGX_OPC_PREFETCH_ADD_L1_FAULT, - TILEGX_OPC_PREFETCH_ADD_L2, - TILEGX_OPC_PREFETCH_ADD_L2_FAULT, - TILEGX_OPC_PREFETCH_ADD_L3, - TILEGX_OPC_PREFETCH_ADD_L3_FAULT, - TILEGX_OPC_PREFETCH_L1, - TILEGX_OPC_PREFETCH_L1_FAULT, - TILEGX_OPC_PREFETCH_L2, - TILEGX_OPC_PREFETCH_L2_FAULT, - TILEGX_OPC_PREFETCH_L3, - TILEGX_OPC_PREFETCH_L3_FAULT, - TILEGX_OPC_RAISE, - TILEGX_OPC_ADD, - TILEGX_OPC_ADDI, - TILEGX_OPC_ADDLI, - TILEGX_OPC_ADDX, - TILEGX_OPC_ADDXI, - TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXSC, - TILEGX_OPC_AND, - TILEGX_OPC_ANDI, - TILEGX_OPC_BEQZ, - TILEGX_OPC_BEQZT, - TILEGX_OPC_BFEXTS, - TILEGX_OPC_BFEXTU, - TILEGX_OPC_BFINS, - TILEGX_OPC_BGEZ, - TILEGX_OPC_BGEZT, - TILEGX_OPC_BGTZ, - TILEGX_OPC_BGTZT, - TILEGX_OPC_BLBC, - TILEGX_OPC_BLBCT, - TILEGX_OPC_BLBS, - TILEGX_OPC_BLBST, - TILEGX_OPC_BLEZ, - TILEGX_OPC_BLEZT, - TILEGX_OPC_BLTZ, - TILEGX_OPC_BLTZT, - TILEGX_OPC_BNEZ, - TILEGX_OPC_BNEZT, - TILEGX_OPC_CLZ, - TILEGX_OPC_CMOVEQZ, - TILEGX_OPC_CMOVNEZ, - TILEGX_OPC_CMPEQ, - TILEGX_OPC_CMPEQI, - TILEGX_OPC_CMPEXCH, - TILEGX_OPC_CMPEXCH4, - TILEGX_OPC_CMPLES, - TILEGX_OPC_CMPLEU, - TILEGX_OPC_CMPLTS, - TILEGX_OPC_CMPLTSI, - TILEGX_OPC_CMPLTU, - TILEGX_OPC_CMPLTUI, - TILEGX_OPC_CMPNE, - TILEGX_OPC_CMUL, - TILEGX_OPC_CMULA, - TILEGX_OPC_CMULAF, - TILEGX_OPC_CMULF, - TILEGX_OPC_CMULFR, - TILEGX_OPC_CMULH, - TILEGX_OPC_CMULHR, - TILEGX_OPC_CRC32_32, - TILEGX_OPC_CRC32_8, - TILEGX_OPC_CTZ, - TILEGX_OPC_DBLALIGN, - TILEGX_OPC_DBLALIGN2, - TILEGX_OPC_DBLALIGN4, - TILEGX_OPC_DBLALIGN6, - TILEGX_OPC_DRAIN, - TILEGX_OPC_DTLBPR, - TILEGX_OPC_EXCH, - TILEGX_OPC_EXCH4, - TILEGX_OPC_FDOUBLE_ADD_FLAGS, - TILEGX_OPC_FDOUBLE_ADDSUB, - TILEGX_OPC_FDOUBLE_MUL_FLAGS, - TILEGX_OPC_FDOUBLE_PACK1, - TILEGX_OPC_FDOUBLE_PACK2, - TILEGX_OPC_FDOUBLE_SUB_FLAGS, - TILEGX_OPC_FDOUBLE_UNPACK_MAX, - TILEGX_OPC_FDOUBLE_UNPACK_MIN, - TILEGX_OPC_FETCHADD, - TILEGX_OPC_FETCHADD4, - TILEGX_OPC_FETCHADDGEZ, - TILEGX_OPC_FETCHADDGEZ4, - TILEGX_OPC_FETCHAND, - TILEGX_OPC_FETCHAND4, - TILEGX_OPC_FETCHOR, - TILEGX_OPC_FETCHOR4, - TILEGX_OPC_FINV, - TILEGX_OPC_FLUSH, - TILEGX_OPC_FLUSHWB, - TILEGX_OPC_FNOP, - TILEGX_OPC_FSINGLE_ADD1, - TILEGX_OPC_FSINGLE_ADDSUB2, - TILEGX_OPC_FSINGLE_MUL1, - TILEGX_OPC_FSINGLE_MUL2, - TILEGX_OPC_FSINGLE_PACK1, - TILEGX_OPC_FSINGLE_PACK2, - TILEGX_OPC_FSINGLE_SUB1, - TILEGX_OPC_ICOH, - TILEGX_OPC_ILL, - TILEGX_OPC_INV, - TILEGX_OPC_IRET, - TILEGX_OPC_J, - TILEGX_OPC_JAL, - TILEGX_OPC_JALR, - TILEGX_OPC_JALRP, - TILEGX_OPC_JR, - TILEGX_OPC_JRP, - TILEGX_OPC_LD, - TILEGX_OPC_LD1S, - TILEGX_OPC_LD1S_ADD, - TILEGX_OPC_LD1U, - TILEGX_OPC_LD1U_ADD, - TILEGX_OPC_LD2S, - TILEGX_OPC_LD2S_ADD, - TILEGX_OPC_LD2U, - TILEGX_OPC_LD2U_ADD, - TILEGX_OPC_LD4S, - TILEGX_OPC_LD4S_ADD, - TILEGX_OPC_LD4U, - TILEGX_OPC_LD4U_ADD, - TILEGX_OPC_LD_ADD, - TILEGX_OPC_LDNA, - TILEGX_OPC_LDNA_ADD, - TILEGX_OPC_LDNT, - TILEGX_OPC_LDNT1S, - TILEGX_OPC_LDNT1S_ADD, - TILEGX_OPC_LDNT1U, - TILEGX_OPC_LDNT1U_ADD, - TILEGX_OPC_LDNT2S, - TILEGX_OPC_LDNT2S_ADD, - TILEGX_OPC_LDNT2U, - TILEGX_OPC_LDNT2U_ADD, - TILEGX_OPC_LDNT4S, - TILEGX_OPC_LDNT4S_ADD, - TILEGX_OPC_LDNT4U, - TILEGX_OPC_LDNT4U_ADD, - TILEGX_OPC_LDNT_ADD, - TILEGX_OPC_LNK, - TILEGX_OPC_MF, - TILEGX_OPC_MFSPR, - TILEGX_OPC_MM, - TILEGX_OPC_MNZ, - TILEGX_OPC_MTSPR, - TILEGX_OPC_MUL_HS_HS, - TILEGX_OPC_MUL_HS_HU, - TILEGX_OPC_MUL_HS_LS, - TILEGX_OPC_MUL_HS_LU, - TILEGX_OPC_MUL_HU_HU, - TILEGX_OPC_MUL_HU_LS, - TILEGX_OPC_MUL_HU_LU, - TILEGX_OPC_MUL_LS_LS, - TILEGX_OPC_MUL_LS_LU, - TILEGX_OPC_MUL_LU_LU, - TILEGX_OPC_MULA_HS_HS, - TILEGX_OPC_MULA_HS_HU, - TILEGX_OPC_MULA_HS_LS, - TILEGX_OPC_MULA_HS_LU, - TILEGX_OPC_MULA_HU_HU, - TILEGX_OPC_MULA_HU_LS, - TILEGX_OPC_MULA_HU_LU, - TILEGX_OPC_MULA_LS_LS, - TILEGX_OPC_MULA_LS_LU, - TILEGX_OPC_MULA_LU_LU, - TILEGX_OPC_MULAX, - TILEGX_OPC_MULX, - TILEGX_OPC_MZ, - TILEGX_OPC_NAP, - TILEGX_OPC_NOP, - TILEGX_OPC_NOR, - TILEGX_OPC_OR, - TILEGX_OPC_ORI, - TILEGX_OPC_PCNT, - TILEGX_OPC_REVBITS, - TILEGX_OPC_REVBYTES, - TILEGX_OPC_ROTL, - TILEGX_OPC_ROTLI, - TILEGX_OPC_SHL, - TILEGX_OPC_SHL16INSLI, - TILEGX_OPC_SHL1ADD, - TILEGX_OPC_SHL1ADDX, - TILEGX_OPC_SHL2ADD, - TILEGX_OPC_SHL2ADDX, - TILEGX_OPC_SHL3ADD, - TILEGX_OPC_SHL3ADDX, - TILEGX_OPC_SHLI, - TILEGX_OPC_SHLX, - TILEGX_OPC_SHLXI, - TILEGX_OPC_SHRS, - TILEGX_OPC_SHRSI, - TILEGX_OPC_SHRU, - TILEGX_OPC_SHRUI, - TILEGX_OPC_SHRUX, - TILEGX_OPC_SHRUXI, - TILEGX_OPC_SHUFFLEBYTES, - TILEGX_OPC_ST, - TILEGX_OPC_ST1, - TILEGX_OPC_ST1_ADD, - TILEGX_OPC_ST2, - TILEGX_OPC_ST2_ADD, - TILEGX_OPC_ST4, - TILEGX_OPC_ST4_ADD, - TILEGX_OPC_ST_ADD, - TILEGX_OPC_STNT, - TILEGX_OPC_STNT1, - TILEGX_OPC_STNT1_ADD, - TILEGX_OPC_STNT2, - TILEGX_OPC_STNT2_ADD, - TILEGX_OPC_STNT4, - TILEGX_OPC_STNT4_ADD, - TILEGX_OPC_STNT_ADD, - TILEGX_OPC_SUB, - TILEGX_OPC_SUBX, - TILEGX_OPC_SUBXSC, - TILEGX_OPC_SWINT0, - TILEGX_OPC_SWINT1, - TILEGX_OPC_SWINT2, - TILEGX_OPC_SWINT3, - TILEGX_OPC_TBLIDXB0, - TILEGX_OPC_TBLIDXB1, - TILEGX_OPC_TBLIDXB2, - TILEGX_OPC_TBLIDXB3, - TILEGX_OPC_V1ADD, - TILEGX_OPC_V1ADDI, - TILEGX_OPC_V1ADDUC, - TILEGX_OPC_V1ADIFFU, - TILEGX_OPC_V1AVGU, - TILEGX_OPC_V1CMPEQ, - TILEGX_OPC_V1CMPEQI, - TILEGX_OPC_V1CMPLES, - TILEGX_OPC_V1CMPLEU, - TILEGX_OPC_V1CMPLTS, - TILEGX_OPC_V1CMPLTSI, - TILEGX_OPC_V1CMPLTU, - TILEGX_OPC_V1CMPLTUI, - TILEGX_OPC_V1CMPNE, - TILEGX_OPC_V1DDOTPU, - TILEGX_OPC_V1DDOTPUA, - TILEGX_OPC_V1DDOTPUS, - TILEGX_OPC_V1DDOTPUSA, - TILEGX_OPC_V1DOTP, - TILEGX_OPC_V1DOTPA, - TILEGX_OPC_V1DOTPU, - TILEGX_OPC_V1DOTPUA, - TILEGX_OPC_V1DOTPUS, - TILEGX_OPC_V1DOTPUSA, - TILEGX_OPC_V1INT_H, - TILEGX_OPC_V1INT_L, - TILEGX_OPC_V1MAXU, - TILEGX_OPC_V1MAXUI, - TILEGX_OPC_V1MINU, - TILEGX_OPC_V1MINUI, - TILEGX_OPC_V1MNZ, - TILEGX_OPC_V1MULTU, - TILEGX_OPC_V1MULU, - TILEGX_OPC_V1MULUS, - TILEGX_OPC_V1MZ, - TILEGX_OPC_V1SADAU, - TILEGX_OPC_V1SADU, - TILEGX_OPC_V1SHL, - TILEGX_OPC_V1SHLI, - TILEGX_OPC_V1SHRS, - TILEGX_OPC_V1SHRSI, - TILEGX_OPC_V1SHRU, - TILEGX_OPC_V1SHRUI, - TILEGX_OPC_V1SUB, - TILEGX_OPC_V1SUBUC, - TILEGX_OPC_V2ADD, - TILEGX_OPC_V2ADDI, - TILEGX_OPC_V2ADDSC, - TILEGX_OPC_V2ADIFFS, - TILEGX_OPC_V2AVGS, - TILEGX_OPC_V2CMPEQ, - TILEGX_OPC_V2CMPEQI, - TILEGX_OPC_V2CMPLES, - TILEGX_OPC_V2CMPLEU, - TILEGX_OPC_V2CMPLTS, - TILEGX_OPC_V2CMPLTSI, - TILEGX_OPC_V2CMPLTU, - TILEGX_OPC_V2CMPLTUI, - TILEGX_OPC_V2CMPNE, - TILEGX_OPC_V2DOTP, - TILEGX_OPC_V2DOTPA, - TILEGX_OPC_V2INT_H, - TILEGX_OPC_V2INT_L, - TILEGX_OPC_V2MAXS, - TILEGX_OPC_V2MAXSI, - TILEGX_OPC_V2MINS, - TILEGX_OPC_V2MINSI, - TILEGX_OPC_V2MNZ, - TILEGX_OPC_V2MULFSC, - TILEGX_OPC_V2MULS, - TILEGX_OPC_V2MULTS, - TILEGX_OPC_V2MZ, - TILEGX_OPC_V2PACKH, - TILEGX_OPC_V2PACKL, - TILEGX_OPC_V2PACKUC, - TILEGX_OPC_V2SADAS, - TILEGX_OPC_V2SADAU, - TILEGX_OPC_V2SADS, - TILEGX_OPC_V2SADU, - TILEGX_OPC_V2SHL, - TILEGX_OPC_V2SHLI, - TILEGX_OPC_V2SHLSC, - TILEGX_OPC_V2SHRS, - TILEGX_OPC_V2SHRSI, - TILEGX_OPC_V2SHRU, - TILEGX_OPC_V2SHRUI, - TILEGX_OPC_V2SUB, - TILEGX_OPC_V2SUBSC, - TILEGX_OPC_V4ADD, - TILEGX_OPC_V4ADDSC, - TILEGX_OPC_V4INT_H, - TILEGX_OPC_V4INT_L, - TILEGX_OPC_V4PACKSC, - TILEGX_OPC_V4SHL, - TILEGX_OPC_V4SHLSC, - TILEGX_OPC_V4SHRS, - TILEGX_OPC_V4SHRU, - TILEGX_OPC_V4SUB, - TILEGX_OPC_V4SUBSC, - TILEGX_OPC_WH64, - TILEGX_OPC_XOR, - TILEGX_OPC_XORI, - TILEGX_OPC_NONE -} tilegx_mnemonic; - - - -typedef enum -{ - TILEGX_PIPELINE_X0, - TILEGX_PIPELINE_X1, - TILEGX_PIPELINE_Y0, - TILEGX_PIPELINE_Y1, - TILEGX_PIPELINE_Y2, -} tilegx_pipeline; - -#define tilegx_is_x_pipeline(p) ((int)(p) <= (int)TILEGX_PIPELINE_X1) - -typedef enum -{ - TILEGX_OP_TYPE_REGISTER, - TILEGX_OP_TYPE_IMMEDIATE, - TILEGX_OP_TYPE_ADDRESS, - TILEGX_OP_TYPE_SPR -} tilegx_operand_type; - -struct tilegx_operand -{ - /* Is this operand a register, immediate or address? */ - tilegx_operand_type type; - - /* The default relocation type for this operand. */ - signed int default_reloc : 16; - - /* How many bits is this value? (used for range checking) */ - unsigned int num_bits : 5; - - /* Is the value signed? (used for range checking) */ - unsigned int is_signed : 1; - - /* Is this operand a source register? */ - unsigned int is_src_reg : 1; - - /* Is this operand written? (i.e. is it a destination register) */ - unsigned int is_dest_reg : 1; - - /* Is this operand PC-relative? */ - unsigned int is_pc_relative : 1; - - /* By how many bits do we right shift the value before inserting? */ - unsigned int rightshift : 2; - - /* Return the bits for this operand to be ORed into an existing bundle. */ - tilegx_bundle_bits (*insert) (int op); - - /* Extract this operand and return it. */ - unsigned int (*extract) (tilegx_bundle_bits bundle); -}; - - -extern const struct tilegx_operand tilegx_operands[]; - -/* One finite-state machine per pipe for rapid instruction decoding. */ -extern const unsigned short * const -tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS]; - - -struct tilegx_opcode -{ - /* The opcode mnemonic, e.g. "add" */ - const char *name; - - /* The enum value for this mnemonic. */ - tilegx_mnemonic mnemonic; - - /* A bit mask of which of the five pipes this instruction - is compatible with: - X0 0x01 - X1 0x02 - Y0 0x04 - Y1 0x08 - Y2 0x10 */ - unsigned char pipes; - - /* How many operands are there? */ - unsigned char num_operands; - - /* Which register does this write implicitly, or TREG_ZERO if none? */ - unsigned char implicitly_written_register; - - /* Can this be bundled with other instructions (almost always true). */ - unsigned char can_bundle; - - /* The description of the operands. Each of these is an - * index into the tilegx_operands[] table. */ - unsigned char operands[TILEGX_NUM_PIPELINE_ENCODINGS][TILEGX_MAX_OPERANDS]; - -}; - -extern const struct tilegx_opcode tilegx_opcodes[]; - -/* Used for non-textual disassembly into structs. */ -struct tilegx_decoded_instruction -{ - const struct tilegx_opcode *opcode; - const struct tilegx_operand *operands[TILEGX_MAX_OPERANDS]; - long long operand_values[TILEGX_MAX_OPERANDS]; -}; - - -/* Disassemble a bundle into a struct for machine processing. */ -extern int parse_insn_tilegx(tilegx_bundle_bits bits, - unsigned long long pc, - struct tilegx_decoded_instruction - decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]); - - - -#endif /* opcode_tilegx_h */ diff --git a/arch/tile/include/asm/timex.h b/arch/tile/include/asm/timex.h deleted file mode 100644 index dc987d53e2a9..000000000000 --- a/arch/tile/include/asm/timex.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_TIMEX_H -#define _ASM_TILE_TIMEX_H - -/* - * This rate should be a multiple of the possible HZ values (100, 250, 1000) - * and a fraction of the possible hardware timer frequencies. Our timer - * frequency is highly tunable but also quite precise, so for the primary use - * of this value (setting ACT_HZ from HZ) we just pick a value that causes - * ACT_HZ to be set to HZ. We make the value somewhat large just to be - * more robust in case someone tries out a new value of HZ. - */ -#define CLOCK_TICK_RATE 1000000 - -typedef unsigned long long cycles_t; - -#if CHIP_HAS_SPLIT_CYCLE() -cycles_t get_cycles(void); -#define get_cycles_low() __insn_mfspr(SPR_CYCLE_LOW) -#else -static inline cycles_t get_cycles(void) -{ - return __insn_mfspr(SPR_CYCLE); -} -#define get_cycles_low() __insn_mfspr(SPR_CYCLE) /* just get all 64 bits */ -#endif - -cycles_t get_clock_rate(void); - -/* Convert nanoseconds to core clock cycles. */ -cycles_t ns2cycles(unsigned long nsecs); - -/* Called at cpu initialization to set some low-level constants. */ -void setup_clock(void); - -/* Called at cpu initialization to start the tile-timer clock device. */ -void setup_tile_timer(void); - -#endif /* _ASM_TILE_TIMEX_H */ diff --git a/arch/tile/include/asm/tlb.h b/arch/tile/include/asm/tlb.h deleted file mode 100644 index 4a891a1a8df3..000000000000 --- a/arch/tile/include/asm/tlb.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_TLB_H -#define _ASM_TILE_TLB_H - -#define tlb_start_vma(tlb, vma) do { } while (0) -#define tlb_end_vma(tlb, vma) do { } while (0) -#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) -#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) - -#include - -#endif /* _ASM_TILE_TLB_H */ diff --git a/arch/tile/include/asm/tlbflush.h b/arch/tile/include/asm/tlbflush.h deleted file mode 100644 index dcf91b25a1e5..000000000000 --- a/arch/tile/include/asm/tlbflush.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_TLBFLUSH_H -#define _ASM_TILE_TLBFLUSH_H - -#include -#include -#include -#include -#include -#include - -/* - * Rather than associating each mm with its own ASID, we just use - * ASIDs to allow us to lazily flush the TLB when we switch mms. - * This way we only have to do an actual TLB flush on mm switch - * every time we wrap ASIDs, not every single time we switch. - * - * FIXME: We might improve performance by keeping ASIDs around - * properly, though since the hypervisor direct-maps VAs to TSB - * entries, we're likely to have lost at least the executable page - * mappings by the time we switch back to the original mm. - */ -DECLARE_PER_CPU(int, current_asid); - -/* The hypervisor tells us what ASIDs are available to us. */ -extern int min_asid, max_asid; - -/* Pass as vma pointer for non-executable mapping, if no vma available. */ -#define FLUSH_NONEXEC ((struct vm_area_struct *)-1UL) - -/* Flush a single user page on this cpu. */ -static inline void local_flush_tlb_page(struct vm_area_struct *vma, - unsigned long addr, - unsigned long page_size) -{ - int rc = hv_flush_page(addr, page_size); - if (rc < 0) - panic("hv_flush_page(%#lx,%#lx) failed: %d", - addr, page_size, rc); - if (!vma || (vma != FLUSH_NONEXEC && (vma->vm_flags & VM_EXEC))) - __flush_icache(); -} - -/* Flush range of user pages on this cpu. */ -static inline void local_flush_tlb_pages(struct vm_area_struct *vma, - unsigned long addr, - unsigned long page_size, - unsigned long len) -{ - int rc = hv_flush_pages(addr, page_size, len); - if (rc < 0) - panic("hv_flush_pages(%#lx,%#lx,%#lx) failed: %d", - addr, page_size, len, rc); - if (!vma || (vma != FLUSH_NONEXEC && (vma->vm_flags & VM_EXEC))) - __flush_icache(); -} - -/* Flush all user pages on this cpu. */ -static inline void local_flush_tlb(void) -{ - int rc = hv_flush_all(1); /* preserve global mappings */ - if (rc < 0) - panic("hv_flush_all(1) failed: %d", rc); - __flush_icache(); -} - -/* - * Global pages have to be flushed a bit differently. Not a real - * performance problem because this does not happen often. - */ -static inline void local_flush_tlb_all(void) -{ - int i; - for (i = 0; ; ++i) { - HV_VirtAddrRange r = hv_inquire_virtual(i); - if (r.size == 0) - break; - local_flush_tlb_pages(NULL, r.start, PAGE_SIZE, r.size); - local_flush_tlb_pages(NULL, r.start, HPAGE_SIZE, r.size); - } -} - -/* - * TLB flushing: - * - * - flush_tlb() flushes the current mm struct TLBs - * - flush_tlb_all() flushes all processes TLBs - * - flush_tlb_mm(mm) flushes the specified mm context TLB's - * - flush_tlb_page(vma, vmaddr) flushes one page - * - flush_tlb_range(vma, start, end) flushes a range of pages - * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages - * - flush_tlb_others(cpumask, mm, va) flushes TLBs on other cpus - * - * Here (as in vm_area_struct), "end" means the first byte after - * our end address. - */ - -extern void flush_tlb_all(void); -extern void flush_tlb_kernel_range(unsigned long start, unsigned long end); -extern void flush_tlb_current_task(void); -extern void flush_tlb_mm(struct mm_struct *); -extern void flush_tlb_page(struct vm_area_struct *, unsigned long); -extern void flush_tlb_page_mm(struct vm_area_struct *, - struct mm_struct *, unsigned long); -extern void flush_tlb_range(struct vm_area_struct *, - unsigned long start, unsigned long end); - -#define flush_tlb() flush_tlb_current_task() - -#endif /* _ASM_TILE_TLBFLUSH_H */ diff --git a/arch/tile/include/asm/topology.h b/arch/tile/include/asm/topology.h deleted file mode 100644 index 635a0a4596f0..000000000000 --- a/arch/tile/include/asm/topology.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_TOPOLOGY_H -#define _ASM_TILE_TOPOLOGY_H - -#ifdef CONFIG_NUMA - -#include - -/* Mappings between logical cpu number and node number. */ -extern struct cpumask node_2_cpu_mask[]; -extern char cpu_2_node[]; - -/* Returns the number of the node containing CPU 'cpu'. */ -static inline int cpu_to_node(int cpu) -{ - return cpu_2_node[cpu]; -} - -/* Returns a bitmask of CPUs on Node 'node'. */ -static inline const struct cpumask *cpumask_of_node(int node) -{ - return &node_2_cpu_mask[node]; -} - -/* For now, use numa node -1 for global allocation. */ -#define pcibus_to_node(bus) ((void)(bus), -1) - -#endif /* CONFIG_NUMA */ - -#include - -#ifdef CONFIG_SMP -#define topology_physical_package_id(cpu) ((void)(cpu), 0) -#define topology_core_id(cpu) (cpu) -#define topology_core_cpumask(cpu) ((void)(cpu), cpu_online_mask) -#define topology_sibling_cpumask(cpu) cpumask_of(cpu) -#endif - -#endif /* _ASM_TILE_TOPOLOGY_H */ diff --git a/arch/tile/include/asm/traps.h b/arch/tile/include/asm/traps.h deleted file mode 100644 index 11c82270c1f5..000000000000 --- a/arch/tile/include/asm/traps.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_TRAPS_H -#define _ASM_TILE_TRAPS_H - -#ifndef __ASSEMBLY__ -#include - -/* mm/fault.c */ -void do_page_fault(struct pt_regs *, int fault_num, - unsigned long address, unsigned long write); -#if CHIP_HAS_TILE_DMA() -void do_async_page_fault(struct pt_regs *); -#endif - -#ifndef __tilegx__ -/* - * We return this structure in registers to avoid having to write - * additional save/restore code in the intvec.S caller. - */ -struct intvec_state { - void *handler; - unsigned long vecnum; - unsigned long fault_num; - unsigned long info; - unsigned long retval; -}; -struct intvec_state do_page_fault_ics(struct pt_regs *regs, int fault_num, - unsigned long address, - unsigned long info); -#endif - -/* kernel/traps.c */ -void do_trap(struct pt_regs *, int fault_num, unsigned long reason); -void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52); - -/* kernel/time.c */ -void do_timer_interrupt(struct pt_regs *, int fault_num); - -/* kernel/messaging.c */ -void hv_message_intr(struct pt_regs *, int intnum); - -#define TILE_NMI_DUMP_STACK 1 /* Dump stack for sysrq+'l' */ - -/* kernel/process.c */ -void do_nmi_dump_stack(struct pt_regs *regs); - -/* kernel/traps.c */ -void do_nmi(struct pt_regs *, int fault_num, unsigned long reason); - -/* kernel/irq.c */ -void tile_dev_intr(struct pt_regs *, int intnum); - -#ifdef CONFIG_HARDWALL -/* kernel/hardwall.c */ -void do_hardwall_trap(struct pt_regs *, int fault_num); -#endif - -/* kernel/ptrace.c */ -void do_breakpoint(struct pt_regs *, int fault_num); - - -#ifdef __tilegx__ -/* kernel/single_step.c */ -void gx_singlestep_handle(struct pt_regs *, int fault_num); - -/* kernel/intvec_64.S */ -void fill_ra_stack(void); - -/* Handle unalign data fixup. */ -extern void do_unaligned(struct pt_regs *regs, int vecnum); -#endif - -#endif /* __ASSEMBLY__ */ - -#ifdef __tilegx__ -/* 128 byte JIT per unalign fixup. */ -#define UNALIGN_JIT_SHIFT 7 -#endif - -#endif /* _ASM_TILE_TRAPS_H */ diff --git a/arch/tile/include/asm/uaccess.h b/arch/tile/include/asm/uaccess.h deleted file mode 100644 index cb4fbe7e4f88..000000000000 --- a/arch/tile/include/asm/uaccess.h +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_UACCESS_H -#define _ASM_TILE_UACCESS_H - -/* - * User space memory access functions - */ -#include -#include -#include - -/* - * The fs value determines whether argument validity checking should be - * performed or not. If get_fs() == USER_DS, checking is performed, with - * get_fs() == KERNEL_DS, checking is bypassed. - * - * For historical reasons, these macros are grossly misnamed. - */ -#define MAKE_MM_SEG(a) ((mm_segment_t) { (a) }) - -#define KERNEL_DS MAKE_MM_SEG(-1UL) -#define USER_DS MAKE_MM_SEG(PAGE_OFFSET) - -#define get_ds() (KERNEL_DS) -#define get_fs() (current_thread_info()->addr_limit) -#define set_fs(x) (current_thread_info()->addr_limit = (x)) - -#define segment_eq(a, b) ((a).seg == (b).seg) - -#ifndef __tilegx__ -/* - * We could allow mapping all 16 MB at 0xfc000000, but we set up a - * special hack in arch_setup_additional_pages() to auto-create a mapping - * for the first 16 KB, and it would seem strange to have different - * user-accessible semantics for memory at 0xfc000000 and above 0xfc004000. - */ -static inline int is_arch_mappable_range(unsigned long addr, - unsigned long size) -{ - return (addr >= MEM_USER_INTRPT && - addr < (MEM_USER_INTRPT + INTRPT_SIZE) && - size <= (MEM_USER_INTRPT + INTRPT_SIZE) - addr); -} -#define is_arch_mappable_range is_arch_mappable_range -#else -#define is_arch_mappable_range(addr, size) 0 -#endif - -/* - * Note that using this definition ignores is_arch_mappable_range(), - * so on tilepro code that uses user_addr_max() is constrained not - * to reference the tilepro user-interrupt region. - */ -#define user_addr_max() (current_thread_info()->addr_limit.seg) - -/* - * Test whether a block of memory is a valid user space address. - * Returns 0 if the range is valid, nonzero otherwise. - */ -int __range_ok(unsigned long addr, unsigned long size); - -/** - * access_ok: - Checks if a user space pointer is valid - * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE. Note that - * %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe - * to write to a block, it is always safe to read from it. - * @addr: User space pointer to start of block to check - * @size: Size of block to check - * - * Context: User context only. This function may sleep if pagefaults are - * enabled. - * - * Checks if a pointer to a block of memory in user space is valid. - * - * Returns true (nonzero) if the memory block may be valid, false (zero) - * if it is definitely invalid. - * - * Note that, depending on architecture, this function probably just - * checks that the pointer is in the user space range - after calling - * this function, memory access functions may still return -EFAULT. - */ -#define access_ok(type, addr, size) ({ \ - __chk_user_ptr(addr); \ - likely(__range_ok((unsigned long)(addr), (size)) == 0); \ -}) - -#include - -/* - * This is a type: either unsigned long, if the argument fits into - * that type, or otherwise unsigned long long. - */ -#define __inttype(x) \ - __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) - -/* - * Support macros for __get_user(). - * Note that __get_user() and __put_user() assume proper alignment. - */ - -#ifdef __LP64__ -#define _ASM_PTR ".quad" -#define _ASM_ALIGN ".align 8" -#else -#define _ASM_PTR ".long" -#define _ASM_ALIGN ".align 4" -#endif - -#define __get_user_asm(OP, x, ptr, ret) \ - asm volatile("1: {" #OP " %1, %2; movei %0, 0 }\n" \ - ".pushsection .fixup,\"ax\"\n" \ - "0: { movei %1, 0; movei %0, %3 }\n" \ - "j 9f\n" \ - ".section __ex_table,\"a\"\n" \ - _ASM_ALIGN "\n" \ - _ASM_PTR " 1b, 0b\n" \ - ".popsection\n" \ - "9:" \ - : "=r" (ret), "=r" (x) \ - : "r" (ptr), "i" (-EFAULT)) - -#ifdef __tilegx__ -#define __get_user_1(x, ptr, ret) __get_user_asm(ld1u, x, ptr, ret) -#define __get_user_2(x, ptr, ret) __get_user_asm(ld2u, x, ptr, ret) -#define __get_user_4(x, ptr, ret) __get_user_asm(ld4s, x, ptr, ret) -#define __get_user_8(x, ptr, ret) __get_user_asm(ld, x, ptr, ret) -#else -#define __get_user_1(x, ptr, ret) __get_user_asm(lb_u, x, ptr, ret) -#define __get_user_2(x, ptr, ret) __get_user_asm(lh_u, x, ptr, ret) -#define __get_user_4(x, ptr, ret) __get_user_asm(lw, x, ptr, ret) -#ifdef __LITTLE_ENDIAN -#define __lo32(a, b) a -#define __hi32(a, b) b -#else -#define __lo32(a, b) b -#define __hi32(a, b) a -#endif -#define __get_user_8(x, ptr, ret) \ - ({ \ - unsigned int __a, __b; \ - asm volatile("1: { lw %1, %3; addi %2, %3, 4 }\n" \ - "2: { lw %2, %2; movei %0, 0 }\n" \ - ".pushsection .fixup,\"ax\"\n" \ - "0: { movei %1, 0; movei %2, 0 }\n" \ - "{ movei %0, %4; j 9f }\n" \ - ".section __ex_table,\"a\"\n" \ - ".align 4\n" \ - ".word 1b, 0b\n" \ - ".word 2b, 0b\n" \ - ".popsection\n" \ - "9:" \ - : "=r" (ret), "=r" (__a), "=&r" (__b) \ - : "r" (ptr), "i" (-EFAULT)); \ - (x) = (__force __typeof(x))(__inttype(x)) \ - (((u64)__hi32(__a, __b) << 32) | \ - __lo32(__a, __b)); \ - }) -#endif - -extern int __get_user_bad(void) - __attribute__((warning("sizeof __get_user argument not 1, 2, 4 or 8"))); - -/** - * __get_user: - Get a simple variable from user space, with less checking. - * @x: Variable to store result. - * @ptr: Source address, in user space. - * - * Context: User context only. This function may sleep if pagefaults are - * enabled. - * - * This macro copies a single simple variable from user space to kernel - * space. It supports simple types like char and int, but not larger - * data types like structures or arrays. - * - * @ptr must have pointer-to-simple-variable type, and the result of - * dereferencing @ptr must be assignable to @x without a cast. - * - * Returns zero on success, or -EFAULT on error. - * On error, the variable @x is set to zero. - * - * Caller must check the pointer with access_ok() before calling this - * function. - */ -#define __get_user(x, ptr) \ - ({ \ - int __ret; \ - typeof(x) _x; \ - __chk_user_ptr(ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: __get_user_1(_x, ptr, __ret); break; \ - case 2: __get_user_2(_x, ptr, __ret); break; \ - case 4: __get_user_4(_x, ptr, __ret); break; \ - case 8: __get_user_8(_x, ptr, __ret); break; \ - default: __ret = __get_user_bad(); break; \ - } \ - (x) = (typeof(*(ptr))) _x; \ - __ret; \ - }) - -/* Support macros for __put_user(). */ - -#define __put_user_asm(OP, x, ptr, ret) \ - asm volatile("1: {" #OP " %1, %2; movei %0, 0 }\n" \ - ".pushsection .fixup,\"ax\"\n" \ - "0: { movei %0, %3; j 9f }\n" \ - ".section __ex_table,\"a\"\n" \ - _ASM_ALIGN "\n" \ - _ASM_PTR " 1b, 0b\n" \ - ".popsection\n" \ - "9:" \ - : "=r" (ret) \ - : "r" (ptr), "r" (x), "i" (-EFAULT)) - -#ifdef __tilegx__ -#define __put_user_1(x, ptr, ret) __put_user_asm(st1, x, ptr, ret) -#define __put_user_2(x, ptr, ret) __put_user_asm(st2, x, ptr, ret) -#define __put_user_4(x, ptr, ret) __put_user_asm(st4, x, ptr, ret) -#define __put_user_8(x, ptr, ret) __put_user_asm(st, x, ptr, ret) -#else -#define __put_user_1(x, ptr, ret) __put_user_asm(sb, x, ptr, ret) -#define __put_user_2(x, ptr, ret) __put_user_asm(sh, x, ptr, ret) -#define __put_user_4(x, ptr, ret) __put_user_asm(sw, x, ptr, ret) -#define __put_user_8(x, ptr, ret) \ - ({ \ - u64 __x = (__force __inttype(x))(x); \ - int __lo = (int) __x, __hi = (int) (__x >> 32); \ - asm volatile("1: { sw %1, %2; addi %0, %1, 4 }\n" \ - "2: { sw %0, %3; movei %0, 0 }\n" \ - ".pushsection .fixup,\"ax\"\n" \ - "0: { movei %0, %4; j 9f }\n" \ - ".section __ex_table,\"a\"\n" \ - ".align 4\n" \ - ".word 1b, 0b\n" \ - ".word 2b, 0b\n" \ - ".popsection\n" \ - "9:" \ - : "=&r" (ret) \ - : "r" (ptr), "r" (__lo32(__lo, __hi)), \ - "r" (__hi32(__lo, __hi)), "i" (-EFAULT)); \ - }) -#endif - -extern int __put_user_bad(void) - __attribute__((warning("sizeof __put_user argument not 1, 2, 4 or 8"))); - -/** - * __put_user: - Write a simple value into user space, with less checking. - * @x: Value to copy to user space. - * @ptr: Destination address, in user space. - * - * Context: User context only. This function may sleep if pagefaults are - * enabled. - * - * This macro copies a single simple value from kernel space to user - * space. It supports simple types like char and int, but not larger - * data types like structures or arrays. - * - * @ptr must have pointer-to-simple-variable type, and @x must be assignable - * to the result of dereferencing @ptr. - * - * Caller must check the pointer with access_ok() before calling this - * function. - * - * Returns zero on success, or -EFAULT on error. - */ -#define __put_user(x, ptr) \ -({ \ - int __ret; \ - typeof(*(ptr)) _x = (x); \ - __chk_user_ptr(ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: __put_user_1(_x, ptr, __ret); break; \ - case 2: __put_user_2(_x, ptr, __ret); break; \ - case 4: __put_user_4(_x, ptr, __ret); break; \ - case 8: __put_user_8(_x, ptr, __ret); break; \ - default: __ret = __put_user_bad(); break; \ - } \ - __ret; \ -}) - -/* - * The versions of get_user and put_user without initial underscores - * check the address of their arguments to make sure they are not - * in kernel space. - */ -#define put_user(x, ptr) \ -({ \ - __typeof__(*(ptr)) __user *__Pu_addr = (ptr); \ - access_ok(VERIFY_WRITE, (__Pu_addr), sizeof(*(__Pu_addr))) ? \ - __put_user((x), (__Pu_addr)) : \ - -EFAULT; \ -}) - -#define get_user(x, ptr) \ -({ \ - __typeof__(*(ptr)) const __user *__Gu_addr = (ptr); \ - access_ok(VERIFY_READ, (__Gu_addr), sizeof(*(__Gu_addr))) ? \ - __get_user((x), (__Gu_addr)) : \ - ((x) = 0, -EFAULT); \ -}) - -extern unsigned long __must_check -raw_copy_to_user(void __user *to, const void *from, unsigned long n); -extern unsigned long __must_check -raw_copy_from_user(void *to, const void __user *from, unsigned long n); -#define INLINE_COPY_FROM_USER -#define INLINE_COPY_TO_USER - -#ifdef __tilegx__ -extern unsigned long raw_copy_in_user( - void __user *to, const void __user *from, unsigned long n); -#endif - - -extern long strnlen_user(const char __user *str, long n); -extern long strncpy_from_user(char *dst, const char __user *src, long); - -/** - * clear_user: - Zero a block of memory in user space. - * @mem: Destination address, in user space. - * @len: Number of bytes to zero. - * - * Zero a block of memory in user space. - * - * Returns number of bytes that could not be cleared. - * On success, this will be zero. - */ -extern unsigned long clear_user_asm(void __user *mem, unsigned long len); -static inline unsigned long __must_check __clear_user( - void __user *mem, unsigned long len) -{ - might_fault(); - return clear_user_asm(mem, len); -} -static inline unsigned long __must_check clear_user( - void __user *mem, unsigned long len) -{ - if (access_ok(VERIFY_WRITE, mem, len)) - return __clear_user(mem, len); - return len; -} - -/** - * flush_user: - Flush a block of memory in user space from cache. - * @mem: Destination address, in user space. - * @len: Number of bytes to flush. - * - * Returns number of bytes that could not be flushed. - * On success, this will be zero. - */ -extern unsigned long flush_user_asm(void __user *mem, unsigned long len); -static inline unsigned long __must_check __flush_user( - void __user *mem, unsigned long len) -{ - int retval; - - might_fault(); - retval = flush_user_asm(mem, len); - mb_incoherent(); - return retval; -} - -static inline unsigned long __must_check flush_user( - void __user *mem, unsigned long len) -{ - if (access_ok(VERIFY_WRITE, mem, len)) - return __flush_user(mem, len); - return len; -} - -/** - * finv_user: - Flush-inval a block of memory in user space from cache. - * @mem: Destination address, in user space. - * @len: Number of bytes to invalidate. - * - * Returns number of bytes that could not be flush-invalidated. - * On success, this will be zero. - */ -extern unsigned long finv_user_asm(void __user *mem, unsigned long len); -static inline unsigned long __must_check __finv_user( - void __user *mem, unsigned long len) -{ - int retval; - - might_fault(); - retval = finv_user_asm(mem, len); - mb_incoherent(); - return retval; -} -static inline unsigned long __must_check finv_user( - void __user *mem, unsigned long len) -{ - if (access_ok(VERIFY_WRITE, mem, len)) - return __finv_user(mem, len); - return len; -} - -#endif /* _ASM_TILE_UACCESS_H */ diff --git a/arch/tile/include/asm/unaligned.h b/arch/tile/include/asm/unaligned.h deleted file mode 100644 index 5a58a0d11449..000000000000 --- a/arch/tile/include/asm/unaligned.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_UNALIGNED_H -#define _ASM_TILE_UNALIGNED_H - -/* - * We could implement faster get_unaligned_[be/le]64 using the ldna - * instruction on tilegx; however, we need to either copy all of the - * other generic functions to here (which is pretty ugly) or else - * modify both the generic code and other arch code to allow arch - * specific unaligned data access functions. Given these functions - * are not often called, we'll stick with the generic version. - */ -#include - -/* - * Is the kernel doing fixups of unaligned accesses? If <0, no kernel - * intervention occurs and SIGBUS is delivered with no data address - * info. If 0, the kernel single-steps the instruction to discover - * the data address to provide with the SIGBUS. If 1, the kernel does - * a fixup. - */ -extern int unaligned_fixup; - -/* Is the kernel printing on each unaligned fixup? */ -extern int unaligned_printk; - -/* Number of unaligned fixups performed */ -extern unsigned int unaligned_fixup_count; - -#endif /* _ASM_TILE_UNALIGNED_H */ diff --git a/arch/tile/include/asm/unistd.h b/arch/tile/include/asm/unistd.h deleted file mode 100644 index 940831fe9e94..000000000000 --- a/arch/tile/include/asm/unistd.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ -/* In compat mode, we use sys_llseek() for compat_sys_llseek(). */ -#ifdef CONFIG_COMPAT -#define __ARCH_WANT_SYS_LLSEEK -#endif -#define __ARCH_WANT_SYS_NEWFSTATAT -#define __ARCH_WANT_SYS_CLONE -#include diff --git a/arch/tile/include/asm/user.h b/arch/tile/include/asm/user.h deleted file mode 100644 index cbc8b4d5a5ce..000000000000 --- a/arch/tile/include/asm/user.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - */ - -#ifndef _ASM_TILE_USER_H -#define _ASM_TILE_USER_H - -/* This header is for a.out file formats, which TILE does not support. */ - -#endif /* _ASM_TILE_USER_H */ diff --git a/arch/tile/include/asm/vdso.h b/arch/tile/include/asm/vdso.h deleted file mode 100644 index 9b069692153f..000000000000 --- a/arch/tile/include/asm/vdso.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef __TILE_VDSO_H__ -#define __TILE_VDSO_H__ - -#include -#include - -/* - * Note about the vdso_data structure: - * - * NEVER USE THEM IN USERSPACE CODE DIRECTLY. The layout of the - * structure is supposed to be known only to the function in the vdso - * itself and may change without notice. - */ - -struct vdso_data { - seqcount_t tz_seq; /* Timezone seqlock */ - seqcount_t tb_seq; /* Timebase seqlock */ - __u64 cycle_last; /* TOD clock for xtime */ - __u64 mask; /* Cycle mask */ - __u32 mult; /* Cycle to nanosecond multiplier */ - __u32 shift; /* Cycle to nanosecond divisor (power of two) */ - __u64 wall_time_sec; - __u64 wall_time_snsec; - __u64 monotonic_time_sec; - __u64 monotonic_time_snsec; - __u64 wall_time_coarse_sec; - __u64 wall_time_coarse_nsec; - __u64 monotonic_time_coarse_sec; - __u64 monotonic_time_coarse_nsec; - __u32 tz_minuteswest; /* Minutes west of Greenwich */ - __u32 tz_dsttime; /* Type of dst correction */ -}; - -extern struct vdso_data *vdso_data; - -/* __vdso_rt_sigreturn is defined with the addresses in the vdso page. */ -extern void __vdso_rt_sigreturn(void); - -extern int setup_vdso_pages(void); - -#endif /* __TILE_VDSO_H__ */ diff --git a/arch/tile/include/asm/vga.h b/arch/tile/include/asm/vga.h deleted file mode 100644 index 7b46e754d611..000000000000 --- a/arch/tile/include/asm/vga.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Access to VGA videoram. - */ - -#ifndef _ASM_TILE_VGA_H -#define _ASM_TILE_VGA_H - -#include - -#define VT_BUF_HAVE_RW - -static inline void scr_writew(u16 val, volatile u16 *addr) -{ - __raw_writew(val, (volatile u16 __iomem *) addr); -} - -static inline u16 scr_readw(volatile const u16 *addr) -{ - return __raw_readw((volatile const u16 __iomem *) addr); -} - -#define vga_readb(a) readb((u8 __iomem *)(a)) -#define vga_writeb(v,a) writeb(v, (u8 __iomem *)(a)) - -#define VGA_MAP_MEM(x,s) ((unsigned long) ioremap(x, s)) - -#endif diff --git a/arch/tile/include/asm/word-at-a-time.h b/arch/tile/include/asm/word-at-a-time.h deleted file mode 100644 index 2f2515867760..000000000000 --- a/arch/tile/include/asm/word-at-a-time.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _ASM_WORD_AT_A_TIME_H -#define _ASM_WORD_AT_A_TIME_H - -#include - -struct word_at_a_time { /* unused */ }; -#define WORD_AT_A_TIME_CONSTANTS {} - -/* Generate 0x01 byte values for zero bytes using a SIMD instruction. */ -static inline unsigned long has_zero(unsigned long val, unsigned long *data, - const struct word_at_a_time *c) -{ -#ifdef __tilegx__ - unsigned long mask = __insn_v1cmpeqi(val, 0); -#else /* tilepro */ - unsigned long mask = __insn_seqib(val, 0); -#endif - *data = mask; - return mask; -} - -/* These operations are both nops. */ -#define prep_zero_mask(val, data, c) (data) -#define create_zero_mask(data) (data) - -/* And this operation just depends on endianness. */ -static inline long find_zero(unsigned long mask) -{ -#ifdef __BIG_ENDIAN - return __builtin_clzl(mask) >> 3; -#else - return __builtin_ctzl(mask) >> 3; -#endif -} - -#ifdef __BIG_ENDIAN -#define zero_bytemask(mask) (~1ul << (63 - __builtin_clzl(mask))) -#else -#define zero_bytemask(mask) ((2ul << __builtin_ctzl(mask)) - 1) -#endif - -#endif /* _ASM_WORD_AT_A_TIME_H */ diff --git a/arch/tile/include/gxio/common.h b/arch/tile/include/gxio/common.h deleted file mode 100644 index 724595a24d04..000000000000 --- a/arch/tile/include/gxio/common.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _GXIO_COMMON_H_ -#define _GXIO_COMMON_H_ - -/* - * Routines shared between the various GXIO device components. - */ - -#include - -#include -#include -#include - -/* Define the standard gxio MMIO functions using kernel functions. */ -#define __gxio_mmio_read8(addr) readb(addr) -#define __gxio_mmio_read16(addr) readw(addr) -#define __gxio_mmio_read32(addr) readl(addr) -#define __gxio_mmio_read64(addr) readq(addr) -#define __gxio_mmio_write8(addr, val) writeb((val), (addr)) -#define __gxio_mmio_write16(addr, val) writew((val), (addr)) -#define __gxio_mmio_write32(addr, val) writel((val), (addr)) -#define __gxio_mmio_write64(addr, val) writeq((val), (addr)) -#define __gxio_mmio_read(addr) __gxio_mmio_read64(addr) -#define __gxio_mmio_write(addr, val) __gxio_mmio_write64((addr), (val)) - -#endif /* !_GXIO_COMMON_H_ */ diff --git a/arch/tile/include/gxio/dma_queue.h b/arch/tile/include/gxio/dma_queue.h deleted file mode 100644 index c8fd47edba30..000000000000 --- a/arch/tile/include/gxio/dma_queue.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _GXIO_DMA_QUEUE_H_ -#define _GXIO_DMA_QUEUE_H_ - -/* - * DMA queue management APIs shared between TRIO and mPIPE. - */ - -#include - -/* The credit counter lives in the high 32 bits. */ -#define DMA_QUEUE_CREDIT_SHIFT 32 - -/* - * State object that tracks a DMA queue's head and tail indices, as - * well as the number of commands posted and completed. The - * structure is accessed via a thread-safe, lock-free algorithm. - */ -typedef struct { - /* - * Address of a MPIPE_EDMA_POST_REGION_VAL_t, - * TRIO_PUSH_DMA_REGION_VAL_t, or TRIO_PULL_DMA_REGION_VAL_t - * register. These register have identical encodings and provide - * information about how many commands have been processed. - */ - void *post_region_addr; - - /* - * A lazily-updated count of how many edescs the hardware has - * completed. - */ - uint64_t hw_complete_count __attribute__ ((aligned(64))); - - /* - * High 32 bits are a count of available egress command credits, - * low 24 bits are the next egress "slot". - */ - int64_t credits_and_next_index; - -} __gxio_dma_queue_t; - -/* Initialize a dma queue. */ -extern void __gxio_dma_queue_init(__gxio_dma_queue_t *dma_queue, - void *post_region_addr, - unsigned int num_entries); - -/* - * Update the "credits_and_next_index" and "hw_complete_count" fields - * based on pending hardware completions. Note that some other thread - * may have already done this and, importantly, may still be in the - * process of updating "credits_and_next_index". - */ -extern void __gxio_dma_queue_update_credits(__gxio_dma_queue_t *dma_queue); - -/* Wait for credits to become available. */ -extern int64_t __gxio_dma_queue_wait_for_credits(__gxio_dma_queue_t *dma_queue, - int64_t modifier); - -/* Reserve slots in the queue, optionally waiting for slots to become - * available, and optionally returning a "completion_slot" suitable for - * direct comparison to "hw_complete_count". - */ -static inline int64_t __gxio_dma_queue_reserve(__gxio_dma_queue_t *dma_queue, - unsigned int num, bool wait, - bool completion) -{ - uint64_t slot; - - /* - * Try to reserve 'num' egress command slots. We do this by - * constructing a constant that subtracts N credits and adds N to - * the index, and using fetchaddgez to only apply it if the credits - * count doesn't go negative. - */ - int64_t modifier = (((int64_t)(-num)) << DMA_QUEUE_CREDIT_SHIFT) | num; - int64_t old = - __insn_fetchaddgez(&dma_queue->credits_and_next_index, - modifier); - - if (unlikely(old + modifier < 0)) { - /* - * We're out of credits. Try once to get more by checking for - * completed egress commands. If that fails, wait or fail. - */ - __gxio_dma_queue_update_credits(dma_queue); - old = __insn_fetchaddgez(&dma_queue->credits_and_next_index, - modifier); - if (old + modifier < 0) { - if (wait) - old = __gxio_dma_queue_wait_for_credits - (dma_queue, modifier); - else - return GXIO_ERR_DMA_CREDITS; - } - } - - /* The bottom 24 bits of old encode the "slot". */ - slot = (old & 0xffffff); - - if (completion) { - /* - * A "completion_slot" is a "slot" which can be compared to - * "hw_complete_count" at any time in the future. To convert - * "slot" into a "completion_slot", we access "hw_complete_count" - * once (knowing that we have reserved a slot, and thus, it will - * be "basically" accurate), and combine its high 40 bits with - * the 24 bit "slot", and handle "wrapping" by adding "1 << 24" - * if the result is LESS than "hw_complete_count". - */ - uint64_t complete; - complete = READ_ONCE(dma_queue->hw_complete_count); - slot |= (complete & 0xffffffffff000000); - if (slot < complete) - slot += 0x1000000; - } - - /* - * If any of our slots mod 256 were equivalent to 0, go ahead and - * collect some egress credits, and update "hw_complete_count", and - * make sure the index doesn't overflow into the credits. - */ - if (unlikely(((old + num) & 0xff) < num)) { - __gxio_dma_queue_update_credits(dma_queue); - - /* Make sure the index doesn't overflow into the credits. */ -#ifdef __BIG_ENDIAN__ - *(((uint8_t *)&dma_queue->credits_and_next_index) + 4) = 0; -#else - *(((uint8_t *)&dma_queue->credits_and_next_index) + 3) = 0; -#endif - } - - return slot; -} - -/* Non-inlinable "__gxio_dma_queue_reserve(..., true)". */ -extern int64_t __gxio_dma_queue_reserve_aux(__gxio_dma_queue_t *dma_queue, - unsigned int num, int wait); - -/* Check whether a particular "completion slot" has completed. - * - * Note that this function requires a "completion slot", and thus - * cannot be used with the result of any "reserve_fast" function. - */ -extern int __gxio_dma_queue_is_complete(__gxio_dma_queue_t *dma_queue, - int64_t completion_slot, int update); - -#endif /* !_GXIO_DMA_QUEUE_H_ */ diff --git a/arch/tile/include/gxio/iorpc_globals.h b/arch/tile/include/gxio/iorpc_globals.h deleted file mode 100644 index 52c721f8dad9..000000000000 --- a/arch/tile/include/gxio/iorpc_globals.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#ifndef __IORPC_LINUX_RPC_H__ -#define __IORPC_LINUX_RPC_H__ - -#include - -#include -#include -#include - -#define IORPC_OP_ARM_POLLFD IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9000) -#define IORPC_OP_CLOSE_POLLFD IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9001) -#define IORPC_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000) -#define IORPC_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001) - -int __iorpc_arm_pollfd(int fd, int pollfd_cookie); - -int __iorpc_close_pollfd(int fd, int pollfd_cookie); - -int __iorpc_get_mmio_base(int fd, HV_PTE *base); - -int __iorpc_check_mmio_offset(int fd, unsigned long offset, unsigned long size); - -#endif /* !__IORPC_LINUX_RPC_H__ */ diff --git a/arch/tile/include/gxio/iorpc_mpipe.h b/arch/tile/include/gxio/iorpc_mpipe.h deleted file mode 100644 index 4cda03de734f..000000000000 --- a/arch/tile/include/gxio/iorpc_mpipe.h +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#ifndef __GXIO_MPIPE_LINUX_RPC_H__ -#define __GXIO_MPIPE_LINUX_RPC_H__ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#define GXIO_MPIPE_OP_ALLOC_BUFFER_STACKS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1200) -#define GXIO_MPIPE_OP_INIT_BUFFER_STACK_AUX IORPC_OPCODE(IORPC_FORMAT_KERNEL_MEM, 0x1201) - -#define GXIO_MPIPE_OP_ALLOC_NOTIF_RINGS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1203) -#define GXIO_MPIPE_OP_INIT_NOTIF_RING_AUX IORPC_OPCODE(IORPC_FORMAT_KERNEL_MEM, 0x1204) -#define GXIO_MPIPE_OP_REQUEST_NOTIF_RING_INTERRUPT IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1205) -#define GXIO_MPIPE_OP_ENABLE_NOTIF_RING_INTERRUPT IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1206) -#define GXIO_MPIPE_OP_ALLOC_NOTIF_GROUPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1207) -#define GXIO_MPIPE_OP_INIT_NOTIF_GROUP IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1208) -#define GXIO_MPIPE_OP_ALLOC_BUCKETS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1209) -#define GXIO_MPIPE_OP_INIT_BUCKET IORPC_OPCODE(IORPC_FORMAT_NONE, 0x120a) -#define GXIO_MPIPE_OP_ALLOC_EDMA_RINGS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x120b) -#define GXIO_MPIPE_OP_INIT_EDMA_RING_AUX IORPC_OPCODE(IORPC_FORMAT_KERNEL_MEM, 0x120c) - -#define GXIO_MPIPE_OP_COMMIT_RULES IORPC_OPCODE(IORPC_FORMAT_NONE, 0x120f) -#define GXIO_MPIPE_OP_REGISTER_CLIENT_MEMORY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1210) -#define GXIO_MPIPE_OP_LINK_OPEN_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1211) -#define GXIO_MPIPE_OP_LINK_CLOSE_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1212) -#define GXIO_MPIPE_OP_LINK_SET_ATTR_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1213) - -#define GXIO_MPIPE_OP_GET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x121e) -#define GXIO_MPIPE_OP_SET_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x121f) -#define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1220) -#define GXIO_MPIPE_OP_CONFIG_EDMA_RING_BLKS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1221) -#define GXIO_MPIPE_OP_ADJUST_TIMESTAMP_FREQ IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1222) -#define GXIO_MPIPE_OP_ARM_POLLFD IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9000) -#define GXIO_MPIPE_OP_CLOSE_POLLFD IORPC_OPCODE(IORPC_FORMAT_KERNEL_POLLFD, 0x9001) -#define GXIO_MPIPE_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000) -#define GXIO_MPIPE_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001) - -int gxio_mpipe_alloc_buffer_stacks(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - -int gxio_mpipe_init_buffer_stack_aux(gxio_mpipe_context_t *context, - void *mem_va, size_t mem_size, - unsigned int mem_flags, unsigned int stack, - unsigned int buffer_size_enum); - - -int gxio_mpipe_alloc_notif_rings(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - -int gxio_mpipe_init_notif_ring_aux(gxio_mpipe_context_t *context, void *mem_va, - size_t mem_size, unsigned int mem_flags, - unsigned int ring); - -int gxio_mpipe_request_notif_ring_interrupt(gxio_mpipe_context_t *context, - int inter_x, int inter_y, - int inter_ipi, int inter_event, - unsigned int ring); - -int gxio_mpipe_enable_notif_ring_interrupt(gxio_mpipe_context_t *context, - unsigned int ring); - -int gxio_mpipe_alloc_notif_groups(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - -int gxio_mpipe_init_notif_group(gxio_mpipe_context_t *context, - unsigned int group, - gxio_mpipe_notif_group_bits_t bits); - -int gxio_mpipe_alloc_buckets(gxio_mpipe_context_t *context, unsigned int count, - unsigned int first, unsigned int flags); - -int gxio_mpipe_init_bucket(gxio_mpipe_context_t *context, unsigned int bucket, - MPIPE_LBL_INIT_DAT_BSTS_TBL_t bucket_info); - -int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - -int gxio_mpipe_init_edma_ring_aux(gxio_mpipe_context_t *context, void *mem_va, - size_t mem_size, unsigned int mem_flags, - unsigned int ring, unsigned int channel); - - -int gxio_mpipe_commit_rules(gxio_mpipe_context_t *context, const void *blob, - size_t blob_size); - -int gxio_mpipe_register_client_memory(gxio_mpipe_context_t *context, - unsigned int iotlb, HV_PTE pte, - unsigned int flags); - -int gxio_mpipe_link_open_aux(gxio_mpipe_context_t *context, - _gxio_mpipe_link_name_t name, unsigned int flags); - -int gxio_mpipe_link_close_aux(gxio_mpipe_context_t *context, int mac); - -int gxio_mpipe_link_set_attr_aux(gxio_mpipe_context_t *context, int mac, - uint32_t attr, int64_t val); - -int gxio_mpipe_get_timestamp_aux(gxio_mpipe_context_t *context, uint64_t *sec, - uint64_t *nsec, uint64_t *cycles); - -int gxio_mpipe_set_timestamp_aux(gxio_mpipe_context_t *context, uint64_t sec, - uint64_t nsec, uint64_t cycles); - -int gxio_mpipe_adjust_timestamp_aux(gxio_mpipe_context_t *context, - int64_t nsec); - -int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t *context, - int32_t ppb); - -int gxio_mpipe_arm_pollfd(gxio_mpipe_context_t *context, int pollfd_cookie); - -int gxio_mpipe_close_pollfd(gxio_mpipe_context_t *context, int pollfd_cookie); - -int gxio_mpipe_get_mmio_base(gxio_mpipe_context_t *context, HV_PTE *base); - -int gxio_mpipe_check_mmio_offset(gxio_mpipe_context_t *context, - unsigned long offset, unsigned long size); - -#endif /* !__GXIO_MPIPE_LINUX_RPC_H__ */ diff --git a/arch/tile/include/gxio/iorpc_mpipe_info.h b/arch/tile/include/gxio/iorpc_mpipe_info.h deleted file mode 100644 index f0b04284468b..000000000000 --- a/arch/tile/include/gxio/iorpc_mpipe_info.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#ifndef __GXIO_MPIPE_INFO_LINUX_RPC_H__ -#define __GXIO_MPIPE_INFO_LINUX_RPC_H__ - -#include - -#include -#include -#include -#include -#include -#include -#include - - -#define GXIO_MPIPE_INFO_OP_INSTANCE_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1250) -#define GXIO_MPIPE_INFO_OP_ENUMERATE_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1251) -#define GXIO_MPIPE_INFO_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000) -#define GXIO_MPIPE_INFO_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001) - - -int gxio_mpipe_info_instance_aux(gxio_mpipe_info_context_t *context, - _gxio_mpipe_link_name_t name); - -int gxio_mpipe_info_enumerate_aux(gxio_mpipe_info_context_t *context, - unsigned int idx, - _gxio_mpipe_link_name_t *name, - _gxio_mpipe_link_mac_t *mac); - -int gxio_mpipe_info_get_mmio_base(gxio_mpipe_info_context_t *context, - HV_PTE *base); - -int gxio_mpipe_info_check_mmio_offset(gxio_mpipe_info_context_t *context, - unsigned long offset, unsigned long size); - -#endif /* !__GXIO_MPIPE_INFO_LINUX_RPC_H__ */ diff --git a/arch/tile/include/gxio/iorpc_trio.h b/arch/tile/include/gxio/iorpc_trio.h deleted file mode 100644 index 376a4f771167..000000000000 --- a/arch/tile/include/gxio/iorpc_trio.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#ifndef __GXIO_TRIO_LINUX_RPC_H__ -#define __GXIO_TRIO_LINUX_RPC_H__ - -#include - -#include -#include -#include -#include -#include -#include - -#define GXIO_TRIO_OP_DEALLOC_ASID IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1400) -#define GXIO_TRIO_OP_ALLOC_ASIDS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1401) - -#define GXIO_TRIO_OP_ALLOC_MEMORY_MAPS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1404) - -#define GXIO_TRIO_OP_ALLOC_SCATTER_QUEUES IORPC_OPCODE(IORPC_FORMAT_NONE, 0x140e) -#define GXIO_TRIO_OP_ALLOC_PIO_REGIONS IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1412) - -#define GXIO_TRIO_OP_INIT_PIO_REGION_AUX IORPC_OPCODE(IORPC_FORMAT_NONE, 0x1414) - -#define GXIO_TRIO_OP_INIT_MEMORY_MAP_MMU_AUX IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141e) -#define GXIO_TRIO_OP_GET_PORT_PROPERTY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x141f) -#define GXIO_TRIO_OP_CONFIG_LEGACY_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1420) -#define GXIO_TRIO_OP_CONFIG_MSI_INTR IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1421) - -#define GXIO_TRIO_OP_SET_MPS_MRS IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1423) -#define GXIO_TRIO_OP_FORCE_RC_LINK_UP IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1424) -#define GXIO_TRIO_OP_FORCE_EP_LINK_UP IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1425) -#define GXIO_TRIO_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000) -#define GXIO_TRIO_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001) - -int gxio_trio_alloc_asids(gxio_trio_context_t *context, unsigned int count, - unsigned int first, unsigned int flags); - - -int gxio_trio_alloc_memory_maps(gxio_trio_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - - -int gxio_trio_alloc_scatter_queues(gxio_trio_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - -int gxio_trio_alloc_pio_regions(gxio_trio_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - -int gxio_trio_init_pio_region_aux(gxio_trio_context_t *context, - unsigned int pio_region, unsigned int mac, - uint32_t bus_address_hi, unsigned int flags); - - -int gxio_trio_init_memory_map_mmu_aux(gxio_trio_context_t *context, - unsigned int map, unsigned long va, - uint64_t size, unsigned int asid, - unsigned int mac, uint64_t bus_address, - unsigned int node, - unsigned int order_mode); - -int gxio_trio_get_port_property(gxio_trio_context_t *context, - struct pcie_trio_ports_property *trio_ports); - -int gxio_trio_config_legacy_intr(gxio_trio_context_t *context, int inter_x, - int inter_y, int inter_ipi, int inter_event, - unsigned int mac, unsigned int intx); - -int gxio_trio_config_msi_intr(gxio_trio_context_t *context, int inter_x, - int inter_y, int inter_ipi, int inter_event, - unsigned int mac, unsigned int mem_map, - uint64_t mem_map_base, uint64_t mem_map_limit, - unsigned int asid); - - -int gxio_trio_set_mps_mrs(gxio_trio_context_t *context, uint16_t mps, - uint16_t mrs, unsigned int mac); - -int gxio_trio_force_rc_link_up(gxio_trio_context_t *context, unsigned int mac); - -int gxio_trio_force_ep_link_up(gxio_trio_context_t *context, unsigned int mac); - -int gxio_trio_get_mmio_base(gxio_trio_context_t *context, HV_PTE *base); - -int gxio_trio_check_mmio_offset(gxio_trio_context_t *context, - unsigned long offset, unsigned long size); - -#endif /* !__GXIO_TRIO_LINUX_RPC_H__ */ diff --git a/arch/tile/include/gxio/iorpc_uart.h b/arch/tile/include/gxio/iorpc_uart.h deleted file mode 100644 index 55429d48ea56..000000000000 --- a/arch/tile/include/gxio/iorpc_uart.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#ifndef __GXIO_UART_LINUX_RPC_H__ -#define __GXIO_UART_LINUX_RPC_H__ - -#include - -#include -#include -#include -#include -#include -#include - -#define GXIO_UART_OP_CFG_INTERRUPT IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1900) -#define GXIO_UART_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000) -#define GXIO_UART_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001) - -int gxio_uart_cfg_interrupt(gxio_uart_context_t *context, int inter_x, - int inter_y, int inter_ipi, int inter_event); - -int gxio_uart_get_mmio_base(gxio_uart_context_t *context, HV_PTE *base); - -int gxio_uart_check_mmio_offset(gxio_uart_context_t *context, - unsigned long offset, unsigned long size); - -#endif /* !__GXIO_UART_LINUX_RPC_H__ */ diff --git a/arch/tile/include/gxio/iorpc_usb_host.h b/arch/tile/include/gxio/iorpc_usb_host.h deleted file mode 100644 index 79962a97de8e..000000000000 --- a/arch/tile/include/gxio/iorpc_usb_host.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* This file is machine-generated; DO NOT EDIT! */ -#ifndef __GXIO_USB_HOST_LINUX_RPC_H__ -#define __GXIO_USB_HOST_LINUX_RPC_H__ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#define GXIO_USB_HOST_OP_CFG_INTERRUPT IORPC_OPCODE(IORPC_FORMAT_KERNEL_INTERRUPT, 0x1800) -#define GXIO_USB_HOST_OP_REGISTER_CLIENT_MEMORY IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x1801) -#define GXIO_USB_HOST_OP_GET_MMIO_BASE IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8000) -#define GXIO_USB_HOST_OP_CHECK_MMIO_OFFSET IORPC_OPCODE(IORPC_FORMAT_NONE_NOUSER, 0x8001) - -int gxio_usb_host_cfg_interrupt(gxio_usb_host_context_t *context, int inter_x, - int inter_y, int inter_ipi, int inter_event); - -int gxio_usb_host_register_client_memory(gxio_usb_host_context_t *context, - HV_PTE pte, unsigned int flags); - -int gxio_usb_host_get_mmio_base(gxio_usb_host_context_t *context, - HV_PTE *base); - -int gxio_usb_host_check_mmio_offset(gxio_usb_host_context_t *context, - unsigned long offset, unsigned long size); - -#endif /* !__GXIO_USB_HOST_LINUX_RPC_H__ */ diff --git a/arch/tile/include/gxio/kiorpc.h b/arch/tile/include/gxio/kiorpc.h deleted file mode 100644 index ee5820979ff3..000000000000 --- a/arch/tile/include/gxio/kiorpc.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Support routines for kernel IORPC drivers. - */ - -#ifndef _GXIO_KIORPC_H -#define _GXIO_KIORPC_H - -#include -#include -#include - -#if CHIP_HAS_MMIO() -void __iomem *iorpc_ioremap(int hv_fd, resource_size_t offset, - unsigned long size); -#endif - -#endif /* _GXIO_KIORPC_H */ diff --git a/arch/tile/include/gxio/mpipe.h b/arch/tile/include/gxio/mpipe.h deleted file mode 100644 index 73e83a187866..000000000000 --- a/arch/tile/include/gxio/mpipe.h +++ /dev/null @@ -1,1871 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _GXIO_MPIPE_H_ -#define _GXIO_MPIPE_H_ - -/* - * - * An API for allocating, configuring, and manipulating mPIPE hardware - * resources. - */ - -#include -#include - -#include - -#include -#include - -#include -#include - -/* - * - * The TILE-Gx mPIPE&tm; shim provides Ethernet connectivity, packet - * classification, and packet load balancing services. The - * gxio_mpipe_ API, declared in , allows applications to - * allocate mPIPE IO channels, configure packet distribution - * parameters, and send and receive Ethernet packets. The API is - * designed to be a minimal wrapper around the mPIPE hardware, making - * system calls only where necessary to preserve inter-process - * protection guarantees. - * - * The APIs described below allow the programmer to allocate and - * configure mPIPE resources. As described below, the mPIPE is a - * single shared hardware device that provides partitionable resources - * that are shared between all applications in the system. The - * gxio_mpipe_ API allows userspace code to make resource request - * calls to the hypervisor, which in turns keeps track of the - * resources in use by all applications, maintains protection - * guarantees, and resets resources upon application shutdown. - * - * We strongly recommend reading the mPIPE section of the IO Device - * Guide (UG404) before working with this API. Most functions in the - * gxio_mpipe_ API are directly analogous to hardware interfaces and - * the documentation assumes that the reader understands those - * hardware interfaces. - * - * @section mpipe__ingress mPIPE Ingress Hardware Resources - * - * The mPIPE ingress hardware provides extensive hardware offload for - * tasks like packet header parsing, load balancing, and memory - * management. This section provides a brief introduction to the - * hardware components and the gxio_mpipe_ calls used to manage them; - * see the IO Device Guide for a much more detailed description of the - * mPIPE's capabilities. - * - * When a packet arrives at one of the mPIPE's Ethernet MACs, it is - * assigned a channel number indicating which MAC received it. It - * then proceeds through the following hardware pipeline: - * - * @subsection mpipe__classification Classification - * - * A set of classification processors run header parsing code on each - * incoming packet, extracting information including the destination - * MAC address, VLAN, Ethernet type, and five-tuple hash. Some of - * this information is then used to choose which buffer stack will be - * used to hold the packet, and which bucket will be used by the load - * balancer to determine which application will receive the packet. - * - * The rules by which the buffer stack and bucket are chosen can be - * configured via the @ref gxio_mpipe_classifier API. A given app can - * specify multiple rules, each one specifying a bucket range, and a - * set of buffer stacks, to be used for packets matching the rule. - * Each rule can optionally specify a restricted set of channels, - * VLANs, and/or dMACs, in which it is interested. By default, a - * given rule starts out matching all channels associated with the - * mPIPE context's set of open links; all VLANs; and all dMACs. - * Subsequent restrictions can then be added. - * - * @subsection mpipe__load_balancing Load Balancing - * - * The mPIPE load balancer is responsible for choosing the NotifRing - * to which the packet will be delivered. This decision is based on - * the bucket number indicated by the classification program. In - * general, the bucket number is based on some number of low bits of - * the packet's flow hash (applications that aren't interested in flow - * hashing use a single bucket). Each load balancer bucket keeps a - * record of the NotifRing to which packets directed to that bucket - * are currently being delivered. Based on the bucket's load - * balancing mode (@ref gxio_mpipe_bucket_mode_t), the load balancer - * either forwards the packet to the previously assigned NotifRing or - * decides to choose a new NotifRing. If a new NotifRing is required, - * the load balancer chooses the least loaded ring in the NotifGroup - * associated with the bucket. - * - * The load balancer is a shared resource. Each application needs to - * explicitly allocate NotifRings, NotifGroups, and buckets, using - * gxio_mpipe_alloc_notif_rings(), gxio_mpipe_alloc_notif_groups(), - * and gxio_mpipe_alloc_buckets(). Then the application needs to - * configure them using gxio_mpipe_init_notif_ring() and - * gxio_mpipe_init_notif_group_and_buckets(). - * - * @subsection mpipe__buffers Buffer Selection and Packet Delivery - * - * Once the load balancer has chosen the destination NotifRing, the - * mPIPE DMA engine pops at least one buffer off of the 'buffer stack' - * chosen by the classification program and DMAs the packet data into - * that buffer. Each buffer stack provides a hardware-accelerated - * stack of data buffers with the same size. If the packet data is - * larger than the buffers provided by the chosen buffer stack, the - * mPIPE hardware pops off multiple buffers and chains the packet data - * through a multi-buffer linked list. Once the packet data is - * delivered to the buffer(s), the mPIPE hardware writes the - * ::gxio_mpipe_idesc_t metadata object (calculated by the classifier) - * into the NotifRing and increments the number of packets delivered - * to that ring. - * - * Applications can push buffers onto a buffer stack by calling - * gxio_mpipe_push_buffer() or by egressing a packet with the - * ::gxio_mpipe_edesc_t::hwb bit set, indicating that the egressed - * buffers should be returned to the stack. - * - * Applications can allocate and initialize buffer stacks with the - * gxio_mpipe_alloc_buffer_stacks() and gxio_mpipe_init_buffer_stack() - * APIs. - * - * The application must also register the memory pages that will hold - * packets. This requires calling gxio_mpipe_register_page() for each - * memory page that will hold packets allocated by the application for - * a given buffer stack. Since each buffer stack is limited to 16 - * registered pages, it may be necessary to use huge pages, or even - * extremely huge pages, to hold all the buffers. - * - * @subsection mpipe__iqueue NotifRings - * - * Each NotifRing is a region of shared memory, allocated by the - * application, to which the mPIPE delivers packet descriptors - * (::gxio_mpipe_idesc_t). The application can allocate them via - * gxio_mpipe_alloc_notif_rings(). The application can then either - * explicitly initialize them with gxio_mpipe_init_notif_ring() and - * then read from them manually, or can make use of the convenience - * wrappers provided by @ref gxio_mpipe_wrappers. - * - * @section mpipe__egress mPIPE Egress Hardware - * - * Applications use eDMA rings to queue packets for egress. The - * application can allocate them via gxio_mpipe_alloc_edma_rings(). - * The application can then either explicitly initialize them with - * gxio_mpipe_init_edma_ring() and then write to them manually, or - * can make use of the convenience wrappers provided by - * @ref gxio_mpipe_wrappers. - * - * @section gxio__shortcomings Plans for Future API Revisions - * - * The API defined here is only an initial version of the mPIPE API. - * Future plans include: - * - * - Higher level wrapper functions to provide common initialization - * patterns. This should help users start writing mPIPE programs - * without having to learn the details of the hardware. - * - * - Support for reset and deallocation of resources, including - * cleanup upon application shutdown. - * - * - Support for calling these APIs in the BME. - * - * - Support for IO interrupts. - * - * - Clearer definitions of thread safety guarantees. - * - * @section gxio__mpipe_examples Examples - * - * See the following mPIPE example programs for more information about - * allocating mPIPE resources and using them in real applications: - * - * - @ref mpipe/ingress/app.c : Receiving packets. - * - * - @ref mpipe/forward/app.c : Forwarding packets. - * - * Note that there are several more examples. - */ - -/* Flags that can be passed to resource allocation functions. */ -enum gxio_mpipe_alloc_flags_e { - /* Require an allocation to start at a specified resource index. */ - GXIO_MPIPE_ALLOC_FIXED = HV_MPIPE_ALLOC_FIXED, -}; - -/* Flags that can be passed to memory registration functions. */ -enum gxio_mpipe_mem_flags_e { - /* Do not fill L3 when writing, and invalidate lines upon egress. */ - GXIO_MPIPE_MEM_FLAG_NT_HINT = IORPC_MEM_BUFFER_FLAG_NT_HINT, - - /* L3 cache fills should only populate IO cache ways. */ - GXIO_MPIPE_MEM_FLAG_IO_PIN = IORPC_MEM_BUFFER_FLAG_IO_PIN, -}; - -/* An ingress packet descriptor. When a packet arrives, the mPIPE - * hardware generates this structure and writes it into a NotifRing. - */ -typedef MPIPE_PDESC_t gxio_mpipe_idesc_t; - -/* An egress command descriptor. Applications write this structure - * into eDMA rings and the hardware performs the indicated operation - * (normally involving egressing some bytes). Note that egressing a - * single packet may involve multiple egress command descriptors. - */ -typedef MPIPE_EDMA_DESC_t gxio_mpipe_edesc_t; - -/* - * Max # of mpipe instances. 2 currently. - */ -#define GXIO_MPIPE_INSTANCE_MAX HV_MPIPE_INSTANCE_MAX - -#define NR_MPIPE_MAX GXIO_MPIPE_INSTANCE_MAX - -/* Get the "va" field from an "idesc". - * - * This is the address at which the ingress hardware copied the first - * byte of the packet. - * - * If the classifier detected a custom header, then this will point to - * the custom header, and gxio_mpipe_idesc_get_l2_start() will point - * to the actual L2 header. - * - * Note that this value may be misleading if "idesc->be" is set. - * - * @param idesc An ingress packet descriptor. - */ -static inline unsigned char *gxio_mpipe_idesc_get_va(gxio_mpipe_idesc_t *idesc) -{ - return (unsigned char *)(long)idesc->va; -} - -/* Get the "xfer_size" from an "idesc". - * - * This is the actual number of packet bytes transferred into memory - * by the hardware. - * - * Note that this value may be misleading if "idesc->be" is set. - * - * @param idesc An ingress packet descriptor. - * - * ISSUE: Is this the best name for this? - * FIXME: Add more docs about chaining, clipping, etc. - */ -static inline unsigned int gxio_mpipe_idesc_get_xfer_size(gxio_mpipe_idesc_t - *idesc) -{ - return idesc->l2_size; -} - -/* Get the "l2_offset" from an "idesc". - * - * Extremely customized classifiers might not support this function. - * - * This is the number of bytes between the "va" and the L2 header. - * - * The L2 header consists of a destination mac address, a source mac - * address, and an initial ethertype. Various initial ethertypes - * allow encoding extra information in the L2 header, often including - * a vlan, and/or a new ethertype. - * - * Note that the "l2_offset" will be non-zero if (and only if) the - * classifier processed a custom header for the packet. - * - * @param idesc An ingress packet descriptor. - */ -static inline uint8_t gxio_mpipe_idesc_get_l2_offset(gxio_mpipe_idesc_t *idesc) -{ - return (idesc->custom1 >> 32) & 0xFF; -} - -/* Get the "l2_start" from an "idesc". - * - * This is simply gxio_mpipe_idesc_get_va() plus - * gxio_mpipe_idesc_get_l2_offset(). - * - * @param idesc An ingress packet descriptor. - */ -static inline unsigned char *gxio_mpipe_idesc_get_l2_start(gxio_mpipe_idesc_t - *idesc) -{ - unsigned char *va = gxio_mpipe_idesc_get_va(idesc); - return va + gxio_mpipe_idesc_get_l2_offset(idesc); -} - -/* Get the "l2_length" from an "idesc". - * - * This is simply gxio_mpipe_idesc_get_xfer_size() minus - * gxio_mpipe_idesc_get_l2_offset(). - * - * @param idesc An ingress packet descriptor. - */ -static inline unsigned int gxio_mpipe_idesc_get_l2_length(gxio_mpipe_idesc_t - *idesc) -{ - unsigned int xfer_size = idesc->l2_size; - return xfer_size - gxio_mpipe_idesc_get_l2_offset(idesc); -} - -/* A context object used to manage mPIPE hardware resources. */ -typedef struct { - - /* File descriptor for calling up to Linux (and thus the HV). */ - int fd; - - /* Corresponding mpipe instance #. */ - int instance; - - /* The VA at which configuration registers are mapped. */ - char *mmio_cfg_base; - - /* The VA at which IDMA, EDMA, and buffer manager are mapped. */ - char *mmio_fast_base; - - /* The "initialized" buffer stacks. */ - gxio_mpipe_rules_stacks_t __stacks; - -} gxio_mpipe_context_t; - -/* This is only used internally, but it's most easily made visible here. */ -typedef gxio_mpipe_context_t gxio_mpipe_info_context_t; - -/* Initialize an mPIPE context. - * - * This function allocates an mPIPE "service domain" and maps the MMIO - * registers into the caller's VA space. - * - * @param context Context object to be initialized. - * @param mpipe_instance Instance number of mPIPE shim to be controlled via - * context. - */ -extern int gxio_mpipe_init(gxio_mpipe_context_t *context, - unsigned int mpipe_instance); - -/* Destroy an mPIPE context. - * - * This function frees the mPIPE "service domain" and unmaps the MMIO - * registers from the caller's VA space. - * - * If a user process exits without calling this routine, the kernel - * will destroy the mPIPE context as part of process teardown. - * - * @param context Context object to be destroyed. - */ -extern int gxio_mpipe_destroy(gxio_mpipe_context_t *context); - -/***************************************************************** - * Buffer Stacks * - ******************************************************************/ - -/* Allocate a set of buffer stacks. - * - * The return value is NOT interesting if count is zero. - * - * @param context An initialized mPIPE context. - * @param count Number of stacks required. - * @param first Index of first stack if ::GXIO_MPIPE_ALLOC_FIXED flag is set, - * otherwise ignored. - * @param flags Flag bits from ::gxio_mpipe_alloc_flags_e. - * @return Index of first allocated buffer stack, or - * ::GXIO_MPIPE_ERR_NO_BUFFER_STACK if allocation failed. - */ -extern int gxio_mpipe_alloc_buffer_stacks(gxio_mpipe_context_t *context, - unsigned int count, - unsigned int first, - unsigned int flags); - -/* Enum codes for buffer sizes supported by mPIPE. */ -typedef enum { - /* 128 byte packet data buffer. */ - GXIO_MPIPE_BUFFER_SIZE_128 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_128, - /* 256 byte packet data buffer. */ - GXIO_MPIPE_BUFFER_SIZE_256 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_256, - /* 512 byte packet data buffer. */ - GXIO_MPIPE_BUFFER_SIZE_512 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_512, - /* 1024 byte packet data buffer. */ - GXIO_MPIPE_BUFFER_SIZE_1024 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_1024, - /* 1664 byte packet data buffer. */ - GXIO_MPIPE_BUFFER_SIZE_1664 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_1664, - /* 4096 byte packet data buffer. */ - GXIO_MPIPE_BUFFER_SIZE_4096 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_4096, - /* 10368 byte packet data buffer. */ - GXIO_MPIPE_BUFFER_SIZE_10368 = - MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_10368, - /* 16384 byte packet data buffer. */ - GXIO_MPIPE_BUFFER_SIZE_16384 = MPIPE_BSM_INIT_DAT_1__SIZE_VAL_BSZ_16384 -} gxio_mpipe_buffer_size_enum_t; - -/* Convert a buffer size in bytes into a buffer size enum. */ -extern gxio_mpipe_buffer_size_enum_t -gxio_mpipe_buffer_size_to_buffer_size_enum(size_t size); - -/* Convert a buffer size enum into a buffer size in bytes. */ -extern size_t -gxio_mpipe_buffer_size_enum_to_buffer_size(gxio_mpipe_buffer_size_enum_t - buffer_size_enum); - -/* Calculate the number of bytes required to store a given number of - * buffers in the memory registered with a buffer stack via - * gxio_mpipe_init_buffer_stack(). - */ -extern size_t gxio_mpipe_calc_buffer_stack_bytes(unsigned long buffers); - -/* Initialize a buffer stack. This function binds a region of memory - * to be used by the hardware for storing buffer addresses pushed via - * gxio_mpipe_push_buffer() or as the result of sending a buffer out - * the egress with the 'push to stack when done' bit set. Once this - * function returns, the memory region's contents may be arbitrarily - * modified by the hardware at any time and software should not access - * the memory region again. - * - * @param context An initialized mPIPE context. - * @param stack The buffer stack index. - * @param buffer_size_enum The size of each buffer in the buffer stack, - * as an enum. - * @param mem The address of the buffer stack. This memory must be - * physically contiguous and aligned to a 64kB boundary. - * @param mem_size The size of the buffer stack, in bytes. - * @param mem_flags ::gxio_mpipe_mem_flags_e memory flags. - * @return Zero on success, ::GXIO_MPIPE_ERR_INVAL_BUFFER_SIZE if - * buffer_size_enum is invalid, ::GXIO_MPIPE_ERR_BAD_BUFFER_STACK if - * stack has not been allocated. - */ -extern int gxio_mpipe_init_buffer_stack(gxio_mpipe_context_t *context, - unsigned int stack, - gxio_mpipe_buffer_size_enum_t - buffer_size_enum, void *mem, - size_t mem_size, - unsigned int mem_flags); - -/* Push a buffer onto a previously initialized buffer stack. - * - * The size of the buffer being pushed must match the size that was - * registered with gxio_mpipe_init_buffer_stack(). All packet buffer - * addresses are 128-byte aligned; the low 7 bits of the specified - * buffer address will be ignored. - * - * @param context An initialized mPIPE context. - * @param stack The buffer stack index. - * @param buffer The buffer (the low seven bits are ignored). - */ -static inline void gxio_mpipe_push_buffer(gxio_mpipe_context_t *context, - unsigned int stack, void *buffer) -{ - MPIPE_BSM_REGION_ADDR_t offset = { {0} }; - MPIPE_BSM_REGION_VAL_t val = { {0} }; - - /* - * The mmio_fast_base region starts at the IDMA region, so subtract - * off that initial offset. - */ - offset.region = - MPIPE_MMIO_ADDR__REGION_VAL_BSM - - MPIPE_MMIO_ADDR__REGION_VAL_IDMA; - offset.stack = stack; - -#if __SIZEOF_POINTER__ == 4 - val.va = ((ulong) buffer) >> MPIPE_BSM_REGION_VAL__VA_SHIFT; -#else - val.va = ((long)buffer) >> MPIPE_BSM_REGION_VAL__VA_SHIFT; -#endif - - __gxio_mmio_write(context->mmio_fast_base + offset.word, val.word); -} - -/* Pop a buffer off of a previously initialized buffer stack. - * - * @param context An initialized mPIPE context. - * @param stack The buffer stack index. - * @return The buffer, or NULL if the stack is empty. - */ -static inline void *gxio_mpipe_pop_buffer(gxio_mpipe_context_t *context, - unsigned int stack) -{ - MPIPE_BSM_REGION_ADDR_t offset = { {0} }; - - /* - * The mmio_fast_base region starts at the IDMA region, so subtract - * off that initial offset. - */ - offset.region = - MPIPE_MMIO_ADDR__REGION_VAL_BSM - - MPIPE_MMIO_ADDR__REGION_VAL_IDMA; - offset.stack = stack; - - while (1) { - /* - * Case 1: val.c == ..._UNCHAINED, va is non-zero. - * Case 2: val.c == ..._INVALID, va is zero. - * Case 3: val.c == ..._NOT_RDY, va is zero. - */ - MPIPE_BSM_REGION_VAL_t val; - val.word = - __gxio_mmio_read(context->mmio_fast_base + - offset.word); - - /* - * Handle case 1 and 2 by returning the buffer (or NULL). - * Handle case 3 by waiting for the prefetch buffer to refill. - */ - if (val.c != MPIPE_EDMA_DESC_WORD1__C_VAL_NOT_RDY) - return (void *)((unsigned long)val. - va << MPIPE_BSM_REGION_VAL__VA_SHIFT); - } -} - -/***************************************************************** - * NotifRings * - ******************************************************************/ - -/* Allocate a set of NotifRings. - * - * The return value is NOT interesting if count is zero. - * - * Note that NotifRings are allocated in chunks, so allocating one at - * a time is much less efficient than allocating several at once. - * - * @param context An initialized mPIPE context. - * @param count Number of NotifRings required. - * @param first Index of first NotifRing if ::GXIO_MPIPE_ALLOC_FIXED flag - * is set, otherwise ignored. - * @param flags Flag bits from ::gxio_mpipe_alloc_flags_e. - * @return Index of first allocated buffer NotifRing, or - * ::GXIO_MPIPE_ERR_NO_NOTIF_RING if allocation failed. - */ -extern int gxio_mpipe_alloc_notif_rings(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - -/* Initialize a NotifRing, using the given memory and size. - * - * @param context An initialized mPIPE context. - * @param ring The NotifRing index. - * @param mem A physically contiguous region of memory to be filled - * with a ring of ::gxio_mpipe_idesc_t structures. - * @param mem_size Number of bytes in the ring. Must be 128, 512, - * 2048, or 65536 * sizeof(gxio_mpipe_idesc_t). - * @param mem_flags ::gxio_mpipe_mem_flags_e memory flags. - * - * @return 0 on success, ::GXIO_MPIPE_ERR_BAD_NOTIF_RING or - * ::GXIO_ERR_INVAL_MEMORY_SIZE on failure. - */ -extern int gxio_mpipe_init_notif_ring(gxio_mpipe_context_t *context, - unsigned int ring, - void *mem, size_t mem_size, - unsigned int mem_flags); - -/* Configure an interrupt to be sent to a tile on incoming NotifRing - * traffic. Once an interrupt is sent for a particular ring, no more - * will be sent until gxio_mica_enable_notif_ring_interrupt() is called. - * - * @param context An initialized mPIPE context. - * @param x X coordinate of interrupt target tile. - * @param y Y coordinate of interrupt target tile. - * @param i Index of the IPI register which will receive the interrupt. - * @param e Specific event which will be set in the target IPI register when - * the interrupt occurs. - * @param ring The NotifRing index. - * @return Zero on success, GXIO_ERR_INVAL if params are out of range. - */ -extern int gxio_mpipe_request_notif_ring_interrupt(gxio_mpipe_context_t - *context, int x, int y, - int i, int e, - unsigned int ring); - -/* Enable an interrupt on incoming NotifRing traffic. - * - * @param context An initialized mPIPE context. - * @param ring The NotifRing index. - * @return Zero on success, GXIO_ERR_INVAL if params are out of range. - */ -extern int gxio_mpipe_enable_notif_ring_interrupt(gxio_mpipe_context_t - *context, unsigned int ring); - -/* Map all of a client's memory via the given IOTLB. - * @param context An initialized mPIPE context. - * @param iotlb IOTLB index. - * @param pte Page table entry. - * @param flags Flags. - * @return Zero on success, or a negative error code. - */ -extern int gxio_mpipe_register_client_memory(gxio_mpipe_context_t *context, - unsigned int iotlb, HV_PTE pte, - unsigned int flags); - -/***************************************************************** - * Notif Groups * - ******************************************************************/ - -/* Allocate a set of NotifGroups. - * - * The return value is NOT interesting if count is zero. - * - * @param context An initialized mPIPE context. - * @param count Number of NotifGroups required. - * @param first Index of first NotifGroup if ::GXIO_MPIPE_ALLOC_FIXED flag - * is set, otherwise ignored. - * @param flags Flag bits from ::gxio_mpipe_alloc_flags_e. - * @return Index of first allocated buffer NotifGroup, or - * ::GXIO_MPIPE_ERR_NO_NOTIF_GROUP if allocation failed. - */ -extern int gxio_mpipe_alloc_notif_groups(gxio_mpipe_context_t *context, - unsigned int count, - unsigned int first, - unsigned int flags); - -/* Add a NotifRing to a NotifGroup. This only sets a bit in the - * application's 'group' object; the hardware NotifGroup can be - * initialized by passing 'group' to gxio_mpipe_init_notif_group() or - * gxio_mpipe_init_notif_group_and_buckets(). - */ -static inline void -gxio_mpipe_notif_group_add_ring(gxio_mpipe_notif_group_bits_t *bits, int ring) -{ - bits->ring_mask[ring / 64] |= (1ull << (ring % 64)); -} - -/* Set a particular NotifGroup bitmask. Since the load balancer - * makes decisions based on both bucket and NotifGroup state, most - * applications should use gxio_mpipe_init_notif_group_and_buckets() - * rather than using this function to configure just a NotifGroup. - */ -extern int gxio_mpipe_init_notif_group(gxio_mpipe_context_t *context, - unsigned int group, - gxio_mpipe_notif_group_bits_t bits); - -/***************************************************************** - * Load Balancer * - ******************************************************************/ - -/* Allocate a set of load balancer buckets. - * - * The return value is NOT interesting if count is zero. - * - * Note that buckets are allocated in chunks, so allocating one at - * a time is much less efficient than allocating several at once. - * - * Note that the buckets are actually divided into two sub-ranges, of - * different sizes, and different chunk sizes, and the range you get - * by default is determined by the size of the request. Allocations - * cannot span the two sub-ranges. - * - * @param context An initialized mPIPE context. - * @param count Number of buckets required. - * @param first Index of first bucket if ::GXIO_MPIPE_ALLOC_FIXED flag is set, - * otherwise ignored. - * @param flags Flag bits from ::gxio_mpipe_alloc_flags_e. - * @return Index of first allocated buffer bucket, or - * ::GXIO_MPIPE_ERR_NO_BUCKET if allocation failed. - */ -extern int gxio_mpipe_alloc_buckets(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - -/* The legal modes for gxio_mpipe_bucket_info_t and - * gxio_mpipe_init_notif_group_and_buckets(). - * - * All modes except ::GXIO_MPIPE_BUCKET_ROUND_ROBIN expect that the user - * will allocate a power-of-two number of buckets and initialize them - * to the same mode. The classifier program then uses the appropriate - * number of low bits from the incoming packet's flow hash to choose a - * load balancer bucket. Based on that bucket's load balancing mode, - * reference count, and currently active NotifRing, the load balancer - * chooses the NotifRing to which the packet will be delivered. - */ -typedef enum { - /* All packets for a bucket go to the same NotifRing unless the - * NotifRing gets full, in which case packets will be dropped. If - * the bucket reference count ever reaches zero, a new NotifRing may - * be chosen. - */ - GXIO_MPIPE_BUCKET_DYNAMIC_FLOW_AFFINITY = - MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_DFA, - - /* All packets for a bucket always go to the same NotifRing. - */ - GXIO_MPIPE_BUCKET_STATIC_FLOW_AFFINITY = - MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_FIXED, - - /* All packets for a bucket go to the least full NotifRing in the - * group, providing load balancing round robin behavior. - */ - GXIO_MPIPE_BUCKET_ROUND_ROBIN = - MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_ALWAYS_PICK, - - /* All packets for a bucket go to the same NotifRing unless the - * NotifRing gets full, at which point the bucket starts using the - * least full NotifRing in the group. If all NotifRings in the - * group are full, packets will be dropped. - */ - GXIO_MPIPE_BUCKET_STICKY_FLOW_LOCALITY = - MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_STICKY, - - /* All packets for a bucket go to the same NotifRing unless the - * NotifRing gets full, or a random timer fires, at which point the - * bucket starts using the least full NotifRing in the group. If - * all NotifRings in the group are full, packets will be dropped. - * WARNING: This mode is BROKEN on chips with fewer than 64 tiles. - */ - GXIO_MPIPE_BUCKET_PREFER_FLOW_LOCALITY = - MPIPE_LBL_INIT_DAT_BSTS_TBL__MODE_VAL_STICKY_RAND, - -} gxio_mpipe_bucket_mode_t; - -/* Copy a set of bucket initialization values into the mPIPE - * hardware. Since the load balancer makes decisions based on both - * bucket and NotifGroup state, most applications should use - * gxio_mpipe_init_notif_group_and_buckets() rather than using this - * function to configure a single bucket. - * - * @param context An initialized mPIPE context. - * @param bucket Bucket index to be initialized. - * @param bucket_info Initial reference count, NotifRing index, and mode. - * @return 0 on success, ::GXIO_MPIPE_ERR_BAD_BUCKET on failure. - */ -extern int gxio_mpipe_init_bucket(gxio_mpipe_context_t *context, - unsigned int bucket, - gxio_mpipe_bucket_info_t bucket_info); - -/* Initializes a group and range of buckets and range of rings such - * that the load balancer runs a particular load balancing function. - * - * First, the group is initialized with the given rings. - * - * Second, each bucket is initialized with the mode and group, and a - * ring chosen round-robin from the given rings. - * - * Normally, the classifier picks a bucket, and then the load balancer - * picks a ring, based on the bucket's mode, group, and current ring, - * possibly updating the bucket's ring. - * - * @param context An initialized mPIPE context. - * @param group The group. - * @param ring The first ring. - * @param num_rings The number of rings. - * @param bucket The first bucket. - * @param num_buckets The number of buckets. - * @param mode The load balancing mode. - * - * @return 0 on success, ::GXIO_MPIPE_ERR_BAD_BUCKET, - * ::GXIO_MPIPE_ERR_BAD_NOTIF_GROUP, or - * ::GXIO_MPIPE_ERR_BAD_NOTIF_RING on failure. - */ -extern int gxio_mpipe_init_notif_group_and_buckets(gxio_mpipe_context_t - *context, - unsigned int group, - unsigned int ring, - unsigned int num_rings, - unsigned int bucket, - unsigned int num_buckets, - gxio_mpipe_bucket_mode_t - mode); - -/* Return credits to a NotifRing and/or bucket. - * - * @param context An initialized mPIPE context. - * @param ring The NotifRing index, or -1. - * @param bucket The bucket, or -1. - * @param count The number of credits to return. - */ -static inline void gxio_mpipe_credit(gxio_mpipe_context_t *context, - int ring, int bucket, unsigned int count) -{ - /* NOTE: Fancy struct initialization would break "C89" header test. */ - - MPIPE_IDMA_RELEASE_REGION_ADDR_t offset = { {0} }; - MPIPE_IDMA_RELEASE_REGION_VAL_t val = { {0} }; - - /* - * The mmio_fast_base region starts at the IDMA region, so subtract - * off that initial offset. - */ - offset.region = - MPIPE_MMIO_ADDR__REGION_VAL_IDMA - - MPIPE_MMIO_ADDR__REGION_VAL_IDMA; - offset.ring = ring; - offset.bucket = bucket; - offset.ring_enable = (ring >= 0); - offset.bucket_enable = (bucket >= 0); - val.count = count; - - __gxio_mmio_write(context->mmio_fast_base + offset.word, val.word); -} - -/***************************************************************** - * Egress Rings * - ******************************************************************/ - -/* Allocate a set of eDMA rings. - * - * The return value is NOT interesting if count is zero. - * - * @param context An initialized mPIPE context. - * @param count Number of eDMA rings required. - * @param first Index of first eDMA ring if ::GXIO_MPIPE_ALLOC_FIXED flag - * is set, otherwise ignored. - * @param flags Flag bits from ::gxio_mpipe_alloc_flags_e. - * @return Index of first allocated buffer eDMA ring, or - * ::GXIO_MPIPE_ERR_NO_EDMA_RING if allocation failed. - */ -extern int gxio_mpipe_alloc_edma_rings(gxio_mpipe_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - -/* Initialize an eDMA ring, using the given memory and size. - * - * @param context An initialized mPIPE context. - * @param ering The eDMA ring index. - * @param channel The channel to use. This must be one of the channels - * associated with the context's set of open links. - * @param mem A physically contiguous region of memory to be filled - * with a ring of ::gxio_mpipe_edesc_t structures. - * @param mem_size Number of bytes in the ring. Must be 512, 2048, - * 8192 or 65536, times 16 (i.e. sizeof(gxio_mpipe_edesc_t)). - * @param mem_flags ::gxio_mpipe_mem_flags_e memory flags. - * - * @return 0 on success, ::GXIO_MPIPE_ERR_BAD_EDMA_RING or - * ::GXIO_ERR_INVAL_MEMORY_SIZE on failure. - */ -extern int gxio_mpipe_init_edma_ring(gxio_mpipe_context_t *context, - unsigned int ering, unsigned int channel, - void *mem, size_t mem_size, - unsigned int mem_flags); - -/* Set the "max_blks", "min_snf_blks", and "db" fields of - * ::MPIPE_EDMA_RG_INIT_DAT_THRESH_t for a given edma ring. - * - * The global pool of dynamic blocks will be automatically adjusted. - * - * This function should not be called after any egress has been done - * on the edma ring. - * - * Most applications should just use gxio_mpipe_equeue_set_snf_size(). - * - * @param context An initialized mPIPE context. - * @param ering The eDMA ring index. - * @param max_blks The number of blocks to dedicate to the ring - * (normally min_snf_blks + 1). Must be greater than min_snf_blocks. - * @param min_snf_blks The number of blocks which must be stored - * prior to starting to send the packet (normally 12). - * @param db Whether to allow use of dynamic blocks by the ring - * (normally 1). - * - * @return 0 on success, negative on error. - */ -extern int gxio_mpipe_config_edma_ring_blks(gxio_mpipe_context_t *context, - unsigned int ering, - unsigned int max_blks, - unsigned int min_snf_blks, - unsigned int db); - -/***************************************************************** - * Classifier Program * - ******************************************************************/ - -/* - * - * Functions for loading or configuring the mPIPE classifier program. - * - * The mPIPE classification processors all run a special "classifier" - * program which, for each incoming packet, parses the packet headers, - * encodes some packet metadata in the "idesc", and either drops the - * packet, or picks a notif ring to handle the packet, and a buffer - * stack to contain the packet, usually based on the channel, VLAN, - * dMAC, flow hash, and packet size, under the guidance of the "rules" - * API described below. - * - * @section gxio_mpipe_classifier_default Default Classifier - * - * The MDE provides a simple "default" classifier program. It is - * shipped as source in "$TILERA_ROOT/src/sys/mpipe/classifier.c", - * which serves as its official documentation. It is shipped as a - * binary program in "$TILERA_ROOT/tile/boot/classifier", which is - * automatically included in bootroms created by "tile-monitor", and - * is automatically loaded by the hypervisor at boot time. - * - * The L2 analysis handles LLC packets, SNAP packets, and "VLAN - * wrappers" (keeping the outer VLAN). - * - * The L3 analysis handles IPv4 and IPv6, dropping packets with bad - * IPv4 header checksums, requesting computation of a TCP/UDP checksum - * if appropriate, and hashing the dest and src IP addresses, plus the - * ports for TCP/UDP packets, into the flow hash. No special analysis - * is done for "fragmented" packets or "tunneling" protocols. Thus, - * the first fragment of a fragmented TCP/UDP packet is hashed using - * src/dest IP address and ports and all subsequent fragments are only - * hashed according to src/dest IP address. - * - * The L3 analysis handles other packets too, hashing the dMAC - * smac into a flow hash. - * - * The channel, VLAN, and dMAC used to pick a "rule" (see the - * "rules" APIs below), which in turn is used to pick a buffer stack - * (based on the packet size) and a bucket (based on the flow hash). - * - * To receive traffic matching a particular (channel/VLAN/dMAC - * pattern, an application should allocate its own buffer stacks and - * load balancer buckets, and map traffic to those stacks and buckets, - * as decribed by the "rules" API below. - * - * Various packet metadata is encoded in the idesc. The flow hash is - * four bytes at 0x0C. The VLAN is two bytes at 0x10. The ethtype is - * two bytes at 0x12. The l3 start is one byte at 0x14. The l4 start - * is one byte at 0x15 for IPv4 and IPv6 packets, and otherwise zero. - * The protocol is one byte at 0x16 for IPv4 and IPv6 packets, and - * otherwise zero. - * - * @section gxio_mpipe_classifier_custom Custom Classifiers. - * - * A custom classifier may be created using "tile-mpipe-cc" with a - * customized version of the default classifier sources. - * - * The custom classifier may be included in bootroms using the - * "--classifier" option to "tile-monitor", or loaded dynamically - * using gxio_mpipe_classifier_load_from_file(). - * - * Be aware that "extreme" customizations may break the assumptions of - * the "rules" APIs described below, but simple customizations, such - * as adding new packet metadata, should be fine. - */ - -/* A set of classifier rules, plus a context. */ -typedef struct { - - /* The context. */ - gxio_mpipe_context_t *context; - - /* The actual rules. */ - gxio_mpipe_rules_list_t list; - -} gxio_mpipe_rules_t; - -/* Initialize a classifier program rules list. - * - * This function can be called on a previously initialized rules list - * to discard any previously added rules. - * - * @param rules Rules list to initialize. - * @param context An initialized mPIPE context. - */ -extern void gxio_mpipe_rules_init(gxio_mpipe_rules_t *rules, - gxio_mpipe_context_t *context); - -/* Begin a new rule on the indicated rules list. - * - * Note that an empty rule matches all packets, but an empty rule list - * matches no packets. - * - * @param rules Rules list to which new rule is appended. - * @param bucket First load balancer bucket to which packets will be - * delivered. - * @param num_buckets Number of buckets (must be a power of two) across - * which packets will be distributed based on the "flow hash". - * @param stacks Either NULL, to assign each packet to the smallest - * initialized buffer stack which does not induce chaining (and to - * drop packets which exceed the largest initialized buffer stack - * buffer size), or an array, with each entry indicating which buffer - * stack should be used for packets up to that size (with 255 - * indicating that those packets should be dropped). - * @return 0 on success, or a negative error code on failure. - */ -extern int gxio_mpipe_rules_begin(gxio_mpipe_rules_t *rules, - unsigned int bucket, - unsigned int num_buckets, - gxio_mpipe_rules_stacks_t *stacks); - -/* Set the headroom of the current rule. - * - * @param rules Rules list whose current rule will be modified. - * @param headroom The headroom. - * @return 0 on success, or a negative error code on failure. - */ -extern int gxio_mpipe_rules_set_headroom(gxio_mpipe_rules_t *rules, - uint8_t headroom); - -/* Indicate that packets from a particular channel can be delivered - * to the buckets and buffer stacks associated with the current rule. - * - * Channels added must be associated with links opened by the mPIPE context - * used in gxio_mpipe_rules_init(). A rule with no channels is equivalent - * to a rule naming all such associated channels. - * - * @param rules Rules list whose current rule will be modified. - * @param channel The channel to add. - * @return 0 on success, or a negative error code on failure. - */ -extern int gxio_mpipe_rules_add_channel(gxio_mpipe_rules_t *rules, - unsigned int channel); - -/* Commit rules. - * - * The rules are sent to the hypervisor, where they are combined with - * the rules from other apps, and used to program the hardware classifier. - * - * Note that if this function returns an error, then the rules will NOT - * have been committed, even if the error is due to interactions with - * rules from another app. - * - * @param rules Rules list to commit. - * @return 0 on success, or a negative error code on failure. - */ -extern int gxio_mpipe_rules_commit(gxio_mpipe_rules_t *rules); - -/***************************************************************** - * Ingress Queue Wrapper * - ******************************************************************/ - -/* - * - * Convenience functions for receiving packets from a NotifRing and - * sending packets via an eDMA ring. - * - * The mpipe ingress and egress hardware uses shared memory packet - * descriptors to describe packets that have arrived on ingress or - * are destined for egress. These descriptors are stored in shared - * memory ring buffers and written or read by hardware as necessary. - * The gxio library provides wrapper functions that manage the head and - * tail pointers for these rings, allowing the user to easily read or - * write packet descriptors. - * - * The initialization interface for ingress and egress rings is quite - * similar. For example, to create an ingress queue, the user passes - * a ::gxio_mpipe_iqueue_t state object, a ring number from - * gxio_mpipe_alloc_notif_rings(), and the address of memory to hold a - * ring buffer to the gxio_mpipe_iqueue_init() function. The function - * returns success when the state object has been initialized and the - * hardware configured to deliver packets to the specified ring - * buffer. Similarly, gxio_mpipe_equeue_init() takes a - * ::gxio_mpipe_equeue_t state object, a ring number from - * gxio_mpipe_alloc_edma_rings(), and a shared memory buffer. - * - * @section gxio_mpipe_iqueue Working with Ingress Queues - * - * Once initialized, the gxio_mpipe_iqueue_t API provides two flows - * for getting the ::gxio_mpipe_idesc_t packet descriptor associated - * with incoming packets. The simplest is to call - * gxio_mpipe_iqueue_get() or gxio_mpipe_iqueue_try_get(). These - * functions copy the oldest packet descriptor out of the NotifRing and - * into a descriptor provided by the caller. They also immediately - * inform the hardware that a descriptor has been processed. - * - * For applications with stringent performance requirements, higher - * efficiency can be achieved by avoiding the packet descriptor copy - * and processing multiple descriptors at once. The - * gxio_mpipe_iqueue_peek() and gxio_mpipe_iqueue_try_peek() functions - * allow such optimizations. These functions provide a pointer to the - * next valid ingress descriptor in the NotifRing's shared memory ring - * buffer, and a count of how many contiguous descriptors are ready to - * be processed. The application can then process any number of those - * descriptors in place, calling gxio_mpipe_iqueue_consume() to inform - * the hardware after each one has been processed. - * - * @section gxio_mpipe_equeue Working with Egress Queues - * - * Similarly, the egress queue API provides a high-performance - * interface plus a simple wrapper for use in posting - * ::gxio_mpipe_edesc_t egress packet descriptors. The simple - * version, gxio_mpipe_equeue_put(), allows the programmer to wait for - * an eDMA ring slot to become available and write a single descriptor - * into the ring. - * - * Alternatively, you can reserve slots in the eDMA ring using - * gxio_mpipe_equeue_reserve() or gxio_mpipe_equeue_try_reserve(), and - * then fill in each slot using gxio_mpipe_equeue_put_at(). This - * capability can be used to amortize the cost of reserving slots - * across several packets. It also allows gather operations to be - * performed on a shared equeue, by ensuring that the edescs for all - * the fragments are all contiguous in the eDMA ring. - * - * The gxio_mpipe_equeue_reserve() and gxio_mpipe_equeue_try_reserve() - * functions return a 63-bit "completion slot", which is actually a - * sequence number, the low bits of which indicate the ring buffer - * index and the high bits the number of times the application has - * gone around the egress ring buffer. The extra bits allow an - * application to check for egress completion by calling - * gxio_mpipe_equeue_is_complete() to see whether a particular 'slot' - * number has finished. Given the maximum packet rates of the Gx - * processor, the 63-bit slot number will never wrap. - * - * In practice, most applications use the ::gxio_mpipe_edesc_t::hwb - * bit to indicate that the buffers containing egress packet data - * should be pushed onto a buffer stack when egress is complete. Such - * applications generally do not need to know when an egress operation - * completes (since there is no need to free a buffer post-egress), - * and thus can use the optimized gxio_mpipe_equeue_reserve_fast() or - * gxio_mpipe_equeue_try_reserve_fast() functions, which return a 24 - * bit "slot", instead of a 63-bit "completion slot". - * - * Once a slot has been "reserved", it MUST be filled. If the - * application reserves a slot and then decides that it does not - * actually need it, it can set the ::gxio_mpipe_edesc_t::ns (no send) - * bit on the descriptor passed to gxio_mpipe_equeue_put_at() to - * indicate that no data should be sent. This technique can also be - * used to drop an incoming packet, instead of forwarding it, since - * any buffer will still be pushed onto the buffer stack when the - * egress descriptor is processed. - */ - -/* A convenient interface to a NotifRing, for use by a single thread. - */ -typedef struct { - - /* The context. */ - gxio_mpipe_context_t *context; - - /* The actual NotifRing. */ - gxio_mpipe_idesc_t *idescs; - - /* The number of entries. */ - unsigned long num_entries; - - /* The number of entries minus one. */ - unsigned long mask_num_entries; - - /* The log2() of the number of entries. */ - unsigned long log2_num_entries; - - /* The next entry. */ - unsigned int head; - - /* The NotifRing id. */ - unsigned int ring; - -#ifdef __BIG_ENDIAN__ - /* The number of byteswapped entries. */ - unsigned int swapped; -#endif - -} gxio_mpipe_iqueue_t; - -/* Initialize an "iqueue". - * - * Takes the iqueue plus the same args as gxio_mpipe_init_notif_ring(). - */ -extern int gxio_mpipe_iqueue_init(gxio_mpipe_iqueue_t *iqueue, - gxio_mpipe_context_t *context, - unsigned int ring, - void *mem, size_t mem_size, - unsigned int mem_flags); - -/* Advance over some old entries in an iqueue. - * - * Please see the documentation for gxio_mpipe_iqueue_consume(). - * - * @param iqueue An ingress queue initialized via gxio_mpipe_iqueue_init(). - * @param count The number of entries to advance over. - */ -static inline void gxio_mpipe_iqueue_advance(gxio_mpipe_iqueue_t *iqueue, - int count) -{ - /* Advance with proper wrap. */ - int head = iqueue->head + count; - iqueue->head = - (head & iqueue->mask_num_entries) + - (head >> iqueue->log2_num_entries); - -#ifdef __BIG_ENDIAN__ - /* HACK: Track swapped entries. */ - iqueue->swapped -= count; -#endif -} - -/* Release the ring and bucket for an old entry in an iqueue. - * - * Releasing the ring allows more packets to be delivered to the ring. - * - * Releasing the bucket allows flows using the bucket to be moved to a - * new ring when using GXIO_MPIPE_BUCKET_DYNAMIC_FLOW_AFFINITY. - * - * This function is shorthand for "gxio_mpipe_credit(iqueue->context, - * iqueue->ring, idesc->bucket_id, 1)", and it may be more convenient - * to make that underlying call, using those values, instead of - * tracking the entire "idesc". - * - * If packet processing is deferred, optimal performance requires that - * the releasing be deferred as well. - * - * Please see the documentation for gxio_mpipe_iqueue_consume(). - * - * @param iqueue An ingress queue initialized via gxio_mpipe_iqueue_init(). - * @param idesc The descriptor which was processed. - */ -static inline void gxio_mpipe_iqueue_release(gxio_mpipe_iqueue_t *iqueue, - gxio_mpipe_idesc_t *idesc) -{ - gxio_mpipe_credit(iqueue->context, iqueue->ring, idesc->bucket_id, 1); -} - -/* Consume a packet from an "iqueue". - * - * After processing packets peeked at via gxio_mpipe_iqueue_peek() - * or gxio_mpipe_iqueue_try_peek(), you must call this function, or - * gxio_mpipe_iqueue_advance() plus gxio_mpipe_iqueue_release(), to - * advance over those entries, and release their rings and buckets. - * - * You may call this function as each packet is processed, or you can - * wait until several packets have been processed. - * - * Note that if you are using a single bucket, and you are handling - * batches of N packets, then you can replace several calls to this - * function with calls to "gxio_mpipe_iqueue_advance(iqueue, N)" and - * "gxio_mpipe_credit(iqueue->context, iqueue->ring, bucket, N)". - * - * Note that if your classifier sets "idesc->nr", then you should - * explicitly call "gxio_mpipe_iqueue_advance(iqueue, idesc)" plus - * "gxio_mpipe_credit(iqueue->context, iqueue->ring, -1, 1)", to - * avoid incorrectly crediting the (unused) bucket. - * - * @param iqueue An ingress queue initialized via gxio_mpipe_iqueue_init(). - * @param idesc The descriptor which was processed. - */ -static inline void gxio_mpipe_iqueue_consume(gxio_mpipe_iqueue_t *iqueue, - gxio_mpipe_idesc_t *idesc) -{ - gxio_mpipe_iqueue_advance(iqueue, 1); - gxio_mpipe_iqueue_release(iqueue, idesc); -} - -/* Peek at the next packet(s) in an "iqueue", without waiting. - * - * If no packets are available, fills idesc_ref with NULL, and then - * returns ::GXIO_MPIPE_ERR_IQUEUE_EMPTY. Otherwise, fills idesc_ref - * with the address of the next valid packet descriptor, and returns - * the maximum number of valid descriptors which can be processed. - * You may process fewer descriptors if desired. - * - * Call gxio_mpipe_iqueue_consume() on each packet once it has been - * processed (or dropped), to allow more packets to be delivered. - * - * @param iqueue An ingress queue initialized via gxio_mpipe_iqueue_init(). - * @param idesc_ref A pointer to a packet descriptor pointer. - * @return The (positive) number of packets which can be processed, - * or ::GXIO_MPIPE_ERR_IQUEUE_EMPTY if no packets are available. - */ -static inline int gxio_mpipe_iqueue_try_peek(gxio_mpipe_iqueue_t *iqueue, - gxio_mpipe_idesc_t **idesc_ref) -{ - gxio_mpipe_idesc_t *next; - - uint64_t head = iqueue->head; - uint64_t tail = __gxio_mmio_read(iqueue->idescs); - - /* Available entries. */ - uint64_t avail = - (tail >= head) ? (tail - head) : (iqueue->num_entries - head); - - if (avail == 0) { - *idesc_ref = NULL; - return GXIO_MPIPE_ERR_IQUEUE_EMPTY; - } - - next = &iqueue->idescs[head]; - - /* ISSUE: Is this helpful? */ - __insn_prefetch(next); - -#ifdef __BIG_ENDIAN__ - /* HACK: Swap new entries directly in memory. */ - { - int i, j; - for (i = iqueue->swapped; i < avail; i++) { - for (j = 0; j < 8; j++) - next[i].words[j] = - __builtin_bswap64(next[i].words[j]); - } - iqueue->swapped = avail; - } -#endif - - *idesc_ref = next; - - return avail; -} - -/* Drop a packet by pushing its buffer (if appropriate). - * - * NOTE: The caller must still call gxio_mpipe_iqueue_consume() if idesc - * came from gxio_mpipe_iqueue_try_peek() or gxio_mpipe_iqueue_peek(). - * - * @param iqueue An ingress queue initialized via gxio_mpipe_iqueue_init(). - * @param idesc A packet descriptor. - */ -static inline void gxio_mpipe_iqueue_drop(gxio_mpipe_iqueue_t *iqueue, - gxio_mpipe_idesc_t *idesc) -{ - /* FIXME: Handle "chaining" properly. */ - - if (!idesc->be) { - unsigned char *va = gxio_mpipe_idesc_get_va(idesc); - gxio_mpipe_push_buffer(iqueue->context, idesc->stack_idx, va); - } -} - -/***************************************************************** - * Egress Queue Wrapper * - ******************************************************************/ - -/* A convenient, thread-safe interface to an eDMA ring. */ -typedef struct { - - /* State object for tracking head and tail pointers. */ - __gxio_dma_queue_t dma_queue; - - /* The ring entries. */ - gxio_mpipe_edesc_t *edescs; - - /* The number of entries minus one. */ - unsigned long mask_num_entries; - - /* The log2() of the number of entries. */ - unsigned long log2_num_entries; - - /* The context. */ - gxio_mpipe_context_t *context; - - /* The ering. */ - unsigned int ering; - - /* The channel. */ - unsigned int channel; - -} gxio_mpipe_equeue_t; - -/* Initialize an "equeue". - * - * This function uses gxio_mpipe_init_edma_ring() to initialize the - * underlying edma_ring using the provided arguments. - * - * @param equeue An egress queue to be initialized. - * @param context An initialized mPIPE context. - * @param ering The eDMA ring index. - * @param channel The channel to use. This must be one of the channels - * associated with the context's set of open links. - * @param mem A physically contiguous region of memory to be filled - * with a ring of ::gxio_mpipe_edesc_t structures. - * @param mem_size Number of bytes in the ring. Must be 512, 2048, - * 8192 or 65536, times 16 (i.e. sizeof(gxio_mpipe_edesc_t)). - * @param mem_flags ::gxio_mpipe_mem_flags_e memory flags. - * - * @return 0 on success, ::GXIO_MPIPE_ERR_BAD_EDMA_RING or - * ::GXIO_ERR_INVAL_MEMORY_SIZE on failure. - */ -extern int gxio_mpipe_equeue_init(gxio_mpipe_equeue_t *equeue, - gxio_mpipe_context_t *context, - unsigned int ering, - unsigned int channel, - void *mem, unsigned int mem_size, - unsigned int mem_flags); - -/* Reserve completion slots for edescs. - * - * Use gxio_mpipe_equeue_put_at() to actually populate the slots. - * - * This function is slower than gxio_mpipe_equeue_reserve_fast(), but - * returns a full 64 bit completion slot, which can be used with - * gxio_mpipe_equeue_is_complete(). - * - * @param equeue An egress queue initialized via gxio_mpipe_equeue_init(). - * @param num Number of slots to reserve (must be non-zero). - * @return The first reserved completion slot, or a negative error code. - */ -static inline int64_t gxio_mpipe_equeue_reserve(gxio_mpipe_equeue_t *equeue, - unsigned int num) -{ - return __gxio_dma_queue_reserve_aux(&equeue->dma_queue, num, true); -} - -/* Reserve completion slots for edescs, if possible. - * - * Use gxio_mpipe_equeue_put_at() to actually populate the slots. - * - * This function is slower than gxio_mpipe_equeue_try_reserve_fast(), - * but returns a full 64 bit completion slot, which can be used with - * gxio_mpipe_equeue_is_complete(). - * - * @param equeue An egress queue initialized via gxio_mpipe_equeue_init(). - * @param num Number of slots to reserve (must be non-zero). - * @return The first reserved completion slot, or a negative error code. - */ -static inline int64_t gxio_mpipe_equeue_try_reserve(gxio_mpipe_equeue_t - *equeue, unsigned int num) -{ - return __gxio_dma_queue_reserve_aux(&equeue->dma_queue, num, false); -} - -/* Reserve slots for edescs. - * - * Use gxio_mpipe_equeue_put_at() to actually populate the slots. - * - * This function is faster than gxio_mpipe_equeue_reserve(), but - * returns a 24 bit slot (instead of a 64 bit completion slot), which - * thus cannot be used with gxio_mpipe_equeue_is_complete(). - * - * @param equeue An egress queue initialized via gxio_mpipe_equeue_init(). - * @param num Number of slots to reserve (should be non-zero). - * @return The first reserved slot, or a negative error code. - */ -static inline int64_t gxio_mpipe_equeue_reserve_fast(gxio_mpipe_equeue_t - *equeue, unsigned int num) -{ - return __gxio_dma_queue_reserve(&equeue->dma_queue, num, true, false); -} - -/* Reserve slots for edescs, if possible. - * - * Use gxio_mpipe_equeue_put_at() to actually populate the slots. - * - * This function is faster than gxio_mpipe_equeue_try_reserve(), but - * returns a 24 bit slot (instead of a 64 bit completion slot), which - * thus cannot be used with gxio_mpipe_equeue_is_complete(). - * - * @param equeue An egress queue initialized via gxio_mpipe_equeue_init(). - * @param num Number of slots to reserve (should be non-zero). - * @return The first reserved slot, or a negative error code. - */ -static inline int64_t gxio_mpipe_equeue_try_reserve_fast(gxio_mpipe_equeue_t - *equeue, - unsigned int num) -{ - return __gxio_dma_queue_reserve(&equeue->dma_queue, num, false, false); -} - -/* - * HACK: This helper function tricks gcc 4.6 into avoiding saving - * a copy of "edesc->words[0]" on the stack for no obvious reason. - */ - -static inline void gxio_mpipe_equeue_put_at_aux(gxio_mpipe_equeue_t *equeue, - uint_reg_t ew[2], - unsigned long slot) -{ - unsigned long edma_slot = slot & equeue->mask_num_entries; - gxio_mpipe_edesc_t *edesc_p = &equeue->edescs[edma_slot]; - - /* - * ISSUE: Could set eDMA ring to be on generation 1 at start, which - * would avoid the negation here, perhaps allowing "__insn_bfins()". - */ - ew[0] |= !((slot >> equeue->log2_num_entries) & 1); - - /* - * NOTE: We use "__gxio_mpipe_write()", plus the fact that the eDMA - * queue alignment restrictions ensure that these two words are on - * the same cacheline, to force proper ordering between the stores. - */ - __gxio_mmio_write64(&edesc_p->words[1], ew[1]); - __gxio_mmio_write64(&edesc_p->words[0], ew[0]); -} - -/* Post an edesc to a given slot in an equeue. - * - * This function copies the supplied edesc into entry "slot mod N" in - * the underlying ring, setting the "gen" bit to the appropriate value - * based on "(slot mod N*2)", where "N" is the size of the ring. Note - * that the higher bits of slot are unused, and thus, this function - * can handle "slots" as well as "completion slots". - * - * Normally this function is used to fill in slots reserved by - * gxio_mpipe_equeue_try_reserve(), gxio_mpipe_equeue_reserve(), - * gxio_mpipe_equeue_try_reserve_fast(), or - * gxio_mpipe_equeue_reserve_fast(), - * - * This function can also be used without "reserving" slots, if the - * application KNOWS that the ring can never overflow, for example, by - * pushing fewer buffers into the buffer stacks than there are total - * slots in the equeue, but this is NOT recommended. - * - * @param equeue An egress queue initialized via gxio_mpipe_equeue_init(). - * @param edesc The egress descriptor to be posted. - * @param slot An egress slot (only the low bits are actually used). - */ -static inline void gxio_mpipe_equeue_put_at(gxio_mpipe_equeue_t *equeue, - gxio_mpipe_edesc_t edesc, - unsigned long slot) -{ - gxio_mpipe_equeue_put_at_aux(equeue, edesc.words, slot); -} - -/* Post an edesc to the next slot in an equeue. - * - * This is a convenience wrapper around - * gxio_mpipe_equeue_reserve_fast() and gxio_mpipe_equeue_put_at(). - * - * @param equeue An egress queue initialized via gxio_mpipe_equeue_init(). - * @param edesc The egress descriptor to be posted. - * @return 0 on success. - */ -static inline int gxio_mpipe_equeue_put(gxio_mpipe_equeue_t *equeue, - gxio_mpipe_edesc_t edesc) -{ - int64_t slot = gxio_mpipe_equeue_reserve_fast(equeue, 1); - if (slot < 0) - return (int)slot; - - gxio_mpipe_equeue_put_at(equeue, edesc, slot); - - return 0; -} - -/* Ask the mPIPE hardware to egress outstanding packets immediately. - * - * This call is not necessary, but may slightly reduce overall latency. - * - * Technically, you should flush all gxio_mpipe_equeue_put_at() writes - * to memory before calling this function, to ensure the descriptors - * are visible in memory before the mPIPE hardware actually looks for - * them. But this should be very rare, and the only side effect would - * be increased latency, so it is up to the caller to decide whether - * or not to flush memory. - * - * @param equeue An egress queue initialized via gxio_mpipe_equeue_init(). - */ -static inline void gxio_mpipe_equeue_flush(gxio_mpipe_equeue_t *equeue) -{ - /* Use "ring_idx = 0" and "count = 0" to "wake up" the eDMA ring. */ - MPIPE_EDMA_POST_REGION_VAL_t val = { {0} }; - /* Flush the write buffers. */ - __insn_flushwb(); - __gxio_mmio_write(equeue->dma_queue.post_region_addr, val.word); -} - -/* Determine if a given edesc has been completed. - * - * Note that this function requires a "completion slot", and thus may - * NOT be used with a "slot" from gxio_mpipe_equeue_reserve_fast() or - * gxio_mpipe_equeue_try_reserve_fast(). - * - * @param equeue An egress queue initialized via gxio_mpipe_equeue_init(). - * @param completion_slot The completion slot used by the edesc. - * @param update If true, and the desc does not appear to have completed - * yet, then update any software cache of the hardware completion counter, - * and check again. This should normally be true. - * @return True iff the given edesc has been completed. - */ -static inline int gxio_mpipe_equeue_is_complete(gxio_mpipe_equeue_t *equeue, - int64_t completion_slot, - int update) -{ - return __gxio_dma_queue_is_complete(&equeue->dma_queue, - completion_slot, update); -} - -/* Set the snf (store and forward) size for an equeue. - * - * The snf size for an equeue defaults to 1536, and encodes the size - * of the largest packet for which egress is guaranteed to avoid - * transmission underruns and/or corrupt checksums under heavy load. - * - * The snf size affects a global resource pool which cannot support, - * for example, all 24 equeues each requesting an snf size of 8K. - * - * To ensure that jumbo packets can be egressed properly, the snf size - * should be set to the size of the largest possible packet, which - * will usually be limited by the size of the app's largest buffer. - * - * This is a convenience wrapper around - * gxio_mpipe_config_edma_ring_blks(). - * - * This function should not be called after any egress has been done - * on the equeue. - * - * @param equeue An egress queue initialized via gxio_mpipe_equeue_init(). - * @param size The snf size, in bytes. - * @return Zero on success, negative error otherwise. - */ -static inline int gxio_mpipe_equeue_set_snf_size(gxio_mpipe_equeue_t *equeue, - size_t size) -{ - int blks = (size + 127) / 128; - return gxio_mpipe_config_edma_ring_blks(equeue->context, equeue->ering, - blks + 1, blks, 1); -} - -/***************************************************************** - * Link Management * - ******************************************************************/ - -/* - * - * Functions for manipulating and sensing the state and configuration - * of physical network links. - * - * @section gxio_mpipe_link_perm Link Permissions - * - * Opening a link (with gxio_mpipe_link_open()) requests a set of link - * permissions, which control what may be done with the link, and potentially - * what permissions may be granted to other processes. - * - * Data permission allows the process to receive packets from the link by - * specifying the link's channel number in mPIPE packet distribution rules, - * and to send packets to the link by using the link's channel number as - * the target for an eDMA ring. - * - * Stats permission allows the process to retrieve link attributes (such as - * the speeds it is capable of running at, or whether it is currently up), and - * to read and write certain statistics-related registers in the link's MAC. - * - * Control permission allows the process to retrieve and modify link attributes - * (so that it may, for example, bring the link up and take it down), and - * read and write many registers in the link's MAC and PHY. - * - * Any permission may be requested as shared, which allows other processes - * to also request shared permission, or exclusive, which prevents other - * processes from requesting it. In keeping with GXIO's typical usage in - * an embedded environment, the defaults for all permissions are shared. - * - * Permissions are granted on a first-come, first-served basis, so if two - * applications request an exclusive permission on the same link, the one - * to run first will win. Note, however, that some system components, like - * the kernel Ethernet driver, may get an opportunity to open links before - * any applications run. - * - * @section gxio_mpipe_link_names Link Names - * - * Link names are of the form gbenumber (for Gigabit Ethernet), - * xgbenumber (for 10 Gigabit Ethernet), loopnumber (for - * internal mPIPE loopback), or ilknumber/channel - * (for Interlaken links); for instance, gbe0, xgbe1, loop3, and - * ilk0/12 are all possible link names. The correspondence between - * the link name and an mPIPE instance number or mPIPE channel number is - * system-dependent; all links will not exist on all systems, and the set - * of numbers used for a particular link type may not start at zero and may - * not be contiguous. Use gxio_mpipe_link_enumerate() to retrieve the set of - * links which exist on a system, and always use gxio_mpipe_link_instance() - * to determine which mPIPE controls a particular link. - * - * Note that in some cases, links may share hardware, such as PHYs, or - * internal mPIPE buffers; in these cases, only one of the links may be - * opened at a time. This is especially common with xgbe and gbe ports, - * since each xgbe port uses 4 SERDES lanes, each of which may also be - * configured as one gbe port. - * - * @section gxio_mpipe_link_states Link States - * - * The mPIPE link management model revolves around three different states, - * which are maintained for each link: - * - * 1. The current link state: is the link up now, and if so, at - * what speed? - * - * 2. The desired link state: what do we want the link state to be? - * The system is always working to make this state the current state; - * thus, if the desired state is up, and the link is down, we'll be - * constantly trying to bring it up, automatically. - * - * 3. The possible link state: what speeds are valid for this - * particular link? Or, in other words, what are the capabilities of - * the link hardware? - * - * These link states are not, strictly speaking, related to application - * state; they may be manipulated at any time, whether or not the link - * is currently being used for data transfer. However, for convenience, - * gxio_mpipe_link_open() and gxio_mpipe_link_close() (or application exit) - * can affect the link state. These implicit link management operations - * may be modified or disabled by the use of link open flags. - * - * From an application, you can use gxio_mpipe_link_get_attr() - * and gxio_mpipe_link_set_attr() to manipulate the link states. - * gxio_mpipe_link_get_attr() with ::GXIO_MPIPE_LINK_POSSIBLE_STATE - * gets you the possible link state. gxio_mpipe_link_get_attr() with - * ::GXIO_MPIPE_LINK_CURRENT_STATE gets you the current link state. - * Finally, gxio_mpipe_link_set_attr() and gxio_mpipe_link_get_attr() - * with ::GXIO_MPIPE_LINK_DESIRED_STATE allow you to modify or retrieve - * the desired link state. - * - * If you want to manage a link from a part of your application which isn't - * involved in packet processing, you can use the ::GXIO_MPIPE_LINK_NO_DATA - * flags on a gxio_mpipe_link_open() call. This opens the link, but does - * not request data permission, so it does not conflict with any exclusive - * permissions which may be held by other processes. You can then can use - * gxio_mpipe_link_get_attr() and gxio_mpipe_link_set_attr() on this link - * object to bring up or take down the link. - * - * Some links support link state bits which support various loopback - * modes. ::GXIO_MPIPE_LINK_LOOP_MAC tests datapaths within the Tile - * Processor itself; ::GXIO_MPIPE_LINK_LOOP_PHY tests the datapath between - * the Tile Processor and the external physical layer interface chip; and - * ::GXIO_MPIPE_LINK_LOOP_EXT tests the entire network datapath with the - * aid of an external loopback connector. In addition to enabling hardware - * testing, such configuration can be useful for software testing, as well. - * - * When LOOP_MAC or LOOP_PHY is enabled, packets transmitted on a channel - * will be received by that channel, instead of being emitted on the - * physical link, and packets received on the physical link will be ignored. - * Other than that, all standard GXIO operations work as you might expect. - * Note that loopback operation requires that the link be brought up using - * one or more of the GXIO_MPIPE_LINK_SPEED_xxx link state bits. - * - * Those familiar with previous versions of the MDE on TILEPro hardware - * will notice significant similarities between the NetIO link management - * model and the mPIPE link management model. However, the NetIO model - * was developed in stages, and some of its features -- for instance, - * the default setting of certain flags -- were shaped by the need to be - * compatible with previous versions of NetIO. Since the features provided - * by the mPIPE hardware and the mPIPE GXIO library are significantly - * different than those provided by NetIO, in some cases, we have made - * different choices in the mPIPE link management API. Thus, please read - * this documentation carefully before assuming that mPIPE link management - * operations are exactly equivalent to their NetIO counterparts. - */ - -/* An object used to manage mPIPE link state and resources. */ -typedef struct { - /* The overall mPIPE context. */ - gxio_mpipe_context_t *context; - - /* The channel number used by this link. */ - uint8_t channel; - - /* The MAC index used by this link. */ - uint8_t mac; -} gxio_mpipe_link_t; - -/* Translate a link name to the instance number of the mPIPE shim which is - * connected to that link. This call does not verify whether the link is - * currently available, and does not reserve any link resources; - * gxio_mpipe_link_open() must be called to perform those functions. - * - * Typically applications will call this function to translate a link name - * to an mPIPE instance number; call gxio_mpipe_init(), passing it that - * instance number, to initialize the mPIPE shim; and then call - * gxio_mpipe_link_open(), passing it the same link name plus the mPIPE - * context, to configure the link. - * - * @param link_name Name of the link; see @ref gxio_mpipe_link_names. - * @return The mPIPE instance number which is associated with the named - * link, or a negative error code (::GXIO_ERR_NO_DEVICE) if the link does - * not exist. - */ -extern int gxio_mpipe_link_instance(const char *link_name); - -/* Retrieve one of this system's legal link names, and its MAC address. - * - * @param index Link name index. If a system supports N legal link names, - * then indices between 0 and N - 1, inclusive, each correspond to one of - * those names. Thus, to retrieve all of a system's legal link names, - * call this function in a loop, starting with an index of zero, and - * incrementing it once per iteration until -1 is returned. - * @param link_name Pointer to the buffer which will receive the retrieved - * link name. The buffer should contain space for at least - * ::GXIO_MPIPE_LINK_NAME_LEN bytes; the returned name, including the - * terminating null byte, will be no longer than that. - * @param link_name Pointer to the buffer which will receive the retrieved - * MAC address. The buffer should contain space for at least 6 bytes. - * @return Zero if a link name was successfully retrieved; -1 if one was - * not. - */ -extern int gxio_mpipe_link_enumerate_mac(int index, char *link_name, - uint8_t *mac_addr); - -/* Open an mPIPE link. - * - * A link must be opened before it may be used to send or receive packets, - * and before its state may be examined or changed. Depending up on the - * link's intended use, one or more link permissions may be requested via - * the flags parameter; see @ref gxio_mpipe_link_perm. In addition, flags - * may request that the link's state be modified at open time. See @ref - * gxio_mpipe_link_states and @ref gxio_mpipe_link_open_flags for more detail. - * - * @param link A link state object, which will be initialized if this - * function completes successfully. - * @param context An initialized mPIPE context. - * @param link_name Name of the link. - * @param flags Zero or more @ref gxio_mpipe_link_open_flags, ORed together. - * @return 0 if the link was successfully opened, or a negative error code. - * - */ -extern int gxio_mpipe_link_open(gxio_mpipe_link_t *link, - gxio_mpipe_context_t *context, - const char *link_name, unsigned int flags); - -/* Close an mPIPE link. - * - * Closing a link makes it available for use by other processes. Once - * a link has been closed, packets may no longer be sent on or received - * from the link, and its state may not be examined or changed. - * - * @param link A link state object, which will no longer be initialized - * if this function completes successfully. - * @return 0 if the link was successfully closed, or a negative error code. - * - */ -extern int gxio_mpipe_link_close(gxio_mpipe_link_t *link); - -/* Return a link's channel number. - * - * @param link A properly initialized link state object. - * @return The channel number for the link. - */ -static inline int gxio_mpipe_link_channel(gxio_mpipe_link_t *link) -{ - return link->channel; -} - -/* Set a link attribute. - * - * @param link A properly initialized link state object. - * @param attr An attribute from the set of @ref gxio_mpipe_link_attrs. - * @param val New value of the attribute. - * @return 0 if the attribute was successfully set, or a negative error - * code. - */ -extern int gxio_mpipe_link_set_attr(gxio_mpipe_link_t *link, uint32_t attr, - int64_t val); - -/////////////////////////////////////////////////////////////////// -// Timestamp // -/////////////////////////////////////////////////////////////////// - -/* Get the timestamp of mPIPE when this routine is called. - * - * @param context An initialized mPIPE context. - * @param ts A timespec structure to store the current clock. - * @return If the call was successful, zero; otherwise, a negative error - * code. - */ -extern int gxio_mpipe_get_timestamp(gxio_mpipe_context_t *context, - struct timespec64 *ts); - -/* Set the timestamp of mPIPE. - * - * @param context An initialized mPIPE context. - * @param ts A timespec structure to store the requested clock. - * @return If the call was successful, zero; otherwise, a negative error - * code. - */ -extern int gxio_mpipe_set_timestamp(gxio_mpipe_context_t *context, - const struct timespec64 *ts); - -/* Adjust the timestamp of mPIPE. - * - * @param context An initialized mPIPE context. - * @param delta A signed time offset to adjust, in nanoseconds. - * The absolute value of this parameter must be less than or - * equal to 1000000000. - * @return If the call was successful, zero; otherwise, a negative error - * code. - */ -extern int gxio_mpipe_adjust_timestamp(gxio_mpipe_context_t *context, - int64_t delta); - -/** Adjust the mPIPE timestamp clock frequency. - * - * @param context An initialized mPIPE context. - * @param ppb A 32-bit signed PPB (Parts Per Billion) value to adjust. - * The absolute value of ppb must be less than or equal to 1000000000. - * Values less than about 30000 will generally cause a GXIO_ERR_INVAL - * return due to the granularity of the hardware that converts reference - * clock cycles into seconds and nanoseconds. - * @return If the call was successful, zero; otherwise, a negative error - * code. - */ -extern int gxio_mpipe_adjust_timestamp_freq(gxio_mpipe_context_t* context, - int32_t ppb); - -#endif /* !_GXIO_MPIPE_H_ */ diff --git a/arch/tile/include/gxio/trio.h b/arch/tile/include/gxio/trio.h deleted file mode 100644 index df10a662cc25..000000000000 --- a/arch/tile/include/gxio/trio.h +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* - * - * An API for allocating, configuring, and manipulating TRIO hardware - * resources - */ - -/* - * - * The TILE-Gx TRIO shim provides connections to external devices via - * PCIe or other transaction IO standards. The gxio_trio_ API, - * declared in , allows applications to allocate and - * configure TRIO IO resources like DMA command rings, memory map - * windows, and device interrupts. The following sections introduce - * the various components of the API. We strongly recommend reading - * the TRIO section of the IO Device Guide (UG404) before working with - * this API. - * - * @section trio__ingress TRIO Ingress Hardware Resources - * - * The TRIO ingress hardware is responsible for examining incoming - * PCIe or StreamIO packets and choosing a processing mechanism based - * on the packets' bus address. The gxio_trio_ API can be used to - * configure different handlers for different ranges of bus address - * space. The user can configure "mapped memory" and "scatter queue" - * regions to match incoming packets within 4kB-aligned ranges of bus - * addresses. Each range specifies a different set of mapping - * parameters to be applied when handling the ingress packet. The - * following sections describe how to work with MapMem and scatter - * queue regions. - * - * @subsection trio__mapmem TRIO MapMem Regions - * - * TRIO mapped memory (or MapMem) regions allow the user to map - * incoming read and write requests directly to the application's - * memory space. MapMem regions are allocated via - * gxio_trio_alloc_memory_maps(). Given an integer MapMem number, - * applications can use gxio_trio_init_memory_map() to specify the - * range of bus addresses that will match the region and the range of - * virtual addresses to which those packets will be applied. - * - * As with many other gxio APIs, the programmer must be sure to - * register memory pages that will be used with MapMem regions. Pages - * can be registered with TRIO by allocating an ASID (address space - * identifier) and then using gxio_trio_register_page() to register up to - * 16 pages with the hardware. The initialization functions for - * resources that require registered memory (MapMem, scatter queues, - * push DMA, and pull DMA) then take an 'asid' parameter in order to - * configure which set of registered pages is used by each resource. - * - * @subsection trio__scatter_queue TRIO Scatter Queues - * - * The TRIO shim's scatter queue regions allow users to dynamically - * map buffers from a large address space into a small range of bus - * addresses. This is particularly helpful for PCIe endpoint devices, - * where the host generally limits the size of BARs to tens of - * megabytes. - * - * Each scatter queue consists of a memory map region, a queue of - * tile-side buffer VAs to be mapped to that region, and a bus-mapped - * "doorbell" register that the remote endpoint can write to trigger a - * dequeue of the current buffer VA, thus swapping in a new buffer. - * The VAs pushed onto a scatter queue must be 4kB aligned, so - * applications may need to use higher-level protocols to inform - * remote entities that they should apply some additional, sub-4kB - * offset when reading or writing the scatter queue region. For more - * information, see the IO Device Guide (UG404). - * - * @section trio__egress TRIO Egress Hardware Resources - * - * The TRIO shim supports two mechanisms for egress packet generation: - * programmed IO (PIO) and push/pull DMA. PIO allows applications to - * create MMIO mappings for PCIe or StreamIO address space, such that - * the application can generate word-sized read or write transactions - * by issuing load or store instructions. Push and pull DMA are tuned - * for larger transactions; they use specialized hardware engines to - * transfer large blocks of data at line rate. - * - * @subsection trio__pio TRIO Programmed IO - * - * Programmed IO allows applications to create MMIO mappings for PCIe - * or StreamIO address space. The hardware PIO regions support access - * to PCIe configuration, IO, and memory space, but the gxio_trio API - * only supports memory space accesses. PIO regions are allocated - * with gxio_trio_alloc_pio_regions() and initialized via - * gxio_trio_init_pio_region(). Once a region is bound to a range of - * bus address via the initialization function, the application can - * use gxio_trio_map_pio_region() to create MMIO mappings from its VA - * space onto the range of bus addresses supported by the PIO region. - * - * @subsection trio_dma TRIO Push and Pull DMA - * - * The TRIO push and pull DMA engines allow users to copy blocks of - * data between application memory and the bus. Push DMA generates - * write packets that copy from application memory to the bus and pull - * DMA generates read packets that copy from the bus into application - * memory. The DMA engines are managed via an API that is very - * similar to the mPIPE eDMA interface. For a detailed explanation of - * the eDMA queue API, see @ref gxio_mpipe_wrappers. - * - * Push and pull DMA queues are allocated via - * gxio_trio_alloc_push_dma_ring() / gxio_trio_alloc_pull_dma_ring(). - * Once allocated, users generally use a ::gxio_trio_dma_queue_t - * object to manage the queue, providing easy wrappers for reserving - * command slots in the DMA command ring, filling those slots, and - * waiting for commands to complete. DMA queues can be initialized - * via gxio_trio_init_push_dma_queue() or - * gxio_trio_init_pull_dma_queue(). - * - * See @ref trio/push_dma/app.c for an example of how to use push DMA. - * - * @section trio_shortcomings Plans for Future API Revisions - * - * The simulation framework is incomplete. Future features include: - * - * - Support for reset and deallocation of resources. - * - * - Support for pull DMA. - * - * - Support for interrupt regions and user-space interrupt delivery. - * - * - Support for getting BAR mappings and reserving regions of BAR - * address space. - */ -#ifndef _GXIO_TRIO_H_ -#define _GXIO_TRIO_H_ - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* A context object used to manage TRIO hardware resources. */ -typedef struct { - - /* File descriptor for calling up to Linux (and thus the HV). */ - int fd; - - /* The VA at which the MAC MMIO registers are mapped. */ - char *mmio_base_mac; - - /* The VA at which the PIO config space are mapped for each PCIe MAC. - Gx36 has max 3 PCIe MACs per TRIO shim. */ - char *mmio_base_pio_cfg[TILEGX_TRIO_PCIES]; - -#ifdef USE_SHARED_PCIE_CONFIG_REGION - /* Index of the shared PIO region for PCI config access. */ - int pio_cfg_index; -#else - /* Index of the PIO region for PCI config access per MAC. */ - int pio_cfg_index[TILEGX_TRIO_PCIES]; -#endif - - /* The VA at which the push DMA MMIO registers are mapped. */ - char *mmio_push_dma[TRIO_NUM_PUSH_DMA_RINGS]; - - /* The VA at which the pull DMA MMIO registers are mapped. */ - char *mmio_pull_dma[TRIO_NUM_PUSH_DMA_RINGS]; - - /* Application space ID. */ - unsigned int asid; - -} gxio_trio_context_t; - -/* Command descriptor for push or pull DMA. */ -typedef TRIO_DMA_DESC_t gxio_trio_dma_desc_t; - -/* A convenient, thread-safe interface to an eDMA ring. */ -typedef struct { - - /* State object for tracking head and tail pointers. */ - __gxio_dma_queue_t dma_queue; - - /* The ring entries. */ - gxio_trio_dma_desc_t *dma_descs; - - /* The number of entries minus one. */ - unsigned long mask_num_entries; - - /* The log2() of the number of entries. */ - unsigned int log2_num_entries; - -} gxio_trio_dma_queue_t; - -/* Initialize a TRIO context. - * - * This function allocates a TRIO "service domain" and maps the MMIO - * registers into the the caller's VA space. - * - * @param trio_index Which TRIO shim; Gx36 must pass 0. - * @param context Context object to be initialized. - */ -extern int gxio_trio_init(gxio_trio_context_t *context, - unsigned int trio_index); - -/* This indicates that an ASID hasn't been allocated. */ -#define GXIO_ASID_NULL -1 - -/* Ordering modes for map memory regions and scatter queue regions. */ -typedef enum gxio_trio_order_mode_e { - /* Writes are not ordered. Reads always wait for previous writes. */ - GXIO_TRIO_ORDER_MODE_UNORDERED = - TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_UNORDERED, - /* Both writes and reads wait for previous transactions to complete. */ - GXIO_TRIO_ORDER_MODE_STRICT = - TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_STRICT, - /* Writes are ordered unless the incoming packet has the - relaxed-ordering attributes set. */ - GXIO_TRIO_ORDER_MODE_OBEY_PACKET = - TRIO_MAP_MEM_SETUP__ORDER_MODE_VAL_REL_ORD -} gxio_trio_order_mode_t; - -/* Initialize a memory mapping region. - * - * @param context An initialized TRIO context. - * @param map A Memory map region allocated by gxio_trio_alloc_memory_map(). - * @param target_mem VA of backing memory, should be registered via - * gxio_trio_register_page() and aligned to 4kB. - * @param target_size Length of the memory mapping, must be a multiple - * of 4kB. - * @param asid ASID to be used for Tile-side address translation. - * @param mac MAC number. - * @param bus_address Bus address at which the mapping starts. - * @param order_mode Memory ordering mode for this mapping. - * @return Zero on success, else ::GXIO_TRIO_ERR_BAD_MEMORY_MAP, - * GXIO_TRIO_ERR_BAD_ASID, or ::GXIO_TRIO_ERR_BAD_BUS_RANGE. - */ -extern int gxio_trio_init_memory_map(gxio_trio_context_t *context, - unsigned int map, void *target_mem, - size_t target_size, unsigned int asid, - unsigned int mac, uint64_t bus_address, - gxio_trio_order_mode_t order_mode); - -/* Flags that can be passed to resource allocation functions. */ -enum gxio_trio_alloc_flags_e { - GXIO_TRIO_ALLOC_FIXED = HV_TRIO_ALLOC_FIXED, -}; - -/* Flags that can be passed to memory registration functions. */ -enum gxio_trio_mem_flags_e { - /* Do not fill L3 when writing, and invalidate lines upon egress. */ - GXIO_TRIO_MEM_FLAG_NT_HINT = IORPC_MEM_BUFFER_FLAG_NT_HINT, - - /* L3 cache fills should only populate IO cache ways. */ - GXIO_TRIO_MEM_FLAG_IO_PIN = IORPC_MEM_BUFFER_FLAG_IO_PIN, -}; - -/* Flag indicating a request generator uses a special traffic - class. */ -#define GXIO_TRIO_FLAG_TRAFFIC_CLASS(N) HV_TRIO_FLAG_TC(N) - -/* Flag indicating a request generator uses a virtual function - number. */ -#define GXIO_TRIO_FLAG_VFUNC(N) HV_TRIO_FLAG_VFUNC(N) - -/***************************************************************** - * Memory Registration * - ******************************************************************/ - -/* Allocate Application Space Identifiers (ASIDs). Each ASID can - * register up to 16 page translations. ASIDs are used by memory map - * regions, scatter queues, and DMA queues to translate application - * VAs into memory system PAs. - * - * @param context An initialized TRIO context. - * @param count Number of ASIDs required. - * @param first Index of first ASID if ::GXIO_TRIO_ALLOC_FIXED flag - * is set, otherwise ignored. - * @param flags Flag bits, including bits from ::gxio_trio_alloc_flags_e. - * @return Index of first ASID, or ::GXIO_TRIO_ERR_NO_ASID if allocation - * failed. - */ -extern int gxio_trio_alloc_asids(gxio_trio_context_t *context, - unsigned int count, unsigned int first, - unsigned int flags); - -#endif /* ! _GXIO_TRIO_H_ */ diff --git a/arch/tile/include/gxio/uart.h b/arch/tile/include/gxio/uart.h deleted file mode 100644 index 438ee7e46c7b..000000000000 --- a/arch/tile/include/gxio/uart.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _GXIO_UART_H_ -#define _GXIO_UART_H_ - -#include "common.h" - -#include -#include - -/* - * - * An API for manipulating UART interface. - */ - -/* - * - * The Rshim allows access to the processor's UART interface. - */ - -/* A context object used to manage UART resources. */ -typedef struct { - - /* File descriptor for calling up to the hypervisor. */ - int fd; - - /* The VA at which our MMIO registers are mapped. */ - char *mmio_base; - -} gxio_uart_context_t; - -/* Request UART interrupts. - * - * Request that interrupts be delivered to a tile when the UART's - * Receive FIFO is written, or the Write FIFO is read. - * - * @param context Pointer to a properly initialized gxio_uart_context_t. - * @param bind_cpu_x X coordinate of CPU to which interrupt will be delivered. - * @param bind_cpu_y Y coordinate of CPU to which interrupt will be delivered. - * @param bind_interrupt IPI interrupt number. - * @param bind_event Sub-interrupt event bit number; a negative value can - * disable the interrupt. - * @return Zero if all of the requested UART events were successfully - * configured to interrupt. - */ -extern int gxio_uart_cfg_interrupt(gxio_uart_context_t *context, - int bind_cpu_x, - int bind_cpu_y, - int bind_interrupt, int bind_event); - -/* Initialize a UART context. - * - * A properly initialized context must be obtained before any of the other - * gxio_uart routines may be used. - * - * @param context Pointer to a gxio_uart_context_t, which will be initialized - * by this routine, if it succeeds. - * @param uart_index Index of the UART to use. - * @return Zero if the context was successfully initialized, else a - * GXIO_ERR_xxx error code. - */ -extern int gxio_uart_init(gxio_uart_context_t *context, int uart_index); - -/* Destroy a UART context. - * - * Once destroyed, a context may not be used with any gxio_uart routines - * other than gxio_uart_init(). After this routine returns, no further - * interrupts requested on this context will be delivered. The state and - * configuration of the pins which had been attached to this context are - * unchanged by this operation. - * - * @param context Pointer to a gxio_uart_context_t. - * @return Zero if the context was successfully destroyed, else a - * GXIO_ERR_xxx error code. - */ -extern int gxio_uart_destroy(gxio_uart_context_t *context); - -/* Write UART register. - * @param context Pointer to a gxio_uart_context_t. - * @param offset UART register offset. - * @param word Data will be wrote to UART reigister. - */ -extern void gxio_uart_write(gxio_uart_context_t *context, uint64_t offset, - uint64_t word); - -/* Read UART register. - * @param context Pointer to a gxio_uart_context_t. - * @param offset UART register offset. - * @return Data read from UART register. - */ -extern uint64_t gxio_uart_read(gxio_uart_context_t *context, uint64_t offset); - -#endif /* _GXIO_UART_H_ */ diff --git a/arch/tile/include/gxio/usb_host.h b/arch/tile/include/gxio/usb_host.h deleted file mode 100644 index 93c9636d2dd7..000000000000 --- a/arch/tile/include/gxio/usb_host.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ -#ifndef _GXIO_USB_H_ -#define _GXIO_USB_H_ - -#include - -#include -#include - -/* - * - * An API for manipulating general-purpose I/O pins. - */ - -/* - * - * The USB shim allows access to the processor's Universal Serial Bus - * connections. - */ - -/* A context object used to manage USB hardware resources. */ -typedef struct { - - /* File descriptor for calling up to the hypervisor. */ - int fd; - - /* The VA at which our MMIO registers are mapped. */ - char *mmio_base; -} gxio_usb_host_context_t; - -/* Initialize a USB context. - * - * A properly initialized context must be obtained before any of the other - * gxio_usb_host routines may be used. - * - * @param context Pointer to a gxio_usb_host_context_t, which will be - * initialized by this routine, if it succeeds. - * @param usb_index Index of the USB shim to use. - * @param is_ehci Nonzero to use the EHCI interface; zero to use the OHCI - * intereface. - * @return Zero if the context was successfully initialized, else a - * GXIO_ERR_xxx error code. - */ -extern int gxio_usb_host_init(gxio_usb_host_context_t *context, int usb_index, - int is_ehci); - -/* Destroy a USB context. - * - * Once destroyed, a context may not be used with any gxio_usb_host routines - * other than gxio_usb_host_init(). After this routine returns, no further - * interrupts or signals requested on this context will be delivered. The - * state and configuration of the pins which had been attached to this - * context are unchanged by this operation. - * - * @param context Pointer to a gxio_usb_host_context_t. - * @return Zero if the context was successfully destroyed, else a - * GXIO_ERR_xxx error code. - */ -extern int gxio_usb_host_destroy(gxio_usb_host_context_t *context); - -/* Retrieve the address of the shim's MMIO registers. - * - * @param context Pointer to a properly initialized gxio_usb_host_context_t. - * @return The address of the shim's MMIO registers. - */ -extern void *gxio_usb_host_get_reg_start(gxio_usb_host_context_t *context); - -/* Retrieve the length of the shim's MMIO registers. - * - * @param context Pointer to a properly initialized gxio_usb_host_context_t. - * @return The length of the shim's MMIO registers. - */ -extern size_t gxio_usb_host_get_reg_len(gxio_usb_host_context_t *context); - -#endif /* _GXIO_USB_H_ */ diff --git a/arch/tile/include/hv/drv_mpipe_intf.h b/arch/tile/include/hv/drv_mpipe_intf.h deleted file mode 100644 index ff7f50f970a5..000000000000 --- a/arch/tile/include/hv/drv_mpipe_intf.h +++ /dev/null @@ -1,605 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * Interface definitions for the mpipe driver. - */ - -#ifndef _SYS_HV_DRV_MPIPE_INTF_H -#define _SYS_HV_DRV_MPIPE_INTF_H - -#include -#include - - -/** Number of mPIPE instances supported */ -#define HV_MPIPE_INSTANCE_MAX (2) - -/** Number of buffer stacks (32). */ -#define HV_MPIPE_NUM_BUFFER_STACKS \ - (MPIPE_MMIO_INIT_DAT_GX36_1__BUFFER_STACK_MASK_WIDTH) - -/** Number of NotifRings (256). */ -#define HV_MPIPE_NUM_NOTIF_RINGS (MPIPE_NUM_NOTIF_RINGS) - -/** Number of NotifGroups (32). */ -#define HV_MPIPE_NUM_NOTIF_GROUPS (MPIPE_NUM_NOTIF_GROUPS) - -/** Number of buckets (4160). */ -#define HV_MPIPE_NUM_BUCKETS (MPIPE_NUM_BUCKETS) - -/** Number of "lo" buckets (4096). */ -#define HV_MPIPE_NUM_LO_BUCKETS 4096 - -/** Number of "hi" buckets (64). */ -#define HV_MPIPE_NUM_HI_BUCKETS \ - (HV_MPIPE_NUM_BUCKETS - HV_MPIPE_NUM_LO_BUCKETS) - -/** Number of edma rings (24). */ -#define HV_MPIPE_NUM_EDMA_RINGS \ - (MPIPE_MMIO_INIT_DAT_GX36_1__EDMA_POST_MASK_WIDTH) - - - - -/** A flag bit indicating a fixed resource allocation. */ -#define HV_MPIPE_ALLOC_FIXED 0x01 - -/** Offset for the config register MMIO region. */ -#define HV_MPIPE_CONFIG_MMIO_OFFSET \ - (MPIPE_MMIO_ADDR__REGION_VAL_CFG << MPIPE_MMIO_ADDR__REGION_SHIFT) - -/** Size of the config register MMIO region. */ -#define HV_MPIPE_CONFIG_MMIO_SIZE (64 * 1024) - -/** Offset for the config register MMIO region. */ -#define HV_MPIPE_FAST_MMIO_OFFSET \ - (MPIPE_MMIO_ADDR__REGION_VAL_IDMA << MPIPE_MMIO_ADDR__REGION_SHIFT) - -/** Size of the fast register MMIO region (IDMA, EDMA, buffer stack). */ -#define HV_MPIPE_FAST_MMIO_SIZE \ - ((MPIPE_MMIO_ADDR__REGION_VAL_BSM + 1 - MPIPE_MMIO_ADDR__REGION_VAL_IDMA) \ - << MPIPE_MMIO_ADDR__REGION_SHIFT) - - -/* - * Each type of resource allocation comes in quantized chunks, where - * XXX_BITS is the number of chunks, and XXX_RES_PER_BIT is the number - * of resources in each chunk. - */ - -/** Number of buffer stack chunks available (32). */ -#define HV_MPIPE_ALLOC_BUFFER_STACKS_BITS \ - MPIPE_MMIO_INIT_DAT_GX36_1__BUFFER_STACK_MASK_WIDTH - -/** Granularity of buffer stack allocation (1). */ -#define HV_MPIPE_ALLOC_BUFFER_STACKS_RES_PER_BIT \ - (HV_MPIPE_NUM_BUFFER_STACKS / HV_MPIPE_ALLOC_BUFFER_STACKS_BITS) - -/** Number of NotifRing chunks available (32). */ -#define HV_MPIPE_ALLOC_NOTIF_RINGS_BITS \ - MPIPE_MMIO_INIT_DAT_GX36_0__NOTIF_RING_MASK_WIDTH - -/** Granularity of NotifRing allocation (8). */ -#define HV_MPIPE_ALLOC_NOTIF_RINGS_RES_PER_BIT \ - (HV_MPIPE_NUM_NOTIF_RINGS / HV_MPIPE_ALLOC_NOTIF_RINGS_BITS) - -/** Number of NotifGroup chunks available (32). */ -#define HV_MPIPE_ALLOC_NOTIF_GROUPS_BITS \ - HV_MPIPE_NUM_NOTIF_GROUPS - -/** Granularity of NotifGroup allocation (1). */ -#define HV_MPIPE_ALLOC_NOTIF_GROUPS_RES_PER_BIT \ - (HV_MPIPE_NUM_NOTIF_GROUPS / HV_MPIPE_ALLOC_NOTIF_GROUPS_BITS) - -/** Number of lo bucket chunks available (16). */ -#define HV_MPIPE_ALLOC_LO_BUCKETS_BITS \ - MPIPE_MMIO_INIT_DAT_GX36_0__BUCKET_RELEASE_MASK_LO_WIDTH - -/** Granularity of lo bucket allocation (256). */ -#define HV_MPIPE_ALLOC_LO_BUCKETS_RES_PER_BIT \ - (HV_MPIPE_NUM_LO_BUCKETS / HV_MPIPE_ALLOC_LO_BUCKETS_BITS) - -/** Number of hi bucket chunks available (16). */ -#define HV_MPIPE_ALLOC_HI_BUCKETS_BITS \ - MPIPE_MMIO_INIT_DAT_GX36_0__BUCKET_RELEASE_MASK_HI_WIDTH - -/** Granularity of hi bucket allocation (4). */ -#define HV_MPIPE_ALLOC_HI_BUCKETS_RES_PER_BIT \ - (HV_MPIPE_NUM_HI_BUCKETS / HV_MPIPE_ALLOC_HI_BUCKETS_BITS) - -/** Number of eDMA ring chunks available (24). */ -#define HV_MPIPE_ALLOC_EDMA_RINGS_BITS \ - MPIPE_MMIO_INIT_DAT_GX36_1__EDMA_POST_MASK_WIDTH - -/** Granularity of eDMA ring allocation (1). */ -#define HV_MPIPE_ALLOC_EDMA_RINGS_RES_PER_BIT \ - (HV_MPIPE_NUM_EDMA_RINGS / HV_MPIPE_ALLOC_EDMA_RINGS_BITS) - - - - -/** Bit vector encoding which NotifRings are in a NotifGroup. */ -typedef struct -{ - /** The actual bits. */ - uint64_t ring_mask[4]; - -} gxio_mpipe_notif_group_bits_t; - - -/** Another name for MPIPE_LBL_INIT_DAT_BSTS_TBL_t. */ -typedef MPIPE_LBL_INIT_DAT_BSTS_TBL_t gxio_mpipe_bucket_info_t; - - - -/** Eight buffer stack ids. */ -typedef struct -{ - /** The stacks. */ - uint8_t stacks[8]; - -} gxio_mpipe_rules_stacks_t; - - -/** A destination mac address. */ -typedef struct -{ - /** The octets. */ - uint8_t octets[6]; - -} gxio_mpipe_rules_dmac_t; - - -/** A vlan. */ -typedef uint16_t gxio_mpipe_rules_vlan_t; - - - -/** Maximum number of characters in a link name. */ -#define GXIO_MPIPE_LINK_NAME_LEN 32 - - -/** Structure holding a link name. Only needed, and only typedef'ed, - * because the IORPC stub generator only handles types which are single - * words coming before the parameter name. */ -typedef struct -{ - /** The name itself. */ - char name[GXIO_MPIPE_LINK_NAME_LEN]; -} -_gxio_mpipe_link_name_t; - -/** Maximum number of characters in a symbol name. */ -#define GXIO_MPIPE_SYMBOL_NAME_LEN 128 - - -/** Structure holding a symbol name. Only needed, and only typedef'ed, - * because the IORPC stub generator only handles types which are single - * words coming before the parameter name. */ -typedef struct -{ - /** The name itself. */ - char name[GXIO_MPIPE_SYMBOL_NAME_LEN]; -} -_gxio_mpipe_symbol_name_t; - - -/** Structure holding a MAC address. */ -typedef struct -{ - /** The address. */ - uint8_t mac[6]; -} -_gxio_mpipe_link_mac_t; - - - -/** Request shared data permission -- that is, the ability to send and - * receive packets -- on the specified link. Other processes may also - * request shared data permission on the same link. - * - * No more than one of ::GXIO_MPIPE_LINK_DATA, ::GXIO_MPIPE_LINK_NO_DATA, - * or ::GXIO_MPIPE_LINK_EXCL_DATA may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_DATA is assumed. - */ -#define GXIO_MPIPE_LINK_DATA 0x00000001UL - -/** Do not request data permission on the specified link. - * - * No more than one of ::GXIO_MPIPE_LINK_DATA, ::GXIO_MPIPE_LINK_NO_DATA, - * or ::GXIO_MPIPE_LINK_EXCL_DATA may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_DATA is assumed. - */ -#define GXIO_MPIPE_LINK_NO_DATA 0x00000002UL - -/** Request exclusive data permission -- that is, the ability to send and - * receive packets -- on the specified link. No other processes may - * request data permission on this link, and if any process already has - * data permission on it, this open will fail. - * - * No more than one of ::GXIO_MPIPE_LINK_DATA, ::GXIO_MPIPE_LINK_NO_DATA, - * or ::GXIO_MPIPE_LINK_EXCL_DATA may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_DATA is assumed. - */ -#define GXIO_MPIPE_LINK_EXCL_DATA 0x00000004UL - -/** Request shared stats permission -- that is, the ability to read and write - * registers which contain link statistics, and to get link attributes -- - * on the specified link. Other processes may also request shared stats - * permission on the same link. - * - * No more than one of ::GXIO_MPIPE_LINK_STATS, ::GXIO_MPIPE_LINK_NO_STATS, - * or ::GXIO_MPIPE_LINK_EXCL_STATS may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_STATS is assumed. - */ -#define GXIO_MPIPE_LINK_STATS 0x00000008UL - -/** Do not request stats permission on the specified link. - * - * No more than one of ::GXIO_MPIPE_LINK_STATS, ::GXIO_MPIPE_LINK_NO_STATS, - * or ::GXIO_MPIPE_LINK_EXCL_STATS may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_STATS is assumed. - */ -#define GXIO_MPIPE_LINK_NO_STATS 0x00000010UL - -/** Request exclusive stats permission -- that is, the ability to read and - * write registers which contain link statistics, and to get link - * attributes -- on the specified link. No other processes may request - * stats permission on this link, and if any process already - * has stats permission on it, this open will fail. - * - * Requesting exclusive stats permission is normally a very bad idea, since - * it prevents programs like mpipe-stat from providing information on this - * link. Applications should only do this if they use MAC statistics - * registers, and cannot tolerate any of the clear-on-read registers being - * reset by other statistics programs. - * - * No more than one of ::GXIO_MPIPE_LINK_STATS, ::GXIO_MPIPE_LINK_NO_STATS, - * or ::GXIO_MPIPE_LINK_EXCL_STATS may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_STATS is assumed. - */ -#define GXIO_MPIPE_LINK_EXCL_STATS 0x00000020UL - -/** Request shared control permission -- that is, the ability to modify link - * attributes, and read and write MAC and MDIO registers -- on the - * specified link. Other processes may also request shared control - * permission on the same link. - * - * No more than one of ::GXIO_MPIPE_LINK_CTL, ::GXIO_MPIPE_LINK_NO_CTL, - * or ::GXIO_MPIPE_LINK_EXCL_CTL may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_CTL is assumed. - */ -#define GXIO_MPIPE_LINK_CTL 0x00000040UL - -/** Do not request control permission on the specified link. - * - * No more than one of ::GXIO_MPIPE_LINK_CTL, ::GXIO_MPIPE_LINK_NO_CTL, - * or ::GXIO_MPIPE_LINK_EXCL_CTL may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_CTL is assumed. - */ -#define GXIO_MPIPE_LINK_NO_CTL 0x00000080UL - -/** Request exclusive control permission -- that is, the ability to modify - * link attributes, and read and write MAC and MDIO registers -- on the - * specified link. No other processes may request control permission on - * this link, and if any process already has control permission on it, - * this open will fail. - * - * Requesting exclusive control permission is not always a good idea, since - * it prevents programs like mpipe-link from configuring the link. - * - * No more than one of ::GXIO_MPIPE_LINK_CTL, ::GXIO_MPIPE_LINK_NO_CTL, - * or ::GXIO_MPIPE_LINK_EXCL_CTL may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_CTL is assumed. - */ -#define GXIO_MPIPE_LINK_EXCL_CTL 0x00000100UL - -/** Set the desired state of the link to up, allowing any speeds which are - * supported by the link hardware, as part of this open operation; do not - * change the desired state of the link when it is closed or the process - * exits. No more than one of ::GXIO_MPIPE_LINK_AUTO_UP, - * ::GXIO_MPIPE_LINK_AUTO_UPDOWN, ::GXIO_MPIPE_LINK_AUTO_DOWN, or - * ::GXIO_MPIPE_LINK_AUTO_NONE may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed. - */ -#define GXIO_MPIPE_LINK_AUTO_UP 0x00000200UL - -/** Set the desired state of the link to up, allowing any speeds which are - * supported by the link hardware, as part of this open operation; when the - * link is closed or this process exits, if no other process has the link - * open, set the desired state of the link to down. No more than one of - * ::GXIO_MPIPE_LINK_AUTO_UP, ::GXIO_MPIPE_LINK_AUTO_UPDOWN, - * ::GXIO_MPIPE_LINK_AUTO_DOWN, or ::GXIO_MPIPE_LINK_AUTO_NONE may be - * specified in a gxio_mpipe_link_open() call. If none are specified, - * ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed. - */ -#define GXIO_MPIPE_LINK_AUTO_UPDOWN 0x00000400UL - -/** Do not change the desired state of the link as part of the open - * operation; when the link is closed or this process exits, if no other - * process has the link open, set the desired state of the link to down. - * No more than one of ::GXIO_MPIPE_LINK_AUTO_UP, - * ::GXIO_MPIPE_LINK_AUTO_UPDOWN, ::GXIO_MPIPE_LINK_AUTO_DOWN, or - * ::GXIO_MPIPE_LINK_AUTO_NONE may be specified in a gxio_mpipe_link_open() - * call. If none are specified, ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed. - */ -#define GXIO_MPIPE_LINK_AUTO_DOWN 0x00000800UL - -/** Do not change the desired state of the link as part of the open - * operation; do not change the desired state of the link when it is - * closed or the process exits. No more than one of - * ::GXIO_MPIPE_LINK_AUTO_UP, ::GXIO_MPIPE_LINK_AUTO_UPDOWN, - * ::GXIO_MPIPE_LINK_AUTO_DOWN, or ::GXIO_MPIPE_LINK_AUTO_NONE may be - * specified in a gxio_mpipe_link_open() call. If none are specified, - * ::GXIO_MPIPE_LINK_AUTO_UPDOWN is assumed. - */ -#define GXIO_MPIPE_LINK_AUTO_NONE 0x00001000UL - -/** Request that this open call not complete until the network link is up. - * The process will wait as long as necessary for this to happen; - * applications which wish to abandon waiting for the link after a - * specific time period should not specify this flag when opening a link, - * but should instead call gxio_mpipe_link_wait() afterward. The link - * must be opened with stats permission. Note that this flag by itself - * does not change the desired link state; if other open flags or previous - * link state changes have not requested a desired state of up, the open - * call will never complete. This flag is not available to kernel - * clients. - */ -#define GXIO_MPIPE_LINK_WAIT 0x00002000UL - - -/* - * Note: link attributes must fit in 24 bits, since we use the top 8 bits - * of the IORPC offset word for the channel number. - */ - -/** Determine whether jumbo frames may be received. If this attribute's - * value value is nonzero, the MAC will accept frames of up to 10240 bytes. - * If the value is zero, the MAC will only accept frames of up to 1544 - * bytes. The default value is zero. */ -#define GXIO_MPIPE_LINK_RECEIVE_JUMBO 0x010000 - -/** Determine whether to send pause frames on this link if the mPIPE packet - * FIFO is nearly full. If the value is zero, pause frames are not sent. - * If the value is nonzero, it is the delay value which will be sent in any - * pause frames which are output, in units of 512 bit times. - * - * Bear in mind that in almost all circumstances, the mPIPE packet FIFO - * will never fill up, since mPIPE will empty it as fast as or faster than - * the incoming data rate, by either delivering or dropping packets. The - * only situation in which this is not true is if the memory and cache - * subsystem is extremely heavily loaded, and mPIPE cannot perform DMA of - * packet data to memory in a timely fashion. In particular, pause frames - * will not be sent if packets cannot be delivered because - * NotifRings are full, buckets are full, or buffers are not available in - * a buffer stack. */ -#define GXIO_MPIPE_LINK_SEND_PAUSE 0x020000 - -/** Determine whether to suspend output on the receipt of pause frames. - * If the value is nonzero, mPIPE shim will suspend output on the link's - * channel when a pause frame is received. If the value is zero, pause - * frames will be ignored. The default value is zero. */ -#define GXIO_MPIPE_LINK_RECEIVE_PAUSE 0x030000 - -/** Interface MAC address. The value is a 6-byte MAC address, in the least - * significant 48 bits of the value; in other words, an address which would - * be printed as '12:34:56:78:90:AB' in IEEE 802 canonical format would - * be returned as 0x12345678ab. - * - * Depending upon the overall system design, a MAC address may or may not - * be available for each interface. Note that the interface's MAC address - * does not limit the packets received on its channel, although the - * classifier's rules could be configured to do that. Similarly, the MAC - * address is not used when transmitting packets, although applications - * could certainly decide to use the assigned address as a source MAC - * address when doing so. This attribute may only be retrieved with - * gxio_mpipe_link_get_attr(); it may not be modified. - */ -#define GXIO_MPIPE_LINK_MAC 0x040000 - -/** Determine whether to discard egress packets on link down. If this value - * is nonzero, packets sent on this link while the link is down will be - * discarded. If this value is zero, no packets will be sent on this link - * while it is down. The default value is one. */ -#define GXIO_MPIPE_LINK_DISCARD_IF_DOWN 0x050000 - -/** Possible link state. The value is a combination of link state flags, - * ORed together, that indicate link modes which are actually supported by - * the hardware. This attribute may only be retrieved with - * gxio_mpipe_link_get_attr(); it may not be modified. */ -#define GXIO_MPIPE_LINK_POSSIBLE_STATE 0x060000 - -/** Current link state. The value is a combination of link state flags, - * ORed together, that indicate the current state of the hardware. If the - * link is down, the value ANDed with ::GXIO_MPIPE_LINK_SPEED will be zero; - * if the link is up, the value ANDed with ::GXIO_MPIPE_LINK_SPEED will - * result in exactly one of the speed values, indicating the current speed. - * This attribute may only be retrieved with gxio_mpipe_link_get_attr(); it - * may not be modified. */ -#define GXIO_MPIPE_LINK_CURRENT_STATE 0x070000 - -/** Desired link state. The value is a conbination of flags, which specify - * the desired state for the link. With gxio_mpipe_link_set_attr(), this - * will, in the background, attempt to bring up the link using whichever of - * the requested flags are reasonable, or take down the link if the flags - * are zero. The actual link up or down operation may happen after this - * call completes. If the link state changes in the future, the system - * will continue to try to get back to the desired link state; for - * instance, if the link is brought up successfully, and then the network - * cable is disconnected, the link will go down. However, the desired - * state of the link is still up, so if the cable is reconnected, the link - * will be brought up again. - * - * With gxio_mpipe_link_set_attr(), this will indicate the desired state - * for the link, as set with a previous gxio_mpipe_link_set_attr() call, - * or implicitly by a gxio_mpipe_link_open() or link close operation. - * This may not reflect the current state of the link; to get that, use - * ::GXIO_MPIPE_LINK_CURRENT_STATE. - */ -#define GXIO_MPIPE_LINK_DESIRED_STATE 0x080000 - - - -/** Link can run, should run, or is running at 10 Mbps. */ -#define GXIO_MPIPE_LINK_10M 0x0000000000000001UL - -/** Link can run, should run, or is running at 100 Mbps. */ -#define GXIO_MPIPE_LINK_100M 0x0000000000000002UL - -/** Link can run, should run, or is running at 1 Gbps. */ -#define GXIO_MPIPE_LINK_1G 0x0000000000000004UL - -/** Link can run, should run, or is running at 10 Gbps. */ -#define GXIO_MPIPE_LINK_10G 0x0000000000000008UL - -/** Link can run, should run, or is running at 20 Gbps. */ -#define GXIO_MPIPE_LINK_20G 0x0000000000000010UL - -/** Link can run, should run, or is running at 25 Gbps. */ -#define GXIO_MPIPE_LINK_25G 0x0000000000000020UL - -/** Link can run, should run, or is running at 50 Gbps. */ -#define GXIO_MPIPE_LINK_50G 0x0000000000000040UL - -/** Link should run at the highest speed supported by the link and by - * the device connected to the link. Only usable as a value for - * the link's desired state; never returned as a value for the current - * or possible states. */ -#define GXIO_MPIPE_LINK_ANYSPEED 0x0000000000000800UL - -/** All legal link speeds. This value is provided for use in extracting - * the speed-related subset of the link state flags; it is not intended - * to be set directly as a value for one of the GXIO_MPIPE_LINK_xxx_STATE - * attributes. A link is up or is requested to be up if its current or - * desired state, respectively, ANDED with this value, is nonzero. */ -#define GXIO_MPIPE_LINK_SPEED_MASK 0x0000000000000FFFUL - -/** Link can run, should run, or is running in MAC loopback mode. This - * loops transmitted packets back to the receiver, inside the Tile - * Processor. */ -#define GXIO_MPIPE_LINK_LOOP_MAC 0x0000000000001000UL - -/** Link can run, should run, or is running in PHY loopback mode. This - * loops transmitted packets back to the receiver, inside the external - * PHY chip. */ -#define GXIO_MPIPE_LINK_LOOP_PHY 0x0000000000002000UL - -/** Link can run, should run, or is running in external loopback mode. - * This requires that an external loopback plug be installed on the - * Ethernet port. Note that only some links require that this be - * configured via the gxio_mpipe_link routines; other links can do - * external loopack with the plug and no special configuration. */ -#define GXIO_MPIPE_LINK_LOOP_EXT 0x0000000000004000UL - -/** All legal loopback types. */ -#define GXIO_MPIPE_LINK_LOOP_MASK 0x000000000000F000UL - -/** Link can run, should run, or is running in full-duplex mode. - * If neither ::GXIO_MPIPE_LINK_FDX nor ::GXIO_MPIPE_LINK_HDX are - * specified in a set of desired state flags, both are assumed. */ -#define GXIO_MPIPE_LINK_FDX 0x0000000000010000UL - -/** Link can run, should run, or is running in half-duplex mode. - * If neither ::GXIO_MPIPE_LINK_FDX nor ::GXIO_MPIPE_LINK_HDX are - * specified in a set of desired state flags, both are assumed. */ -#define GXIO_MPIPE_LINK_HDX 0x0000000000020000UL - - -/** An individual rule. */ -typedef struct -{ - /** The total size. */ - uint16_t size; - - /** The priority. */ - int16_t priority; - - /** The "headroom" in each buffer. */ - uint8_t headroom; - - /** The "tailroom" in each buffer. */ - uint8_t tailroom; - - /** The "capacity" of the largest buffer. */ - uint16_t capacity; - - /** The mask for converting a flow hash into a bucket. */ - uint16_t bucket_mask; - - /** The offset for converting a flow hash into a bucket. */ - uint16_t bucket_first; - - /** The buffer stack ids. */ - gxio_mpipe_rules_stacks_t stacks; - - /** The actual channels. */ - uint32_t channel_bits; - - /** The number of dmacs. */ - uint16_t num_dmacs; - - /** The number of vlans. */ - uint16_t num_vlans; - - /** The actual dmacs and vlans. */ - uint8_t dmacs_and_vlans[]; - -} gxio_mpipe_rules_rule_t; - - -/** A list of classifier rules. */ -typedef struct -{ - /** The offset to the end of the current rule. */ - uint16_t tail; - - /** The offset to the start of the current rule. */ - uint16_t head; - - /** The actual rules. */ - uint8_t rules[4096 - 4]; - -} gxio_mpipe_rules_list_t; - - - - -/** mPIPE statistics structure. These counters include all relevant - * events occurring on all links within the mPIPE shim. */ -typedef struct -{ - /** Number of ingress packets dropped for any reason. */ - uint64_t ingress_drops; - /** Number of ingress packets dropped because a buffer stack was empty. */ - uint64_t ingress_drops_no_buf; - /** Number of ingress packets dropped or truncated due to lack of space in - * the iPkt buffer. */ - uint64_t ingress_drops_ipkt; - /** Number of ingress packets dropped by the classifier or load balancer */ - uint64_t ingress_drops_cls_lb; - /** Total number of ingress packets. */ - uint64_t ingress_packets; - /** Total number of egress packets. */ - uint64_t egress_packets; - /** Total number of ingress bytes. */ - uint64_t ingress_bytes; - /** Total number of egress bytes. */ - uint64_t egress_bytes; -} -gxio_mpipe_stats_t; - - -#endif /* _SYS_HV_DRV_MPIPE_INTF_H */ diff --git a/arch/tile/include/hv/drv_mshim_intf.h b/arch/tile/include/hv/drv_mshim_intf.h deleted file mode 100644 index c6ef3bdc55cf..000000000000 --- a/arch/tile/include/hv/drv_mshim_intf.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file drv_mshim_intf.h - * Interface definitions for the Linux EDAC memory controller driver. - */ - -#ifndef _SYS_HV_INCLUDE_DRV_MSHIM_INTF_H -#define _SYS_HV_INCLUDE_DRV_MSHIM_INTF_H - -/** Number of memory controllers in the public API. */ -#define TILE_MAX_MSHIMS 4 - -/** Memory info under each memory controller. */ -struct mshim_mem_info -{ - uint64_t mem_size; /**< Total memory size in bytes. */ - uint8_t mem_type; /**< Memory type, DDR2 or DDR3. */ - uint8_t mem_ecc; /**< Memory supports ECC. */ -}; - -/** - * DIMM error structure. - * For now, only correctable errors are counted and the mshim doesn't record - * the error PA. HV takes panic upon uncorrectable errors. - */ -struct mshim_mem_error -{ - uint32_t sbe_count; /**< Number of single-bit errors. */ -}; - -/** Read this offset to get the memory info per mshim. */ -#define MSHIM_MEM_INFO_OFF 0x100 - -/** Read this offset to check DIMM error. */ -#define MSHIM_MEM_ERROR_OFF 0x200 - -#endif /* _SYS_HV_INCLUDE_DRV_MSHIM_INTF_H */ diff --git a/arch/tile/include/hv/drv_pcie_rc_intf.h b/arch/tile/include/hv/drv_pcie_rc_intf.h deleted file mode 100644 index 9bd2243bece0..000000000000 --- a/arch/tile/include/hv/drv_pcie_rc_intf.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file drv_pcie_rc_intf.h - * Interface definitions for the PCIE Root Complex. - */ - -#ifndef _SYS_HV_DRV_PCIE_RC_INTF_H -#define _SYS_HV_DRV_PCIE_RC_INTF_H - -/** File offset for reading the interrupt base number used for PCIE legacy - interrupts and PLX Gen 1 requirement flag */ -#define PCIE_RC_CONFIG_MASK_OFF 0 - - -/** - * Structure used for obtaining PCIe config information, read from the PCIE - * subsystem /ctl file at initialization - */ -typedef struct pcie_rc_config -{ - int intr; /**< interrupt number used for downcall */ - int plx_gen1; /**< flag for PLX Gen 1 configuration */ -} pcie_rc_config_t; - -#endif /* _SYS_HV_DRV_PCIE_RC_INTF_H */ diff --git a/arch/tile/include/hv/drv_srom_intf.h b/arch/tile/include/hv/drv_srom_intf.h deleted file mode 100644 index 6395faa6d9e6..000000000000 --- a/arch/tile/include/hv/drv_srom_intf.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file drv_srom_intf.h - * Interface definitions for the SPI Flash ROM driver. - */ - -#ifndef _SYS_HV_INCLUDE_DRV_SROM_INTF_H -#define _SYS_HV_INCLUDE_DRV_SROM_INTF_H - -/** Read this offset to get the total device size. */ -#define SROM_TOTAL_SIZE_OFF 0xF0000000 - -/** Read this offset to get the device sector size. */ -#define SROM_SECTOR_SIZE_OFF 0xF0000004 - -/** Read this offset to get the device page size. */ -#define SROM_PAGE_SIZE_OFF 0xF0000008 - -/** Write this offset to flush any pending writes. */ -#define SROM_FLUSH_OFF 0xF1000000 - -/** Write this offset, plus the byte offset of the start of a sector, to - * erase a sector. Any write data is ignored, but there must be at least - * one byte of write data. Only applies when the driver is in MTD mode. - */ -#define SROM_ERASE_OFF 0xF2000000 - -#endif /* _SYS_HV_INCLUDE_DRV_SROM_INTF_H */ diff --git a/arch/tile/include/hv/drv_trio_intf.h b/arch/tile/include/hv/drv_trio_intf.h deleted file mode 100644 index 237e04dee66c..000000000000 --- a/arch/tile/include/hv/drv_trio_intf.h +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * Interface definitions for the trio driver. - */ - -#ifndef _SYS_HV_DRV_TRIO_INTF_H -#define _SYS_HV_DRV_TRIO_INTF_H - -#include - -/** The vendor ID for all Tilera processors. */ -#define TILERA_VENDOR_ID 0x1a41 - -/** The device ID for the Gx36 processor. */ -#define TILERA_GX36_DEV_ID 0x0200 - -/** Device ID for our internal bridge when running as RC. */ -#define TILERA_GX36_RC_DEV_ID 0x2000 - -/** Maximum number of TRIO interfaces. */ -#define TILEGX_NUM_TRIO 2 - -/** Gx36 has max 3 PCIe MACs per TRIO interface. */ -#define TILEGX_TRIO_PCIES 3 - -/** Specify port properties for a PCIe MAC. */ -struct pcie_port_property -{ - /** If true, the link can be configured in PCIe root complex mode. */ - uint8_t allow_rc: 1; - - /** If true, the link can be configured in PCIe endpoint mode. */ - uint8_t allow_ep: 1; - - /** If true, the link can be configured in StreamIO mode. */ - uint8_t allow_sio: 1; - - /** If true, the link is allowed to support 1-lane operation. Software - * will not consider it an error if the link comes up as a x1 link. */ - uint8_t allow_x1: 1; - - /** If true, the link is allowed to support 2-lane operation. Software - * will not consider it an error if the link comes up as a x2 link. */ - uint8_t allow_x2: 1; - - /** If true, the link is allowed to support 4-lane operation. Software - * will not consider it an error if the link comes up as a x4 link. */ - uint8_t allow_x4: 1; - - /** If true, the link is allowed to support 8-lane operation. Software - * will not consider it an error if the link comes up as a x8 link. */ - uint8_t allow_x8: 1; - - /** If true, this link is connected to a device which may or may not - * be present. */ - uint8_t removable: 1; - -}; - -/** Configurations can be issued to configure a char stream interrupt. */ -typedef enum pcie_stream_intr_config_sel_e -{ - /** Interrupt configuration for memory map regions. */ - MEM_MAP_SEL, - - /** Interrupt configuration for push DMAs. */ - PUSH_DMA_SEL, - - /** Interrupt configuration for pull DMAs. */ - PULL_DMA_SEL, -} -pcie_stream_intr_config_sel_t; - - -/** The mmap file offset (PA) of the TRIO config region. */ -#define HV_TRIO_CONFIG_OFFSET \ - ((unsigned long long)TRIO_MMIO_ADDRESS_SPACE__REGION_VAL_CFG << \ - TRIO_MMIO_ADDRESS_SPACE__REGION_SHIFT) - -/** The maximum size of the TRIO config region. */ -#define HV_TRIO_CONFIG_SIZE \ - (1ULL << TRIO_CFG_REGION_ADDR__REGION_SHIFT) - -/** Size of the config region mapped into client. We can't use - * TRIO_MMIO_ADDRESS_SPACE__OFFSET_WIDTH because it - * will require the kernel to allocate 4GB VA space - * from the VMALLOC region which has a total range - * of 4GB. - */ -#define HV_TRIO_CONFIG_IOREMAP_SIZE \ - ((uint64_t) 1 << TRIO_CFG_REGION_ADDR__PROT_SHIFT) - -/** The mmap file offset (PA) of a scatter queue region. */ -#define HV_TRIO_SQ_OFFSET(queue) \ - (((unsigned long long)TRIO_MMIO_ADDRESS_SPACE__REGION_VAL_MAP_SQ << \ - TRIO_MMIO_ADDRESS_SPACE__REGION_SHIFT) | \ - ((queue) << TRIO_MAP_SQ_REGION_ADDR__SQ_SEL_SHIFT)) - -/** The maximum size of a scatter queue region. */ -#define HV_TRIO_SQ_SIZE \ - (1ULL << TRIO_MAP_SQ_REGION_ADDR__SQ_SEL_SHIFT) - - -/** The "hardware MMIO region" of the first PIO region. */ -#define HV_TRIO_FIRST_PIO_REGION 8 - -/** The mmap file offset (PA) of a PIO region. */ -#define HV_TRIO_PIO_OFFSET(region) \ - (((unsigned long long)(region) + HV_TRIO_FIRST_PIO_REGION) \ - << TRIO_PIO_REGIONS_ADDR__REGION_SHIFT) - -/** The maximum size of a PIO region. */ -#define HV_TRIO_PIO_SIZE (1ULL << TRIO_PIO_REGIONS_ADDR__ADDR_WIDTH) - - -/** The mmap file offset (PA) of a push DMA region. */ -#define HV_TRIO_PUSH_DMA_OFFSET(ring) \ - (((unsigned long long)TRIO_MMIO_ADDRESS_SPACE__REGION_VAL_PUSH_DMA << \ - TRIO_MMIO_ADDRESS_SPACE__REGION_SHIFT) | \ - ((ring) << TRIO_PUSH_DMA_REGION_ADDR__RING_SEL_SHIFT)) - -/** The mmap file offset (PA) of a pull DMA region. */ -#define HV_TRIO_PULL_DMA_OFFSET(ring) \ - (((unsigned long long)TRIO_MMIO_ADDRESS_SPACE__REGION_VAL_PULL_DMA << \ - TRIO_MMIO_ADDRESS_SPACE__REGION_SHIFT) | \ - ((ring) << TRIO_PULL_DMA_REGION_ADDR__RING_SEL_SHIFT)) - -/** The maximum size of a DMA region. */ -#define HV_TRIO_DMA_REGION_SIZE \ - (1ULL << TRIO_PUSH_DMA_REGION_ADDR__RING_SEL_SHIFT) - - -/** The mmap file offset (PA) of a Mem-Map interrupt region. */ -#define HV_TRIO_MEM_MAP_INTR_OFFSET(map) \ - (((unsigned long long)TRIO_MMIO_ADDRESS_SPACE__REGION_VAL_MAP_MEM << \ - TRIO_MMIO_ADDRESS_SPACE__REGION_SHIFT) | \ - ((map) << TRIO_MAP_MEM_REGION_ADDR__MAP_SEL_SHIFT)) - -/** The maximum size of a Mem-Map interrupt region. */ -#define HV_TRIO_MEM_MAP_INTR_SIZE \ - (1ULL << TRIO_MAP_MEM_REGION_ADDR__MAP_SEL_SHIFT) - - -/** A flag bit indicating a fixed resource allocation. */ -#define HV_TRIO_ALLOC_FIXED 0x01 - -/** TRIO requires that all mappings have 4kB aligned start addresses. */ -#define HV_TRIO_PAGE_SHIFT 12 - -/** TRIO requires that all mappings have 4kB aligned start addresses. */ -#define HV_TRIO_PAGE_SIZE (1ull << HV_TRIO_PAGE_SHIFT) - - -/* Specify all PCIe port properties for a TRIO. */ -struct pcie_trio_ports_property -{ - struct pcie_port_property ports[TILEGX_TRIO_PCIES]; - - /** Set if this TRIO belongs to a Gx72 device. */ - uint8_t is_gx72; -}; - -/* Flags indicating traffic class. */ -#define HV_TRIO_FLAG_TC_SHIFT 4 -#define HV_TRIO_FLAG_TC_RMASK 0xf -#define HV_TRIO_FLAG_TC(N) \ - ((((N) & HV_TRIO_FLAG_TC_RMASK) + 1) << HV_TRIO_FLAG_TC_SHIFT) - -/* Flags indicating virtual functions. */ -#define HV_TRIO_FLAG_VFUNC_SHIFT 8 -#define HV_TRIO_FLAG_VFUNC_RMASK 0xff -#define HV_TRIO_FLAG_VFUNC(N) \ - ((((N) & HV_TRIO_FLAG_VFUNC_RMASK) + 1) << HV_TRIO_FLAG_VFUNC_SHIFT) - - -/* Flag indicating an ordered PIO region. */ -#define HV_TRIO_PIO_FLAG_ORDERED (1 << 16) - -/* Flags indicating special types of PIO regions. */ -#define HV_TRIO_PIO_FLAG_SPACE_SHIFT 17 -#define HV_TRIO_PIO_FLAG_SPACE_MASK (0x3 << HV_TRIO_PIO_FLAG_SPACE_SHIFT) -#define HV_TRIO_PIO_FLAG_CONFIG_SPACE (0x1 << HV_TRIO_PIO_FLAG_SPACE_SHIFT) -#define HV_TRIO_PIO_FLAG_IO_SPACE (0x2 << HV_TRIO_PIO_FLAG_SPACE_SHIFT) - - -#endif /* _SYS_HV_DRV_TRIO_INTF_H */ diff --git a/arch/tile/include/hv/drv_uart_intf.h b/arch/tile/include/hv/drv_uart_intf.h deleted file mode 100644 index f5379e2404fd..000000000000 --- a/arch/tile/include/hv/drv_uart_intf.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * Interface definitions for the UART driver. - */ - -#ifndef _SYS_HV_DRV_UART_INTF_H -#define _SYS_HV_DRV_UART_INTF_H - -#include - -/** Number of UART ports supported. */ -#define TILEGX_UART_NR 2 - -/** The mmap file offset (PA) of the UART MMIO region. */ -#define HV_UART_MMIO_OFFSET 0 - -/** The maximum size of the UARTs MMIO region (64K Bytes). */ -#define HV_UART_MMIO_SIZE (1UL << 16) - -#endif /* _SYS_HV_DRV_UART_INTF_H */ diff --git a/arch/tile/include/hv/drv_usb_host_intf.h b/arch/tile/include/hv/drv_usb_host_intf.h deleted file mode 100644 index 24ce774a3f1d..000000000000 --- a/arch/tile/include/hv/drv_usb_host_intf.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * Interface definitions for the USB host driver. - */ - -#ifndef _SYS_HV_DRV_USB_HOST_INTF_H -#define _SYS_HV_DRV_USB_HOST_INTF_H - -#include - - -/** Offset for the EHCI register MMIO region. */ -#define HV_USB_HOST_MMIO_OFFSET_EHCI ((uint64_t) USB_HOST_HCCAPBASE_REG) - -/** Offset for the OHCI register MMIO region. */ -#define HV_USB_HOST_MMIO_OFFSET_OHCI ((uint64_t) USB_HOST_OHCD_HC_REVISION_REG) - -/** Size of the register MMIO region. This turns out to be the same for - * both EHCI and OHCI. */ -#define HV_USB_HOST_MMIO_SIZE ((uint64_t) 0x1000) - -/** The number of service domains supported by the USB host shim. */ -#define HV_USB_HOST_NUM_SVC_DOM 1 - - -#endif /* _SYS_HV_DRV_USB_HOST_INTF_H */ diff --git a/arch/tile/include/hv/drv_xgbe_impl.h b/arch/tile/include/hv/drv_xgbe_impl.h deleted file mode 100644 index 3a73b2b44913..000000000000 --- a/arch/tile/include/hv/drv_xgbe_impl.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file drivers/xgbe/impl.h - * Implementation details for the NetIO library. - */ - -#ifndef __DRV_XGBE_IMPL_H__ -#define __DRV_XGBE_IMPL_H__ - -#include -#include -#include - - -/** How many groups we have (log2). */ -#define LOG2_NUM_GROUPS (12) -/** How many groups we have. */ -#define NUM_GROUPS (1 << LOG2_NUM_GROUPS) - -/** Number of output requests we'll buffer per tile. */ -#define EPP_REQS_PER_TILE (32) - -/** Words used in an eDMA command without checksum acceleration. */ -#define EDMA_WDS_NO_CSUM 8 -/** Words used in an eDMA command with checksum acceleration. */ -#define EDMA_WDS_CSUM 10 -/** Total available words in the eDMA command FIFO. */ -#define EDMA_WDS_TOTAL 128 - - -/* - * FIXME: These definitions are internal and should have underscores! - * NOTE: The actual numeric values here are intentional and allow us to - * optimize the concept "if small ... else if large ... else ...", by - * checking for the low bit being set, and then for non-zero. - * These are used as array indices, so they must have the values (0, 1, 2) - * in some order. - */ -#define SIZE_SMALL (1) /**< Small packet queue. */ -#define SIZE_LARGE (2) /**< Large packet queue. */ -#define SIZE_JUMBO (0) /**< Jumbo packet queue. */ - -/** The number of "SIZE_xxx" values. */ -#define NETIO_NUM_SIZES 3 - - -/* - * Default numbers of packets for IPP drivers. These values are chosen - * such that CIPP1 will not overflow its L2 cache. - */ - -/** The default number of small packets. */ -#define NETIO_DEFAULT_SMALL_PACKETS 2750 -/** The default number of large packets. */ -#define NETIO_DEFAULT_LARGE_PACKETS 2500 -/** The default number of jumbo packets. */ -#define NETIO_DEFAULT_JUMBO_PACKETS 250 - - -/** Log2 of the size of a memory arena. */ -#define NETIO_ARENA_SHIFT 24 /* 16 MB */ -/** Size of a memory arena. */ -#define NETIO_ARENA_SIZE (1 << NETIO_ARENA_SHIFT) - - -/** A queue of packets. - * - * This structure partially defines a queue of packets waiting to be - * processed. The queue as a whole is written to by an interrupt handler and - * read by non-interrupt code; this data structure is what's touched by the - * interrupt handler. The other part of the queue state, the read offset, is - * kept in user space, not in hypervisor space, so it is in a separate data - * structure. - * - * The read offset (__packet_receive_read in the user part of the queue - * structure) points to the next packet to be read. When the read offset is - * equal to the write offset, the queue is empty; therefore the queue must - * contain one more slot than the required maximum queue size. - * - * Here's an example of all 3 state variables and what they mean. All - * pointers move left to right. - * - * @code - * I I V V V V I I I I - * 0 1 2 3 4 5 6 7 8 9 10 - * ^ ^ ^ ^ - * | | | - * | | __last_packet_plus_one - * | __buffer_write - * __packet_receive_read - * @endcode - * - * This queue has 10 slots, and thus can hold 9 packets (_last_packet_plus_one - * = 10). The read pointer is at 2, and the write pointer is at 6; thus, - * there are valid, unread packets in slots 2, 3, 4, and 5. The remaining - * slots are invalid (do not contain a packet). - */ -typedef struct { - /** Byte offset of the next notify packet to be written: zero for the first - * packet on the queue, sizeof (netio_pkt_t) for the second packet on the - * queue, etc. */ - volatile uint32_t __packet_write; - - /** Offset of the packet after the last valid packet (i.e., when any - * pointer is incremented to this value, it wraps back to zero). */ - uint32_t __last_packet_plus_one; -} -__netio_packet_queue_t; - - -/** A queue of buffers. - * - * This structure partially defines a queue of empty buffers which have been - * obtained via requests to the IPP. (The elements of the queue are packet - * handles, which are transformed into a full netio_pkt_t when the buffer is - * retrieved.) The queue as a whole is written to by an interrupt handler and - * read by non-interrupt code; this data structure is what's touched by the - * interrupt handler. The other parts of the queue state, the read offset and - * requested write offset, are kept in user space, not in hypervisor space, so - * they are in a separate data structure. - * - * The read offset (__buffer_read in the user part of the queue structure) - * points to the next buffer to be read. When the read offset is equal to the - * write offset, the queue is empty; therefore the queue must contain one more - * slot than the required maximum queue size. - * - * The requested write offset (__buffer_requested_write in the user part of - * the queue structure) points to the slot which will hold the next buffer we - * request from the IPP, once we get around to sending such a request. When - * the requested write offset is equal to the write offset, no requests for - * new buffers are outstanding; when the requested write offset is one greater - * than the read offset, no more requests may be sent. - * - * Note that, unlike the packet_queue, the buffer_queue places incoming - * buffers at decreasing addresses. This makes the check for "is it time to - * wrap the buffer pointer" cheaper in the assembly code which receives new - * buffers, and means that the value which defines the queue size, - * __last_buffer, is different than in the packet queue. Also, the offset - * used in the packet_queue is already scaled by the size of a packet; here we - * use unscaled slot indices for the offsets. (These differences are - * historical, and in the future it's possible that the packet_queue will look - * more like this queue.) - * - * @code - * Here's an example of all 4 state variables and what they mean. Remember: - * all pointers move right to left. - * - * V V V I I R R V V V - * 0 1 2 3 4 5 6 7 8 9 - * ^ ^ ^ ^ - * | | | | - * | | | __last_buffer - * | | __buffer_write - * | __buffer_requested_write - * __buffer_read - * @endcode - * - * This queue has 10 slots, and thus can hold 9 buffers (_last_buffer = 9). - * The read pointer is at 2, and the write pointer is at 6; thus, there are - * valid, unread buffers in slots 2, 1, 0, 9, 8, and 7. The requested write - * pointer is at 4; thus, requests have been made to the IPP for buffers which - * will be placed in slots 6 and 5 when they arrive. Finally, the remaining - * slots are invalid (do not contain a buffer). - */ -typedef struct -{ - /** Ordinal number of the next buffer to be written: 0 for the first slot in - * the queue, 1 for the second slot in the queue, etc. */ - volatile uint32_t __buffer_write; - - /** Ordinal number of the last buffer (i.e., when any pointer is decremented - * below zero, it is reloaded with this value). */ - uint32_t __last_buffer; -} -__netio_buffer_queue_t; - - -/** - * An object for providing Ethernet packets to a process. - */ -typedef struct __netio_queue_impl_t -{ - /** The queue of packets waiting to be received. */ - __netio_packet_queue_t __packet_receive_queue; - /** The intr bit mask that IDs this device. */ - unsigned int __intr_id; - /** Offset to queues of empty buffers, one per size. */ - uint32_t __buffer_queue[NETIO_NUM_SIZES]; - /** The address of the first EPP tile, or -1 if no EPP. */ - /* ISSUE: Actually this is always "0" or "~0". */ - uint32_t __epp_location; - /** The queue ID that this queue represents. */ - unsigned int __queue_id; - /** Number of acknowledgements received. */ - volatile uint32_t __acks_received; - /** Last completion number received for packet_sendv. */ - volatile uint32_t __last_completion_rcv; - /** Number of packets allowed to be outstanding. */ - uint32_t __max_outstanding; - /** First VA available for packets. */ - void* __va_0; - /** First VA in second range available for packets. */ - void* __va_1; - /** Padding to align the "__packets" field to the size of a netio_pkt_t. */ - uint32_t __padding[3]; - /** The packets themselves. */ - netio_pkt_t __packets[0]; -} -netio_queue_impl_t; - - -/** - * An object for managing the user end of a NetIO queue. - */ -typedef struct __netio_queue_user_impl_t -{ - /** The next incoming packet to be read. */ - uint32_t __packet_receive_read; - /** The next empty buffers to be read, one index per size. */ - uint8_t __buffer_read[NETIO_NUM_SIZES]; - /** Where the empty buffer we next request from the IPP will go, one index - * per size. */ - uint8_t __buffer_requested_write[NETIO_NUM_SIZES]; - /** PCIe interface flag. */ - uint8_t __pcie; - /** Number of packets left to be received before we send a credit update. */ - uint32_t __receive_credit_remaining; - /** Value placed in __receive_credit_remaining when it reaches zero. */ - uint32_t __receive_credit_interval; - /** First fast I/O routine index. */ - uint32_t __fastio_index; - /** Number of acknowledgements expected. */ - uint32_t __acks_outstanding; - /** Last completion number requested. */ - uint32_t __last_completion_req; - /** File descriptor for driver. */ - int __fd; -} -netio_queue_user_impl_t; - - -#define NETIO_GROUP_CHUNK_SIZE 64 /**< Max # groups in one IPP request */ -#define NETIO_BUCKET_CHUNK_SIZE 64 /**< Max # buckets in one IPP request */ - - -/** Internal structure used to convey packet send information to the - * hypervisor. FIXME: Actually, it's not used for that anymore, but - * netio_packet_send() still uses it internally. - */ -typedef struct -{ - uint16_t flags; /**< Packet flags (__NETIO_SEND_FLG_xxx) */ - uint16_t transfer_size; /**< Size of packet */ - uint32_t va; /**< VA of start of packet */ - __netio_pkt_handle_t handle; /**< Packet handle */ - uint32_t csum0; /**< First checksum word */ - uint32_t csum1; /**< Second checksum word */ -} -__netio_send_cmd_t; - - -/** Flags used in two contexts: - * - As the "flags" member in the __netio_send_cmd_t, above; used only - * for netio_pkt_send_{prepare,commit}. - * - As part of the flags passed to the various send packet fast I/O calls. - */ - -/** Need acknowledgement on this packet. Note that some code in the - * normal send_pkt fast I/O handler assumes that this is equal to 1. */ -#define __NETIO_SEND_FLG_ACK 0x1 - -/** Do checksum on this packet. (Only used with the __netio_send_cmd_t; - * normal packet sends use a special fast I/O index to denote checksumming, - * and multi-segment sends test the checksum descriptor.) */ -#define __NETIO_SEND_FLG_CSUM 0x2 - -/** Get a completion on this packet. Only used with multi-segment sends. */ -#define __NETIO_SEND_FLG_COMPLETION 0x4 - -/** Position of the number-of-extra-segments value in the flags word. - Only used with multi-segment sends. */ -#define __NETIO_SEND_FLG_XSEG_SHIFT 3 - -/** Width of the number-of-extra-segments value in the flags word. */ -#define __NETIO_SEND_FLG_XSEG_WIDTH 2 - -#endif /* __DRV_XGBE_IMPL_H__ */ diff --git a/arch/tile/include/hv/drv_xgbe_intf.h b/arch/tile/include/hv/drv_xgbe_intf.h deleted file mode 100644 index 2a20b266d944..000000000000 --- a/arch/tile/include/hv/drv_xgbe_intf.h +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file drv_xgbe_intf.h - * Interface to the hypervisor XGBE driver. - */ - -#ifndef __DRV_XGBE_INTF_H__ -#define __DRV_XGBE_INTF_H__ - -/** - * An object for forwarding VAs and PAs to the hypervisor. - * @ingroup types - * - * This allows the supervisor to specify a number of areas of memory to - * store packet buffers. - */ -typedef struct -{ - /** The physical address of the memory. */ - HV_PhysAddr pa; - /** Page table entry for the memory. This is only used to derive the - * memory's caching mode; the PA bits are ignored. */ - HV_PTE pte; - /** The virtual address of the memory. */ - HV_VirtAddr va; - /** Size (in bytes) of the memory area. */ - int size; - -} -netio_ipp_address_t; - -/** The various pread/pwrite offsets into the hypervisor-level driver. - * @ingroup types - */ -typedef enum -{ - /** Inform the Linux driver of the address of the NetIO arena memory. - * This offset is actually only used to convey information from netio - * to the Linux driver; it never makes it from there to the hypervisor. - * Write-only; takes a uint32_t specifying the VA address. */ - NETIO_FIXED_ADDR = 0x5000000000000000ULL, - - /** Inform the Linux driver of the size of the NetIO arena memory. - * This offset is actually only used to convey information from netio - * to the Linux driver; it never makes it from there to the hypervisor. - * Write-only; takes a uint32_t specifying the VA size. */ - NETIO_FIXED_SIZE = 0x5100000000000000ULL, - - /** Register current tile with IPP. Write then read: write, takes a - * netio_input_config_t, read returns a pointer to a netio_queue_impl_t. */ - NETIO_IPP_INPUT_REGISTER_OFF = 0x6000000000000000ULL, - - /** Unregister current tile from IPP. Write-only, takes a dummy argument. */ - NETIO_IPP_INPUT_UNREGISTER_OFF = 0x6100000000000000ULL, - - /** Start packets flowing. Write-only, takes a dummy argument. */ - NETIO_IPP_INPUT_INIT_OFF = 0x6200000000000000ULL, - - /** Stop packets flowing. Write-only, takes a dummy argument. */ - NETIO_IPP_INPUT_UNINIT_OFF = 0x6300000000000000ULL, - - /** Configure group (typically we group on VLAN). Write-only: takes an - * array of netio_group_t's, low 24 bits of the offset is the base group - * number times the size of a netio_group_t. */ - NETIO_IPP_INPUT_GROUP_CFG_OFF = 0x6400000000000000ULL, - - /** Configure bucket. Write-only: takes an array of netio_bucket_t's, low - * 24 bits of the offset is the base bucket number times the size of a - * netio_bucket_t. */ - NETIO_IPP_INPUT_BUCKET_CFG_OFF = 0x6500000000000000ULL, - - /** Get/set a parameter. Read or write: read or write data is the parameter - * value, low 32 bits of the offset is a __netio_getset_offset_t. */ - NETIO_IPP_PARAM_OFF = 0x6600000000000000ULL, - - /** Get fast I/O index. Read-only; returns a 4-byte base index value. */ - NETIO_IPP_GET_FASTIO_OFF = 0x6700000000000000ULL, - - /** Configure hijack IP address. Packets with this IPv4 dest address - * go to bucket NETIO_NUM_BUCKETS - 1. Write-only: takes an IP address - * in some standard form. FIXME: Define the form! */ - NETIO_IPP_INPUT_HIJACK_CFG_OFF = 0x6800000000000000ULL, - - /** - * Offsets beyond this point are reserved for the supervisor (although that - * enforcement must be done by the supervisor driver itself). - */ - NETIO_IPP_USER_MAX_OFF = 0x6FFFFFFFFFFFFFFFULL, - - /** Register I/O memory. Write-only, takes a netio_ipp_address_t. */ - NETIO_IPP_IOMEM_REGISTER_OFF = 0x7000000000000000ULL, - - /** Unregister I/O memory. Write-only, takes a netio_ipp_address_t. */ - NETIO_IPP_IOMEM_UNREGISTER_OFF = 0x7100000000000000ULL, - - /* Offsets greater than 0x7FFFFFFF can't be used directly from Linux - * userspace code due to limitations in the pread/pwrite syscalls. */ - - /** Drain LIPP buffers. */ - NETIO_IPP_DRAIN_OFF = 0xFA00000000000000ULL, - - /** Supply a netio_ipp_address_t to be used as shared memory for the - * LEPP command queue. */ - NETIO_EPP_SHM_OFF = 0xFB00000000000000ULL, - - /* 0xFC... is currently unused. */ - - /** Stop IPP/EPP tiles. Write-only, takes a dummy argument. */ - NETIO_IPP_STOP_SHIM_OFF = 0xFD00000000000000ULL, - - /** Start IPP/EPP tiles. Write-only, takes a dummy argument. */ - NETIO_IPP_START_SHIM_OFF = 0xFE00000000000000ULL, - - /** Supply packet arena. Write-only, takes an array of - * netio_ipp_address_t values. */ - NETIO_IPP_ADDRESS_OFF = 0xFF00000000000000ULL, -} netio_hv_offset_t; - -/** Extract the base offset from an offset */ -#define NETIO_BASE_OFFSET(off) ((off) & 0xFF00000000000000ULL) -/** Extract the local offset from an offset */ -#define NETIO_LOCAL_OFFSET(off) ((off) & 0x00FFFFFFFFFFFFFFULL) - - -/** - * Get/set offset. - */ -typedef union -{ - struct - { - uint64_t addr:48; /**< Class-specific address */ - unsigned int class:8; /**< Class (e.g., NETIO_PARAM) */ - unsigned int opcode:8; /**< High 8 bits of NETIO_IPP_PARAM_OFF */ - } - bits; /**< Bitfields */ - uint64_t word; /**< Aggregated value to use as the offset */ -} -__netio_getset_offset_t; - -/** - * Fast I/O index offsets (must be contiguous). - */ -typedef enum -{ - NETIO_FASTIO_ALLOCATE = 0, /**< Get empty packet buffer */ - NETIO_FASTIO_FREE_BUFFER = 1, /**< Give buffer back to IPP */ - NETIO_FASTIO_RETURN_CREDITS = 2, /**< Give credits to IPP */ - NETIO_FASTIO_SEND_PKT_NOCK = 3, /**< Send a packet, no checksum */ - NETIO_FASTIO_SEND_PKT_CK = 4, /**< Send a packet, with checksum */ - NETIO_FASTIO_SEND_PKT_VEC = 5, /**< Send a vector of packets */ - NETIO_FASTIO_SENDV_PKT = 6, /**< Sendv one packet */ - NETIO_FASTIO_NUM_INDEX = 7, /**< Total number of fast I/O indices */ -} netio_fastio_index_t; - -/** 3-word return type for Fast I/O call. */ -typedef struct -{ - int err; /**< Error code. */ - uint32_t val0; /**< Value. Meaning depends upon the specific call. */ - uint32_t val1; /**< Value. Meaning depends upon the specific call. */ -} netio_fastio_rv3_t; - -/** 0-argument fast I/O call */ -int __netio_fastio0(uint32_t fastio_index); -/** 1-argument fast I/O call */ -int __netio_fastio1(uint32_t fastio_index, uint32_t arg0); -/** 3-argument fast I/O call, 2-word return value */ -netio_fastio_rv3_t __netio_fastio3_rv3(uint32_t fastio_index, uint32_t arg0, - uint32_t arg1, uint32_t arg2); -/** 4-argument fast I/O call */ -int __netio_fastio4(uint32_t fastio_index, uint32_t arg0, uint32_t arg1, - uint32_t arg2, uint32_t arg3); -/** 6-argument fast I/O call */ -int __netio_fastio6(uint32_t fastio_index, uint32_t arg0, uint32_t arg1, - uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5); -/** 9-argument fast I/O call */ -int __netio_fastio9(uint32_t fastio_index, uint32_t arg0, uint32_t arg1, - uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5, - uint32_t arg6, uint32_t arg7, uint32_t arg8); - -/** Allocate an empty packet. - * @param fastio_index Fast I/O index. - * @param size Size of the packet to allocate. - */ -#define __netio_fastio_allocate(fastio_index, size) \ - __netio_fastio1((fastio_index) + NETIO_FASTIO_ALLOCATE, size) - -/** Free a buffer. - * @param fastio_index Fast I/O index. - * @param handle Handle for the packet to free. - */ -#define __netio_fastio_free_buffer(fastio_index, handle) \ - __netio_fastio1((fastio_index) + NETIO_FASTIO_FREE_BUFFER, handle) - -/** Increment our receive credits. - * @param fastio_index Fast I/O index. - * @param credits Number of credits to add. - */ -#define __netio_fastio_return_credits(fastio_index, credits) \ - __netio_fastio1((fastio_index) + NETIO_FASTIO_RETURN_CREDITS, credits) - -/** Send packet, no checksum. - * @param fastio_index Fast I/O index. - * @param ackflag Nonzero if we want an ack. - * @param size Size of the packet. - * @param va Virtual address of start of packet. - * @param handle Packet handle. - */ -#define __netio_fastio_send_pkt_nock(fastio_index, ackflag, size, va, handle) \ - __netio_fastio4((fastio_index) + NETIO_FASTIO_SEND_PKT_NOCK, ackflag, \ - size, va, handle) - -/** Send packet, calculate checksum. - * @param fastio_index Fast I/O index. - * @param ackflag Nonzero if we want an ack. - * @param size Size of the packet. - * @param va Virtual address of start of packet. - * @param handle Packet handle. - * @param csum0 Shim checksum header. - * @param csum1 Checksum seed. - */ -#define __netio_fastio_send_pkt_ck(fastio_index, ackflag, size, va, handle, \ - csum0, csum1) \ - __netio_fastio6((fastio_index) + NETIO_FASTIO_SEND_PKT_CK, ackflag, \ - size, va, handle, csum0, csum1) - - -/** Format for the "csum0" argument to the __netio_fastio_send routines - * and LEPP. Note that this is currently exactly identical to the - * ShimProtocolOffloadHeader. - */ -typedef union -{ - struct - { - unsigned int start_byte:7; /**< The first byte to be checksummed */ - unsigned int count:14; /**< Number of bytes to be checksummed. */ - unsigned int destination_byte:7; /**< The byte to write the checksum to. */ - unsigned int reserved:4; /**< Reserved. */ - } bits; /**< Decomposed method of access. */ - unsigned int word; /**< To send out the IDN. */ -} __netio_checksum_header_t; - - -/** Sendv packet with 1 or 2 segments. - * @param fastio_index Fast I/O index. - * @param flags Ack/csum/notify flags in low 3 bits; number of segments minus - * 1 in next 2 bits; expected checksum in high 16 bits. - * @param confno Confirmation number to request, if notify flag set. - * @param csum0 Checksum descriptor; if zero, no checksum. - * @param va_F Virtual address of first segment. - * @param va_L Virtual address of last segment, if 2 segments. - * @param len_F_L Length of first segment in low 16 bits; length of last - * segment, if 2 segments, in high 16 bits. - */ -#define __netio_fastio_sendv_pkt_1_2(fastio_index, flags, confno, csum0, \ - va_F, va_L, len_F_L) \ - __netio_fastio6((fastio_index) + NETIO_FASTIO_SENDV_PKT, flags, confno, \ - csum0, va_F, va_L, len_F_L) - -/** Send packet on PCIe interface. - * @param fastio_index Fast I/O index. - * @param flags Ack/csum/notify flags in low 3 bits. - * @param confno Confirmation number to request, if notify flag set. - * @param csum0 Checksum descriptor; Hard wired 0, not needed for PCIe. - * @param va_F Virtual address of the packet buffer. - * @param va_L Virtual address of last segment, if 2 segments. Hard wired 0. - * @param len_F_L Length of the packet buffer in low 16 bits. - */ -#define __netio_fastio_send_pcie_pkt(fastio_index, flags, confno, csum0, \ - va_F, va_L, len_F_L) \ - __netio_fastio6((fastio_index) + PCIE_FASTIO_SENDV_PKT, flags, confno, \ - csum0, va_F, va_L, len_F_L) - -/** Sendv packet with 3 or 4 segments. - * @param fastio_index Fast I/O index. - * @param flags Ack/csum/notify flags in low 3 bits; number of segments minus - * 1 in next 2 bits; expected checksum in high 16 bits. - * @param confno Confirmation number to request, if notify flag set. - * @param csum0 Checksum descriptor; if zero, no checksum. - * @param va_F Virtual address of first segment. - * @param va_L Virtual address of last segment (third segment if 3 segments, - * fourth segment if 4 segments). - * @param len_F_L Length of first segment in low 16 bits; length of last - * segment in high 16 bits. - * @param va_M0 Virtual address of "middle 0" segment; this segment is sent - * second when there are three segments, and third if there are four. - * @param va_M1 Virtual address of "middle 1" segment; this segment is sent - * second when there are four segments. - * @param len_M0_M1 Length of middle 0 segment in low 16 bits; length of middle - * 1 segment, if 4 segments, in high 16 bits. - */ -#define __netio_fastio_sendv_pkt_3_4(fastio_index, flags, confno, csum0, va_F, \ - va_L, len_F_L, va_M0, va_M1, len_M0_M1) \ - __netio_fastio9((fastio_index) + NETIO_FASTIO_SENDV_PKT, flags, confno, \ - csum0, va_F, va_L, len_F_L, va_M0, va_M1, len_M0_M1) - -/** Send vector of packets. - * @param fastio_index Fast I/O index. - * @param seqno Number of packets transmitted so far on this interface; - * used to decide which packets should be acknowledged. - * @param nentries Number of entries in vector. - * @param va Virtual address of start of vector entry array. - * @return 3-word netio_fastio_rv3_t structure. The structure's err member - * is an error code, or zero if no error. The val0 member is the - * updated value of seqno; it has been incremented by 1 for each - * packet sent. That increment may be less than nentries if an - * error occurred, or if some of the entries in the vector contain - * handles equal to NETIO_PKT_HANDLE_NONE. The val1 member is the - * updated value of nentries; it has been decremented by 1 for each - * vector entry processed. Again, that decrement may be less than - * nentries (leaving the returned value positive) if an error - * occurred. - */ -#define __netio_fastio_send_pkt_vec(fastio_index, seqno, nentries, va) \ - __netio_fastio3_rv3((fastio_index) + NETIO_FASTIO_SEND_PKT_VEC, seqno, \ - nentries, va) - - -/** An egress DMA command for LEPP. */ -typedef struct -{ - /** Is this a TSO transfer? - * - * NOTE: This field is always 0, to distinguish it from - * lepp_tso_cmd_t. It must come first! - */ - uint8_t tso : 1; - - /** Unused padding bits. */ - uint8_t _unused : 3; - - /** Should this packet be sent directly from caches instead of DRAM, - * using hash-for-home to locate the packet data? - */ - uint8_t hash_for_home : 1; - - /** Should we compute a checksum? */ - uint8_t compute_checksum : 1; - - /** Is this the final buffer for this packet? - * - * A single packet can be split over several input buffers (a "gather" - * operation). This flag indicates that this is the last buffer - * in a packet. - */ - uint8_t end_of_packet : 1; - - /** Should LEPP advance 'comp_busy' when this DMA is fully finished? */ - uint8_t send_completion : 1; - - /** High bits of Client Physical Address of the start of the buffer - * to be egressed. - * - * NOTE: Only 6 bits are actually needed here, as CPAs are - * currently 38 bits. So two bits could be scavenged from this. - */ - uint8_t cpa_hi; - - /** The number of bytes to be egressed. */ - uint16_t length; - - /** Low 32 bits of Client Physical Address of the start of the buffer - * to be egressed. - */ - uint32_t cpa_lo; - - /** Checksum information (only used if 'compute_checksum'). */ - __netio_checksum_header_t checksum_data; - -} lepp_cmd_t; - - -/** A chunk of physical memory for a TSO egress. */ -typedef struct -{ - /** The low bits of the CPA. */ - uint32_t cpa_lo; - /** The high bits of the CPA. */ - uint16_t cpa_hi : 15; - /** Should this packet be sent directly from caches instead of DRAM, - * using hash-for-home to locate the packet data? - */ - uint16_t hash_for_home : 1; - /** The length in bytes. */ - uint16_t length; -} lepp_frag_t; - - -/** An LEPP command that handles TSO. */ -typedef struct -{ - /** Is this a TSO transfer? - * - * NOTE: This field is always 1, to distinguish it from - * lepp_cmd_t. It must come first! - */ - uint8_t tso : 1; - - /** Unused padding bits. */ - uint8_t _unused : 7; - - /** Size of the header[] array in bytes. It must be in the range - * [40, 127], which are the smallest header for a TCP packet over - * Ethernet and the maximum possible prepend size supported by - * hardware, respectively. Note that the array storage must be - * padded out to a multiple of four bytes so that the following - * LEPP command is aligned properly. - */ - uint8_t header_size; - - /** Byte offset of the IP header in header[]. */ - uint8_t ip_offset; - - /** Byte offset of the TCP header in header[]. */ - uint8_t tcp_offset; - - /** The number of bytes to use for the payload of each packet, - * except of course the last one, which may not have enough bytes. - * This means that each Ethernet packet except the last will have a - * size of header_size + payload_size. - */ - uint16_t payload_size; - - /** The length of the 'frags' array that follows this struct. */ - uint16_t num_frags; - - /** The actual frags. */ - lepp_frag_t frags[0 /* Variable-sized; num_frags entries. */]; - - /* - * The packet header template logically follows frags[], - * but you can't declare that in C. - * - * uint32_t header[header_size_in_words_rounded_up]; - */ - -} lepp_tso_cmd_t; - - -/** An LEPP completion ring entry. */ -typedef void* lepp_comp_t; - - -/** Maximum number of frags for one TSO command. This is adapted from - * linux's "MAX_SKB_FRAGS", and presumably over-estimates by one, for - * our page size of exactly 65536. We add one for a "body" fragment. - */ -#define LEPP_MAX_FRAGS (65536 / HV_DEFAULT_PAGE_SIZE_SMALL + 2 + 1) - -/** Total number of bytes needed for an lepp_tso_cmd_t. */ -#define LEPP_TSO_CMD_SIZE(num_frags, header_size) \ - (sizeof(lepp_tso_cmd_t) + \ - (num_frags) * sizeof(lepp_frag_t) + \ - (((header_size) + 3) & -4)) - -/** The size of the lepp "cmd" queue. */ -#define LEPP_CMD_QUEUE_BYTES \ - (((CHIP_L2_CACHE_SIZE() - 2 * CHIP_L2_LINE_SIZE()) / \ - (sizeof(lepp_cmd_t) + sizeof(lepp_comp_t))) * sizeof(lepp_cmd_t)) - -/** The largest possible command that can go in lepp_queue_t::cmds[]. */ -#define LEPP_MAX_CMD_SIZE LEPP_TSO_CMD_SIZE(LEPP_MAX_FRAGS, 128) - -/** The largest possible value of lepp_queue_t::cmd_{head, tail} (inclusive). - */ -#define LEPP_CMD_LIMIT \ - (LEPP_CMD_QUEUE_BYTES - LEPP_MAX_CMD_SIZE) - -/** The maximum number of completions in an LEPP queue. */ -#define LEPP_COMP_QUEUE_SIZE \ - ((LEPP_CMD_LIMIT + sizeof(lepp_cmd_t) - 1) / sizeof(lepp_cmd_t)) - -/** Increment an index modulo the queue size. */ -#define LEPP_QINC(var) \ - (var = __insn_mnz(var - (LEPP_COMP_QUEUE_SIZE - 1), var + 1)) - -/** A queue used to convey egress commands from the client to LEPP. */ -typedef struct -{ - /** Index of first completion not yet processed by user code. - * If this is equal to comp_busy, there are no such completions. - * - * NOTE: This is only read/written by the user. - */ - unsigned int comp_head; - - /** Index of first completion record not yet completed. - * If this is equal to comp_tail, there are no such completions. - * This index gets advanced (modulo LEPP_QUEUE_SIZE) whenever - * a command with the 'completion' bit set is finished. - * - * NOTE: This is only written by LEPP, only read by the user. - */ - volatile unsigned int comp_busy; - - /** Index of the first empty slot in the completion ring. - * Entries from this up to but not including comp_head (in ring order) - * can be filled in with completion data. - * - * NOTE: This is only read/written by the user. - */ - unsigned int comp_tail; - - /** Byte index of first command enqueued for LEPP but not yet processed. - * - * This is always divisible by sizeof(void*) and always <= LEPP_CMD_LIMIT. - * - * NOTE: LEPP advances this counter as soon as it no longer needs - * the cmds[] storage for this entry, but the transfer is not actually - * complete (i.e. the buffer pointed to by the command is no longer - * needed) until comp_busy advances. - * - * If this is equal to cmd_tail, the ring is empty. - * - * NOTE: This is only written by LEPP, only read by the user. - */ - volatile unsigned int cmd_head; - - /** Byte index of first empty slot in the command ring. This field can - * be incremented up to but not equal to cmd_head (because that would - * mean the ring is empty). - * - * This is always divisible by sizeof(void*) and always <= LEPP_CMD_LIMIT. - * - * NOTE: This is read/written by the user, only read by LEPP. - */ - volatile unsigned int cmd_tail; - - /** A ring of variable-sized egress DMA commands. - * - * NOTE: Only written by the user, only read by LEPP. - */ - char cmds[LEPP_CMD_QUEUE_BYTES] - __attribute__((aligned(CHIP_L2_LINE_SIZE()))); - - /** A ring of user completion data. - * NOTE: Only read/written by the user. - */ - lepp_comp_t comps[LEPP_COMP_QUEUE_SIZE] - __attribute__((aligned(CHIP_L2_LINE_SIZE()))); -} lepp_queue_t; - - -/** An internal helper function for determining the number of entries - * available in a ring buffer, given that there is one sentinel. - */ -static inline unsigned int -_lepp_num_free_slots(unsigned int head, unsigned int tail) -{ - /* - * One entry is reserved for use as a sentinel, to distinguish - * "empty" from "full". So we compute - * (head - tail - 1) % LEPP_QUEUE_SIZE, but without using a slow % operation. - */ - return (head - tail - 1) + ((head <= tail) ? LEPP_COMP_QUEUE_SIZE : 0); -} - - -/** Returns how many new comp entries can be enqueued. */ -static inline unsigned int -lepp_num_free_comp_slots(const lepp_queue_t* q) -{ - return _lepp_num_free_slots(q->comp_head, q->comp_tail); -} - -static inline int -lepp_qsub(int v1, int v2) -{ - int delta = v1 - v2; - return delta + ((delta >> 31) & LEPP_COMP_QUEUE_SIZE); -} - - -/** FIXME: Check this from linux, via a new "pwrite()" call. */ -#define LIPP_VERSION 1 - - -/** We use exactly two bytes of alignment padding. */ -#define LIPP_PACKET_PADDING 2 - -/** The minimum size of a "small" buffer (including the padding). */ -#define LIPP_SMALL_PACKET_SIZE 128 - -/* - * NOTE: The following two values should total to less than around - * 13582, to keep the total size used for "lipp_state_t" below 64K. - */ - -/** The maximum number of "small" buffers. - * This is enough for 53 network cpus with 128 credits. Note that - * if these are exhausted, we will fall back to using large buffers. - */ -#define LIPP_SMALL_BUFFERS 6785 - -/** The maximum number of "large" buffers. - * This is enough for 53 network cpus with 128 credits. - */ -#define LIPP_LARGE_BUFFERS 6785 - -#endif /* __DRV_XGBE_INTF_H__ */ diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h deleted file mode 100644 index f10b332b3b65..000000000000 --- a/arch/tile/include/hv/hypervisor.h +++ /dev/null @@ -1,2656 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file hypervisor.h - * The hypervisor's public API. - */ - -#ifndef _HV_HV_H -#define _HV_HV_H - -#include - -/* Linux builds want unsigned long constants, but assembler wants numbers */ -#ifdef __ASSEMBLER__ -/** One, for assembler */ -#define __HV_SIZE_ONE 1 -#elif !defined(__tile__) && CHIP_VA_WIDTH() > 32 -/** One, for 64-bit on host */ -#define __HV_SIZE_ONE 1ULL -#else -/** One, for Linux */ -#define __HV_SIZE_ONE 1UL -#endif - -/** The log2 of the span of a level-1 page table, in bytes. - */ -#define HV_LOG2_L1_SPAN 32 - -/** The span of a level-1 page table, in bytes. - */ -#define HV_L1_SPAN (__HV_SIZE_ONE << HV_LOG2_L1_SPAN) - -/** The log2 of the initial size of small pages, in bytes. - * See HV_DEFAULT_PAGE_SIZE_SMALL. - */ -#define HV_LOG2_DEFAULT_PAGE_SIZE_SMALL 16 - -/** The initial size of small pages, in bytes. This value should be verified - * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL). - * It may also be modified when installing a new context. - */ -#define HV_DEFAULT_PAGE_SIZE_SMALL \ - (__HV_SIZE_ONE << HV_LOG2_DEFAULT_PAGE_SIZE_SMALL) - -/** The log2 of the initial size of large pages, in bytes. - * See HV_DEFAULT_PAGE_SIZE_LARGE. - */ -#define HV_LOG2_DEFAULT_PAGE_SIZE_LARGE 24 - -/** The initial size of large pages, in bytes. This value should be verified - * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE). - * It may also be modified when installing a new context. - */ -#define HV_DEFAULT_PAGE_SIZE_LARGE \ - (__HV_SIZE_ONE << HV_LOG2_DEFAULT_PAGE_SIZE_LARGE) - -#if CHIP_VA_WIDTH() > 32 - -/** The log2 of the initial size of jumbo pages, in bytes. - * See HV_DEFAULT_PAGE_SIZE_JUMBO. - */ -#define HV_LOG2_DEFAULT_PAGE_SIZE_JUMBO 32 - -/** The initial size of jumbo pages, in bytes. This value should - * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_JUMBO). - * It may also be modified when installing a new context. - */ -#define HV_DEFAULT_PAGE_SIZE_JUMBO \ - (__HV_SIZE_ONE << HV_LOG2_DEFAULT_PAGE_SIZE_JUMBO) - -#endif - -/** The log2 of the granularity at which page tables must be aligned; - * in other words, the CPA for a page table must have this many zero - * bits at the bottom of the address. - */ -#define HV_LOG2_PAGE_TABLE_ALIGN 11 - -/** The granularity at which page tables must be aligned. - */ -#define HV_PAGE_TABLE_ALIGN (__HV_SIZE_ONE << HV_LOG2_PAGE_TABLE_ALIGN) - -/** Normal start of hypervisor glue in client physical memory. */ -#define HV_GLUE_START_CPA 0x10000 - -/** This much space is reserved at HV_GLUE_START_CPA - * for the hypervisor glue. The client program must start at - * some address higher than this, and in particular the address of - * its text section should be equal to zero modulo HV_PAGE_SIZE_LARGE - * so that relative offsets to the HV glue are correct. - */ -#define HV_GLUE_RESERVED_SIZE 0x10000 - -/** Each entry in the hv dispatch array takes this many bytes. */ -#define HV_DISPATCH_ENTRY_SIZE 32 - -/** Version of the hypervisor interface defined by this file */ -#define _HV_VERSION 13 - -/** Last version of the hypervisor interface with old hv_init() ABI. - * - * The change from version 12 to version 13 corresponds to launching - * the client by default at PL2 instead of PL1 (corresponding to the - * hv itself running at PL3 instead of PL2). To make this explicit, - * the hv_init() API was also extended so the client can report its - * desired PL, resulting in a more helpful failure diagnostic. If you - * call hv_init() with _HV_VERSION_OLD_HV_INIT and omit the client_pl - * argument, the hypervisor will assume client_pl = 1. - * - * Note that this is a deprecated solution and we do not expect to - * support clients of the Tilera hypervisor running at PL1 indefinitely. - */ -#define _HV_VERSION_OLD_HV_INIT 12 - -/* Index into hypervisor interface dispatch code blocks. - * - * Hypervisor calls are invoked from user space by calling code - * at an address HV_BASE_ADDRESS + (index) * HV_DISPATCH_ENTRY_SIZE, - * where index is one of these enum values. - * - * Normally a supervisor is expected to produce a set of symbols - * starting at HV_BASE_ADDRESS that obey this convention, but a user - * program could call directly through function pointers if desired. - * - * These numbers are part of the binary API and will not be changed - * without updating HV_VERSION, which should be a rare event. - */ - -/** reserved. */ -#define _HV_DISPATCH_RESERVED 0 - -/** hv_init */ -#define HV_DISPATCH_INIT 1 - -/** hv_install_context */ -#define HV_DISPATCH_INSTALL_CONTEXT 2 - -/** hv_sysconf */ -#define HV_DISPATCH_SYSCONF 3 - -/** hv_get_rtc */ -#define HV_DISPATCH_GET_RTC 4 - -/** hv_set_rtc */ -#define HV_DISPATCH_SET_RTC 5 - -/** hv_flush_asid */ -#define HV_DISPATCH_FLUSH_ASID 6 - -/** hv_flush_page */ -#define HV_DISPATCH_FLUSH_PAGE 7 - -/** hv_flush_pages */ -#define HV_DISPATCH_FLUSH_PAGES 8 - -/** hv_restart */ -#define HV_DISPATCH_RESTART 9 - -/** hv_halt */ -#define HV_DISPATCH_HALT 10 - -/** hv_power_off */ -#define HV_DISPATCH_POWER_OFF 11 - -/** hv_inquire_physical */ -#define HV_DISPATCH_INQUIRE_PHYSICAL 12 - -/** hv_inquire_memory_controller */ -#define HV_DISPATCH_INQUIRE_MEMORY_CONTROLLER 13 - -/** hv_inquire_virtual */ -#define HV_DISPATCH_INQUIRE_VIRTUAL 14 - -/** hv_inquire_asid */ -#define HV_DISPATCH_INQUIRE_ASID 15 - -/** hv_nanosleep */ -#define HV_DISPATCH_NANOSLEEP 16 - -/** hv_console_read_if_ready */ -#define HV_DISPATCH_CONSOLE_READ_IF_READY 17 - -/** hv_console_write */ -#define HV_DISPATCH_CONSOLE_WRITE 18 - -/** hv_downcall_dispatch */ -#define HV_DISPATCH_DOWNCALL_DISPATCH 19 - -/** hv_inquire_topology */ -#define HV_DISPATCH_INQUIRE_TOPOLOGY 20 - -/** hv_fs_findfile */ -#define HV_DISPATCH_FS_FINDFILE 21 - -/** hv_fs_fstat */ -#define HV_DISPATCH_FS_FSTAT 22 - -/** hv_fs_pread */ -#define HV_DISPATCH_FS_PREAD 23 - -/** hv_physaddr_read64 */ -#define HV_DISPATCH_PHYSADDR_READ64 24 - -/** hv_physaddr_write64 */ -#define HV_DISPATCH_PHYSADDR_WRITE64 25 - -/** hv_get_command_line */ -#define HV_DISPATCH_GET_COMMAND_LINE 26 - -/** hv_set_caching */ -#define HV_DISPATCH_SET_CACHING 27 - -/** hv_bzero_page */ -#define HV_DISPATCH_BZERO_PAGE 28 - -/** hv_register_message_state */ -#define HV_DISPATCH_REGISTER_MESSAGE_STATE 29 - -/** hv_send_message */ -#define HV_DISPATCH_SEND_MESSAGE 30 - -/** hv_receive_message */ -#define HV_DISPATCH_RECEIVE_MESSAGE 31 - -/** hv_inquire_context */ -#define HV_DISPATCH_INQUIRE_CONTEXT 32 - -/** hv_start_all_tiles */ -#define HV_DISPATCH_START_ALL_TILES 33 - -/** hv_dev_open */ -#define HV_DISPATCH_DEV_OPEN 34 - -/** hv_dev_close */ -#define HV_DISPATCH_DEV_CLOSE 35 - -/** hv_dev_pread */ -#define HV_DISPATCH_DEV_PREAD 36 - -/** hv_dev_pwrite */ -#define HV_DISPATCH_DEV_PWRITE 37 - -/** hv_dev_poll */ -#define HV_DISPATCH_DEV_POLL 38 - -/** hv_dev_poll_cancel */ -#define HV_DISPATCH_DEV_POLL_CANCEL 39 - -/** hv_dev_preada */ -#define HV_DISPATCH_DEV_PREADA 40 - -/** hv_dev_pwritea */ -#define HV_DISPATCH_DEV_PWRITEA 41 - -/** hv_flush_remote */ -#define HV_DISPATCH_FLUSH_REMOTE 42 - -/** hv_console_putc */ -#define HV_DISPATCH_CONSOLE_PUTC 43 - -/** hv_inquire_tiles */ -#define HV_DISPATCH_INQUIRE_TILES 44 - -/** hv_confstr */ -#define HV_DISPATCH_CONFSTR 45 - -/** hv_reexec */ -#define HV_DISPATCH_REEXEC 46 - -/** hv_set_command_line */ -#define HV_DISPATCH_SET_COMMAND_LINE 47 - -#if !CHIP_HAS_IPI() - -/** hv_clear_intr */ -#define HV_DISPATCH_CLEAR_INTR 48 - -/** hv_enable_intr */ -#define HV_DISPATCH_ENABLE_INTR 49 - -/** hv_disable_intr */ -#define HV_DISPATCH_DISABLE_INTR 50 - -/** hv_raise_intr */ -#define HV_DISPATCH_RAISE_INTR 51 - -/** hv_trigger_ipi */ -#define HV_DISPATCH_TRIGGER_IPI 52 - -#endif /* !CHIP_HAS_IPI() */ - -/** hv_store_mapping */ -#define HV_DISPATCH_STORE_MAPPING 53 - -/** hv_inquire_realpa */ -#define HV_DISPATCH_INQUIRE_REALPA 54 - -/** hv_flush_all */ -#define HV_DISPATCH_FLUSH_ALL 55 - -#if CHIP_HAS_IPI() -/** hv_get_ipi_pte */ -#define HV_DISPATCH_GET_IPI_PTE 56 -#endif - -/** hv_set_pte_super_shift */ -#define HV_DISPATCH_SET_PTE_SUPER_SHIFT 57 - -/** hv_console_set_ipi */ -#define HV_DISPATCH_CONSOLE_SET_IPI 63 - -/** hv_send_nmi */ -#define HV_DISPATCH_SEND_NMI 65 - -/** One more than the largest dispatch value */ -#define _HV_DISPATCH_END 66 - - -#ifndef __ASSEMBLER__ - -#ifdef __KERNEL__ -#include -typedef u32 __hv32; /**< 32-bit value */ -typedef u64 __hv64; /**< 64-bit value */ -#else -#include -typedef uint32_t __hv32; /**< 32-bit value */ -typedef uint64_t __hv64; /**< 64-bit value */ -#endif - - -/** Hypervisor physical address. */ -typedef __hv64 HV_PhysAddr; - -#if CHIP_VA_WIDTH() > 32 -/** Hypervisor virtual address. */ -typedef __hv64 HV_VirtAddr; -#else -/** Hypervisor virtual address. */ -typedef __hv32 HV_VirtAddr; -#endif /* CHIP_VA_WIDTH() > 32 */ - -/** Hypervisor ASID. */ -typedef unsigned int HV_ASID; - -/** Hypervisor tile location for a memory access - * ("location overridden target"). - */ -typedef unsigned int HV_LOTAR; - -/** Hypervisor size of a page. */ -typedef unsigned long HV_PageSize; - -/** A page table entry. - */ -typedef struct -{ - __hv64 val; /**< Value of PTE */ -} HV_PTE; - -/** Hypervisor error code. */ -typedef int HV_Errno; - -#endif /* !__ASSEMBLER__ */ - -#define HV_OK 0 /**< No error */ -#define HV_EINVAL -801 /**< Invalid argument */ -#define HV_ENODEV -802 /**< No such device */ -#define HV_ENOENT -803 /**< No such file or directory */ -#define HV_EBADF -804 /**< Bad file number */ -#define HV_EFAULT -805 /**< Bad address */ -#define HV_ERECIP -806 /**< Bad recipients */ -#define HV_E2BIG -807 /**< Message too big */ -#define HV_ENOTSUP -808 /**< Service not supported */ -#define HV_EBUSY -809 /**< Device busy */ -#define HV_ENOSYS -810 /**< Invalid syscall */ -#define HV_EPERM -811 /**< No permission */ -#define HV_ENOTREADY -812 /**< Device not ready */ -#define HV_EIO -813 /**< I/O error */ -#define HV_ENOMEM -814 /**< Out of memory */ -#define HV_EAGAIN -815 /**< Try again */ - -#define HV_ERR_MAX -801 /**< Largest HV error code */ -#define HV_ERR_MIN -815 /**< Smallest HV error code */ - -#ifndef __ASSEMBLER__ - -/** Pass HV_VERSION to hv_init to request this version of the interface. */ -typedef enum { - HV_VERSION = _HV_VERSION, - HV_VERSION_OLD_HV_INIT = _HV_VERSION_OLD_HV_INIT, - -} HV_VersionNumber; - -/** Initializes the hypervisor. - * - * @param interface_version_number The version of the hypervisor interface - * that this program expects, typically HV_VERSION. - * @param chip_num Architecture number of the chip the client was built for. - * @param chip_rev_num Revision number of the chip the client was built for. - * @param client_pl Privilege level the client is built for - * (not required if interface_version_number == HV_VERSION_OLD_HV_INIT). - */ -void hv_init(HV_VersionNumber interface_version_number, - int chip_num, int chip_rev_num, int client_pl); - - -/** Queries we can make for hv_sysconf(). - * - * These numbers are part of the binary API and guaranteed not to change. - */ -typedef enum { - /** An invalid value; do not use. */ - _HV_SYSCONF_RESERVED = 0, - - /** The length of the glue section containing the hv_ procs, in bytes. */ - HV_SYSCONF_GLUE_SIZE = 1, - - /** The size of small pages, in bytes. */ - HV_SYSCONF_PAGE_SIZE_SMALL = 2, - - /** The size of large pages, in bytes. */ - HV_SYSCONF_PAGE_SIZE_LARGE = 3, - - /** Processor clock speed, in hertz. */ - HV_SYSCONF_CPU_SPEED = 4, - - /** Processor temperature, in degrees Kelvin. The value - * HV_SYSCONF_TEMP_KTOC may be subtracted from this to get degrees - * Celsius. If that Celsius value is HV_SYSCONF_OVERTEMP, this indicates - * that the temperature has hit an upper limit and is no longer being - * accurately tracked. - */ - HV_SYSCONF_CPU_TEMP = 5, - - /** Board temperature, in degrees Kelvin. The value - * HV_SYSCONF_TEMP_KTOC may be subtracted from this to get degrees - * Celsius. If that Celsius value is HV_SYSCONF_OVERTEMP, this indicates - * that the temperature has hit an upper limit and is no longer being - * accurately tracked. - */ - HV_SYSCONF_BOARD_TEMP = 6, - - /** Legal page size bitmask for hv_install_context(). - * For example, if 16KB and 64KB small pages are supported, - * it would return "HV_CTX_PG_SM_16K | HV_CTX_PG_SM_64K". - */ - HV_SYSCONF_VALID_PAGE_SIZES = 7, - - /** The size of jumbo pages, in bytes. - * If no jumbo pages are available, zero will be returned. - */ - HV_SYSCONF_PAGE_SIZE_JUMBO = 8, - -} HV_SysconfQuery; - -/** Offset to subtract from returned Kelvin temperature to get degrees - Celsius. */ -#define HV_SYSCONF_TEMP_KTOC 273 - -/** Pseudo-temperature value indicating that the temperature has - * pegged at its upper limit and is no longer accurate; note that this is - * the value after subtracting HV_SYSCONF_TEMP_KTOC. */ -#define HV_SYSCONF_OVERTEMP 999 - -/** Query a configuration value from the hypervisor. - * @param query Which value is requested (HV_SYSCONF_xxx). - * @return The requested value, or -1 the requested value is illegal or - * unavailable. - */ -long hv_sysconf(HV_SysconfQuery query); - - -/** Queries we can make for hv_confstr(). - * - * These numbers are part of the binary API and guaranteed not to change. - */ -typedef enum { - /** An invalid value; do not use. */ - _HV_CONFSTR_RESERVED = 0, - - /** Board part number. */ - HV_CONFSTR_BOARD_PART_NUM = 1, - - /** Board serial number. */ - HV_CONFSTR_BOARD_SERIAL_NUM = 2, - - /** Chip serial number. */ - HV_CONFSTR_CHIP_SERIAL_NUM = 3, - - /** Board revision level. */ - HV_CONFSTR_BOARD_REV = 4, - - /** Hypervisor software version. */ - HV_CONFSTR_HV_SW_VER = 5, - - /** The name for this chip model. */ - HV_CONFSTR_CHIP_MODEL = 6, - - /** Human-readable board description. */ - HV_CONFSTR_BOARD_DESC = 7, - - /** Human-readable description of the hypervisor configuration. */ - HV_CONFSTR_HV_CONFIG = 8, - - /** Human-readable version string for the boot image (for instance, - * who built it and when, what configuration file was used). */ - HV_CONFSTR_HV_CONFIG_VER = 9, - - /** Mezzanine part number. */ - HV_CONFSTR_MEZZ_PART_NUM = 10, - - /** Mezzanine serial number. */ - HV_CONFSTR_MEZZ_SERIAL_NUM = 11, - - /** Mezzanine revision level. */ - HV_CONFSTR_MEZZ_REV = 12, - - /** Human-readable mezzanine description. */ - HV_CONFSTR_MEZZ_DESC = 13, - - /** Control path for the onboard network switch. */ - HV_CONFSTR_SWITCH_CONTROL = 14, - - /** Chip revision level. */ - HV_CONFSTR_CHIP_REV = 15, - - /** CPU module part number. */ - HV_CONFSTR_CPUMOD_PART_NUM = 16, - - /** CPU module serial number. */ - HV_CONFSTR_CPUMOD_SERIAL_NUM = 17, - - /** CPU module revision level. */ - HV_CONFSTR_CPUMOD_REV = 18, - - /** Human-readable CPU module description. */ - HV_CONFSTR_CPUMOD_DESC = 19, - - /** Per-tile hypervisor statistics. When this identifier is specified, - * the hv_confstr call takes two extra arguments. The first is the - * HV_XY_TO_LOTAR of the target tile's coordinates. The second is - * a flag word. The only current flag is the lowest bit, which means - * "zero out the stats instead of retrieving them"; in this case the - * buffer and buffer length are ignored. */ - HV_CONFSTR_HV_STATS = 20 - -} HV_ConfstrQuery; - -/** Query a configuration string from the hypervisor. - * - * @param query Identifier for the specific string to be retrieved - * (HV_CONFSTR_xxx). Some strings may require or permit extra - * arguments to be appended which select specific objects to be - * described; see the string descriptions above. - * @param buf Buffer in which to place the string. - * @param len Length of the buffer. - * @return If query is valid, then the length of the corresponding string, - * including the trailing null; if this is greater than len, the string - * was truncated. If query is invalid, HV_EINVAL. If the specified - * buffer is not writable by the client, HV_EFAULT. - */ -int hv_confstr(HV_ConfstrQuery query, HV_VirtAddr buf, int len, ...); - -/** Tile coordinate */ -typedef struct -{ - /** X coordinate, relative to supervisor's top-left coordinate */ - int x; - - /** Y coordinate, relative to supervisor's top-left coordinate */ - int y; -} HV_Coord; - - -#if CHIP_HAS_IPI() - -/** Get the PTE for sending an IPI to a particular tile. - * - * @param tile Tile which will receive the IPI. - * @param pl Indicates which IPI registers: 0 = IPI_0, 1 = IPI_1. - * @param pte Filled with resulting PTE. - * @result Zero if no error, non-zero for invalid parameters. - */ -int hv_get_ipi_pte(HV_Coord tile, int pl, HV_PTE* pte); - -/** Configure the console interrupt. - * - * When the console client interrupt is enabled, the hypervisor will - * deliver the specified IPI to the client in the following situations: - * - * - The console has at least one character available for input. - * - * - The console can accept new characters for output, and the last call - * to hv_console_write() did not write all of the characters requested - * by the client. - * - * Note that in some system configurations, console interrupt will not - * be available; clients should be prepared for this routine to fail and - * to fall back to periodic console polling in that case. - * - * @param ipi Index of the IPI register which will receive the interrupt. - * @param event IPI event number for console interrupt. If less than 0, - * disable the console IPI interrupt. - * @param coord Tile to be targeted for console interrupt. - * @return 0 on success, otherwise, HV_EINVAL if illegal parameter, - * HV_ENOTSUP if console interrupt are not available. - */ -int hv_console_set_ipi(int ipi, int event, HV_Coord coord); - -#else /* !CHIP_HAS_IPI() */ - -/** A set of interrupts. */ -typedef __hv32 HV_IntrMask; - -/** The low interrupt numbers are reserved for use by the client in - * delivering IPIs. Any interrupt numbers higher than this value are - * reserved for use by HV device drivers. */ -#define HV_MAX_IPI_INTERRUPT 7 - -/** Enable a set of device interrupts. - * - * @param enab_mask Bitmap of interrupts to enable. - */ -void hv_enable_intr(HV_IntrMask enab_mask); - -/** Disable a set of device interrupts. - * - * @param disab_mask Bitmap of interrupts to disable. - */ -void hv_disable_intr(HV_IntrMask disab_mask); - -/** Clear a set of device interrupts. - * - * @param clear_mask Bitmap of interrupts to clear. - */ -void hv_clear_intr(HV_IntrMask clear_mask); - -/** Raise a set of device interrupts. - * - * @param raise_mask Bitmap of interrupts to raise. - */ -void hv_raise_intr(HV_IntrMask raise_mask); - -/** Trigger a one-shot interrupt on some tile - * - * @param tile Which tile to interrupt. - * @param interrupt Interrupt number to trigger; must be between 0 and - * HV_MAX_IPI_INTERRUPT. - * @return HV_OK on success, or a hypervisor error code. - */ -HV_Errno hv_trigger_ipi(HV_Coord tile, int interrupt); - -#endif /* !CHIP_HAS_IPI() */ - -/** Store memory mapping in debug memory so that external debugger can read it. - * A maximum of 16 entries can be stored. - * - * @param va VA of memory that is mapped. - * @param len Length of mapped memory. - * @param pa PA of memory that is mapped. - * @return 0 on success, -1 if the maximum number of mappings is exceeded. - */ -int hv_store_mapping(HV_VirtAddr va, unsigned int len, HV_PhysAddr pa); - -/** Given a client PA and a length, return its real (HV) PA. - * - * @param cpa Client physical address. - * @param len Length of mapped memory. - * @return physical address, or -1 if cpa or len is not valid. - */ -HV_PhysAddr hv_inquire_realpa(HV_PhysAddr cpa, unsigned int len); - -/** RTC return flag for no RTC chip present. - */ -#define HV_RTC_NO_CHIP 0x1 - -/** RTC return flag for low-voltage condition, indicating that battery had - * died and time read is unreliable. - */ -#define HV_RTC_LOW_VOLTAGE 0x2 - -/** Date/Time of day */ -typedef struct { -#if CHIP_WORD_SIZE() > 32 - __hv64 tm_sec; /**< Seconds, 0-59 */ - __hv64 tm_min; /**< Minutes, 0-59 */ - __hv64 tm_hour; /**< Hours, 0-23 */ - __hv64 tm_mday; /**< Day of month, 0-30 */ - __hv64 tm_mon; /**< Month, 0-11 */ - __hv64 tm_year; /**< Years since 1900, 0-199 */ - __hv64 flags; /**< Return flags, 0 if no error */ -#else - __hv32 tm_sec; /**< Seconds, 0-59 */ - __hv32 tm_min; /**< Minutes, 0-59 */ - __hv32 tm_hour; /**< Hours, 0-23 */ - __hv32 tm_mday; /**< Day of month, 0-30 */ - __hv32 tm_mon; /**< Month, 0-11 */ - __hv32 tm_year; /**< Years since 1900, 0-199 */ - __hv32 flags; /**< Return flags, 0 if no error */ -#endif -} HV_RTCTime; - -/** Read the current time-of-day clock. - * @return HV_RTCTime of current time (GMT). - */ -HV_RTCTime hv_get_rtc(void); - - -/** Set the current time-of-day clock. - * @param time time to reset time-of-day to (GMT). - */ -void hv_set_rtc(HV_RTCTime time); - -/** Installs a context, comprising a page table and other attributes. - * - * Once this service completes, page_table will be used to translate - * subsequent virtual address references to physical memory. - * - * Installing a context does not cause an implicit TLB flush. Before - * reusing an ASID value for a different address space, the client is - * expected to flush old references from the TLB with hv_flush_asid(). - * (Alternately, hv_flush_all() may be used to flush many ASIDs at once.) - * After invalidating a page table entry, changing its attributes, or - * changing its target CPA, the client is expected to flush old references - * from the TLB with hv_flush_page() or hv_flush_pages(). Making a - * previously invalid page valid does not require a flush. - * - * Specifying an invalid ASID, or an invalid CPA (client physical address) - * (either as page_table_pointer, or within the referenced table), - * or another page table data item documented as above as illegal may - * lead to client termination; since the validation of the table is - * done as needed, this may happen before the service returns, or at - * some later time, or never, depending upon the client's pattern of - * memory references. Page table entries which supply translations for - * invalid virtual addresses may result in client termination, or may - * be silently ignored. "Invalid" in this context means a value which - * was not provided to the client via the appropriate hv_inquire_* routine. - * - * To support changing the instruction VAs at the same time as - * installing the new page table, this call explicitly supports - * setting the "lr" register to a different address and then jumping - * directly to the hv_install_context() routine. In this case, the - * new page table does not need to contain any mapping for the - * hv_install_context address itself. - * - * At most one HV_CTX_PG_SM_* flag may be specified in "flags"; - * if multiple flags are specified, HV_EINVAL is returned. - * Specifying none of the flags results in using the default page size. - * All cores participating in a given client must request the same - * page size, or the results are undefined. - * - * @param page_table Root of the page table. - * @param access PTE providing info on how to read the page table. This - * value must be consistent between multiple tiles sharing a page table, - * and must also be consistent with any virtual mappings the client - * may be using to access the page table. - * @param asid HV_ASID the page table is to be used for. - * @param flags Context flags, denoting attributes or privileges of the - * current context (HV_CTX_xxx). - * @return Zero on success, or a hypervisor error code on failure. - */ -int hv_install_context(HV_PhysAddr page_table, HV_PTE access, HV_ASID asid, - __hv32 flags); - -#endif /* !__ASSEMBLER__ */ - -#define HV_CTX_DIRECTIO 0x1 /**< Direct I/O requests are accepted from - PL0. */ - -#define HV_CTX_PG_SM_4K 0x10 /**< Use 4K small pages, if available. */ -#define HV_CTX_PG_SM_16K 0x20 /**< Use 16K small pages, if available. */ -#define HV_CTX_PG_SM_64K 0x40 /**< Use 64K small pages, if available. */ -#define HV_CTX_PG_SM_MASK 0xf0 /**< Mask of all possible small pages. */ - -#ifndef __ASSEMBLER__ - - -/** Set the number of pages ganged together by HV_PTE_SUPER at a - * particular level of the page table. - * - * The current TILE-Gx hardware only supports powers of four - * (i.e. log2_count must be a multiple of two), and the requested - * "super" page size must be less than the span of the next level in - * the page table. The largest size that can be requested is 64GB. - * - * The shift value is initially "0" for all page table levels, - * indicating that the HV_PTE_SUPER bit is effectively ignored. - * - * If you change the count from one non-zero value to another, the - * hypervisor will flush the entire TLB and TSB to avoid confusion. - * - * @param level Page table level (0, 1, or 2) - * @param log2_count Base-2 log of the number of pages to gang together, - * i.e. how much to shift left the base page size for the super page size. - * @return Zero on success, or a hypervisor error code on failure. - */ -int hv_set_pte_super_shift(int level, int log2_count); - - -/** Value returned from hv_inquire_context(). */ -typedef struct -{ - /** Physical address of page table */ - HV_PhysAddr page_table; - - /** PTE which defines access method for top of page table */ - HV_PTE access; - - /** ASID associated with this page table */ - HV_ASID asid; - - /** Context flags */ - __hv32 flags; -} HV_Context; - -/** Retrieve information about the currently installed context. - * @return The data passed to the last successful hv_install_context call. - */ -HV_Context hv_inquire_context(void); - - -/** Flushes all translations associated with the named address space - * identifier from the TLB and any other hypervisor data structures. - * Translations installed with the "global" bit are not flushed. - * - * Specifying an invalid ASID may lead to client termination. "Invalid" - * in this context means a value which was not provided to the client - * via hv_inquire_asid(). - * - * @param asid HV_ASID whose entries are to be flushed. - * @return Zero on success, or a hypervisor error code on failure. -*/ -int hv_flush_asid(HV_ASID asid); - - -/** Flushes all translations associated with the named virtual address - * and page size from the TLB and other hypervisor data structures. Only - * pages visible to the current ASID are affected; note that this includes - * global pages in addition to pages specific to the current ASID. - * - * The supplied VA need not be aligned; it may be anywhere in the - * subject page. - * - * Specifying an invalid virtual address may lead to client termination, - * or may silently succeed. "Invalid" in this context means a value - * which was not provided to the client via hv_inquire_virtual. - * - * @param address Address of the page to flush. - * @param page_size Size of pages to assume. - * @return Zero on success, or a hypervisor error code on failure. - */ -int hv_flush_page(HV_VirtAddr address, HV_PageSize page_size); - - -/** Flushes all translations associated with the named virtual address range - * and page size from the TLB and other hypervisor data structures. Only - * pages visible to the current ASID are affected; note that this includes - * global pages in addition to pages specific to the current ASID. - * - * The supplied VA need not be aligned; it may be anywhere in the - * subject page. - * - * Specifying an invalid virtual address may lead to client termination, - * or may silently succeed. "Invalid" in this context means a value - * which was not provided to the client via hv_inquire_virtual. - * - * @param start Address to flush. - * @param page_size Size of pages to assume. - * @param size The number of bytes to flush. Any page in the range - * [start, start + size) will be flushed from the TLB. - * @return Zero on success, or a hypervisor error code on failure. - */ -int hv_flush_pages(HV_VirtAddr start, HV_PageSize page_size, - unsigned long size); - - -/** Flushes all non-global translations (if preserve_global is true), - * or absolutely all translations (if preserve_global is false). - * - * @param preserve_global Non-zero if we want to preserve "global" mappings. - * @return Zero on success, or a hypervisor error code on failure. -*/ -int hv_flush_all(int preserve_global); - - -/** Restart machine with optional restart command and optional args. - * @param cmd Const pointer to command to restart with, or NULL - * @param args Const pointer to argument string to restart with, or NULL - */ -void hv_restart(HV_VirtAddr cmd, HV_VirtAddr args); - - -/** Halt machine. */ -void hv_halt(void); - - -/** Power off machine. */ -void hv_power_off(void); - - -/** Re-enter virtual-is-physical memory translation mode and restart - * execution at a given address. - * @param entry Client physical address at which to begin execution. - * @return A hypervisor error code on failure; if the operation is - * successful the call does not return. - */ -int hv_reexec(HV_PhysAddr entry); - - -/** Chip topology */ -typedef struct -{ - /** Relative coordinates of the querying tile */ - HV_Coord coord; - - /** Width of the querying supervisor's tile rectangle. */ - int width; - - /** Height of the querying supervisor's tile rectangle. */ - int height; - -} HV_Topology; - -/** Returns information about the tile coordinate system. - * - * Each supervisor is given a rectangle of tiles it potentially controls. - * These tiles are labeled using a relative coordinate system with (0,0) as - * the upper left tile regardless of their physical location on the chip. - * - * This call returns both the size of that rectangle and the position - * within that rectangle of the querying tile. - * - * Not all tiles within that rectangle may be available to the supervisor; - * to get the precise set of available tiles, you must also call - * hv_inquire_tiles(HV_INQ_TILES_AVAIL, ...). - **/ -HV_Topology hv_inquire_topology(void); - -/** Sets of tiles we can retrieve with hv_inquire_tiles(). - * - * These numbers are part of the binary API and guaranteed not to change. - */ -typedef enum { - /** An invalid value; do not use. */ - _HV_INQ_TILES_RESERVED = 0, - - /** All available tiles within the supervisor's tile rectangle. */ - HV_INQ_TILES_AVAIL = 1, - - /** The set of tiles used for hash-for-home caching. */ - HV_INQ_TILES_HFH_CACHE = 2, - - /** The set of tiles that can be legally used as a LOTAR for a PTE. */ - HV_INQ_TILES_LOTAR = 3, - - /** The set of "shared" driver tiles that the hypervisor may - * periodically interrupt. */ - HV_INQ_TILES_SHARED = 4 -} HV_InqTileSet; - -/** Returns specific information about various sets of tiles within the - * supervisor's tile rectangle. - * - * @param set Which set of tiles to retrieve. - * @param cpumask Pointer to a returned bitmask (in row-major order, - * supervisor-relative) of tiles. The low bit of the first word - * corresponds to the tile at the upper left-hand corner of the - * supervisor's rectangle. In order for the supervisor to know the - * buffer length to supply, it should first call hv_inquire_topology. - * @param length Number of bytes available for the returned bitmask. - **/ -HV_Errno hv_inquire_tiles(HV_InqTileSet set, HV_VirtAddr cpumask, int length); - - -/** An identifier for a memory controller. Multiple memory controllers - * may be connected to one chip, and this uniquely identifies each one. - */ -typedef int HV_MemoryController; - -/** A range of physical memory. */ -typedef struct -{ - HV_PhysAddr start; /**< Starting address. */ - __hv64 size; /**< Size in bytes. */ - HV_MemoryController controller; /**< Which memory controller owns this. */ -} HV_PhysAddrRange; - -/** Returns information about a range of physical memory. - * - * hv_inquire_physical() returns one of the ranges of client - * physical addresses which are available to this client. - * - * The first range is retrieved by specifying an idx of 0, and - * successive ranges are returned with subsequent idx values. Ranges - * are ordered by increasing start address (i.e., as idx increases, - * so does start), do not overlap, and do not touch (i.e., the - * available memory is described with the fewest possible ranges). - * - * If an out-of-range idx value is specified, the returned size will be zero. - * A client can count the number of ranges by increasing idx until the - * returned size is zero. There will always be at least one valid range. - * - * Some clients might not be prepared to deal with more than one - * physical address range; they still ought to call this routine and - * issue a warning message if they're given more than one range, on the - * theory that whoever configured the hypervisor to provide that memory - * should know that it's being wasted. - */ -HV_PhysAddrRange hv_inquire_physical(int idx); - -/** Possible DIMM types. */ -typedef enum -{ - NO_DIMM = 0, /**< No DIMM */ - DDR2 = 1, /**< DDR2 */ - DDR3 = 2 /**< DDR3 */ -} HV_DIMM_Type; - -#ifdef __tilegx__ - -/** Log2 of minimum DIMM bytes supported by the memory controller. */ -#define HV_MSH_MIN_DIMM_SIZE_SHIFT 29 - -/** Max number of DIMMs contained by one memory controller. */ -#define HV_MSH_MAX_DIMMS 8 - -#else - -/** Log2 of minimum DIMM bytes supported by the memory controller. */ -#define HV_MSH_MIN_DIMM_SIZE_SHIFT 26 - -/** Max number of DIMMs contained by one memory controller. */ -#define HV_MSH_MAX_DIMMS 2 - -#endif - -/** Number of bits to right-shift to get the DIMM type. */ -#define HV_DIMM_TYPE_SHIFT 0 - -/** Bits to mask to get the DIMM type. */ -#define HV_DIMM_TYPE_MASK 0xf - -/** Number of bits to right-shift to get the DIMM size. */ -#define HV_DIMM_SIZE_SHIFT 4 - -/** Bits to mask to get the DIMM size. */ -#define HV_DIMM_SIZE_MASK 0xf - -/** Memory controller information. */ -typedef struct -{ - HV_Coord coord; /**< Relative tile coordinates of the port used by a - specified tile to communicate with this controller. */ - __hv64 speed; /**< Speed of this controller in bytes per second. */ -} HV_MemoryControllerInfo; - -/** Returns information about a particular memory controller. - * - * hv_inquire_memory_controller(coord,idx) returns information about a - * particular controller. Two pieces of information are returned: - * - The relative coordinates of the port on the controller that the specified - * tile would use to contact it. The relative coordinates may lie - * outside the supervisor's rectangle, i.e. the controller may not - * be attached to a node managed by the querying node's supervisor. - * In particular note that x or y may be negative. - * - The speed of the memory controller. (This is a not-to-exceed value - * based on the raw hardware data rate, and may not be achievable in - * practice; it is provided to give clients information on the relative - * performance of the available controllers.) - * - * Clients should avoid calling this interface with invalid values. - * A client who does may be terminated. - * @param coord Tile for which to calculate the relative port position. - * @param controller Index of the controller; identical to value returned - * from other routines like hv_inquire_physical. - * @return Information about the controller. - */ -HV_MemoryControllerInfo hv_inquire_memory_controller(HV_Coord coord, - int controller); - - -/** A range of virtual memory. */ -typedef struct -{ - HV_VirtAddr start; /**< Starting address. */ - __hv64 size; /**< Size in bytes. */ -} HV_VirtAddrRange; - -/** Returns information about a range of virtual memory. - * - * hv_inquire_virtual() returns one of the ranges of client - * virtual addresses which are available to this client. - * - * The first range is retrieved by specifying an idx of 0, and - * successive ranges are returned with subsequent idx values. Ranges - * are ordered by increasing start address (i.e., as idx increases, - * so does start), do not overlap, and do not touch (i.e., the - * available memory is described with the fewest possible ranges). - * - * If an out-of-range idx value is specified, the returned size will be zero. - * A client can count the number of ranges by increasing idx until the - * returned size is zero. There will always be at least one valid range. - * - * Some clients may well have various virtual addresses hardwired - * into themselves; for instance, their instruction stream may - * have been compiled expecting to live at a particular address. - * Such clients should use this interface to verify they've been - * given the virtual address space they expect, and issue a (potentially - * fatal) warning message otherwise. - * - * Note that the returned size is a __hv64, not a __hv32, so it is - * possible to express a single range spanning the entire 32-bit - * address space. - */ -HV_VirtAddrRange hv_inquire_virtual(int idx); - - -/** A range of ASID values. */ -typedef struct -{ - HV_ASID start; /**< First ASID in the range. */ - unsigned int size; /**< Number of ASIDs. Zero for an invalid range. */ -} HV_ASIDRange; - -/** Returns information about a range of ASIDs. - * - * hv_inquire_asid() returns one of the ranges of address - * space identifiers which are available to this client. - * - * The first range is retrieved by specifying an idx of 0, and - * successive ranges are returned with subsequent idx values. Ranges - * are ordered by increasing start value (i.e., as idx increases, - * so does start), do not overlap, and do not touch (i.e., the - * available ASIDs are described with the fewest possible ranges). - * - * If an out-of-range idx value is specified, the returned size will be zero. - * A client can count the number of ranges by increasing idx until the - * returned size is zero. There will always be at least one valid range. - */ -HV_ASIDRange hv_inquire_asid(int idx); - - -/** Waits for at least the specified number of nanoseconds then returns. - * - * NOTE: this deprecated function currently assumes a 750 MHz clock, - * and is thus not generally suitable for use. New code should call - * hv_sysconf(HV_SYSCONF_CPU_SPEED), compute a cycle count to wait for, - * and delay by looping while checking the cycle counter SPR. - * - * @param nanosecs The number of nanoseconds to sleep. - */ -void hv_nanosleep(int nanosecs); - - -/** Reads a character from the console without blocking. - * - * @return A value from 0-255 indicates the value successfully read. - * A negative value means no value was ready. - */ -int hv_console_read_if_ready(void); - - -/** Writes a character to the console, blocking if the console is busy. - * - * This call cannot fail. If the console is broken for some reason, - * output will simply vanish. - * @param byte Character to write. - */ -void hv_console_putc(int byte); - - -/** Writes a string to the console, blocking if the console is busy. - * @param bytes Pointer to characters to write. - * @param len Number of characters to write. - * @return Number of characters written, or HV_EFAULT if the buffer is invalid. - */ -int hv_console_write(HV_VirtAddr bytes, int len); - - -/** Dispatch the next interrupt from the client downcall mechanism. - * - * The hypervisor uses downcalls to notify the client of asynchronous - * events. Some of these events are hypervisor-created (like incoming - * messages). Some are regular interrupts which initially occur in - * the hypervisor, and are normally handled directly by the client; - * when these occur in a client's interrupt critical section, they must - * be delivered through the downcall mechanism. - * - * A downcall is initially delivered to the client as an INTCTRL_CL - * interrupt, where CL is the client's PL. Upon entry to the INTCTRL_CL - * vector, the client must immediately invoke the hv_downcall_dispatch - * service. This service will not return; instead it will cause one of - * the client's actual downcall-handling interrupt vectors to be entered. - * The EX_CONTEXT registers in the client will be set so that when the - * client irets, it will return to the code which was interrupted by the - * INTCTRL_CL interrupt. - * - * Under some circumstances, the firing of INTCTRL_CL can race with - * the lowering of a device interrupt. In such a case, the - * hv_downcall_dispatch service may issue an iret instruction instead - * of entering one of the client's actual downcall-handling interrupt - * vectors. This will return execution to the location that was - * interrupted by INTCTRL_CL. - * - * Any saving of registers should be done by the actual handling - * vectors; no registers should be changed by the INTCTRL_CL handler. - * In particular, the client should not use a jal instruction to invoke - * the hv_downcall_dispatch service, as that would overwrite the client's - * lr register. Note that the hv_downcall_dispatch service may overwrite - * one or more of the client's system save registers. - * - * The client must not modify the INTCTRL_CL_STATUS SPR. The hypervisor - * will set this register to cause a downcall to happen, and will clear - * it when no further downcalls are pending. - * - * When a downcall vector is entered, the INTCTRL_CL interrupt will be - * masked. When the client is done processing a downcall, and is ready - * to accept another, it must unmask this interrupt; if more downcalls - * are pending, this will cause the INTCTRL_CL vector to be reentered. - * Currently the following interrupt vectors can be entered through a - * downcall: - * - * INT_MESSAGE_RCV_DWNCL (hypervisor message available) - * INT_DEV_INTR_DWNCL (device interrupt) - * INT_DMATLB_MISS_DWNCL (DMA TLB miss) - * INT_SNITLB_MISS_DWNCL (SNI TLB miss) - * INT_DMATLB_ACCESS_DWNCL (DMA TLB access violation) - */ -void hv_downcall_dispatch(void); - -#endif /* !__ASSEMBLER__ */ - -/** We use actual interrupt vectors which never occur (they're only there - * to allow setting MPLs for related SPRs) for our downcall vectors. - */ -/** Message receive downcall interrupt vector */ -#define INT_MESSAGE_RCV_DWNCL INT_BOOT_ACCESS -/** DMA TLB miss downcall interrupt vector */ -#define INT_DMATLB_MISS_DWNCL INT_DMA_ASID -/** Static nework processor instruction TLB miss interrupt vector */ -#define INT_SNITLB_MISS_DWNCL INT_SNI_ASID -/** DMA TLB access violation downcall interrupt vector */ -#define INT_DMATLB_ACCESS_DWNCL INT_DMA_CPL -/** Device interrupt downcall interrupt vector */ -#define INT_DEV_INTR_DWNCL INT_WORLD_ACCESS -/** NMI downcall interrupt vector */ -#define INT_NMI_DWNCL 64 - -#define HV_NMI_FLAG_FORCE 0x1 /**< Force an NMI downcall regardless of - the ICS bit of the client. */ - -#ifndef __ASSEMBLER__ - -/** Requests the inode for a specific full pathname. - * - * Performs a lookup in the hypervisor filesystem for a given filename. - * Multiple calls with the same filename will always return the same inode. - * If there is no such filename, HV_ENOENT is returned. - * A bad filename pointer may result in HV_EFAULT instead. - * - * @param filename Constant pointer to name of requested file - * @return Inode of requested file - */ -int hv_fs_findfile(HV_VirtAddr filename); - - -/** Data returned from an fstat request. - * Note that this structure should be no more than 40 bytes in size so - * that it can always be returned completely in registers. - */ -typedef struct -{ - int size; /**< Size of file (or HV_Errno on error) */ - unsigned int flags; /**< Flags (see HV_FS_FSTAT_FLAGS) */ -} HV_FS_StatInfo; - -/** Bitmask flags for fstat request */ -typedef enum -{ - HV_FS_ISDIR = 0x0001 /**< Is the entry a directory? */ -} HV_FS_FSTAT_FLAGS; - -/** Get stat information on a given file inode. - * - * Return information on the file with the given inode. - * - * IF the HV_FS_ISDIR bit is set, the "file" is a directory. Reading - * it will return NUL-separated filenames (no directory part) relative - * to the path to the inode of the directory "file". These can be - * appended to the path to the directory "file" after a forward slash - * to create additional filenames. Note that it is not required - * that all valid paths be decomposable into valid parent directories; - * a filesystem may validly have just a few files, none of which have - * HV_FS_ISDIR set. However, if clients may wish to enumerate the - * files in the filesystem, it is recommended to include all the - * appropriate parent directory "files" to give a consistent view. - * - * An invalid file inode will cause an HV_EBADF error to be returned. - * - * @param inode The inode number of the query - * @return An HV_FS_StatInfo structure - */ -HV_FS_StatInfo hv_fs_fstat(int inode); - - -/** Read data from a specific hypervisor file. - * On error, may return HV_EBADF for a bad inode or HV_EFAULT for a bad buf. - * Reads near the end of the file will return fewer bytes than requested. - * Reads at or beyond the end of a file will return zero. - * - * @param inode the hypervisor file to read - * @param buf the buffer to read data into - * @param length the number of bytes of data to read - * @param offset the offset into the file to read the data from - * @return number of bytes successfully read, or an HV_Errno code - */ -int hv_fs_pread(int inode, HV_VirtAddr buf, int length, int offset); - - -/** Read a 64-bit word from the specified physical address. - * The address must be 8-byte aligned. - * Specifying an invalid physical address will lead to client termination. - * @param addr The physical address to read - * @param access The PTE describing how to read the memory - * @return The 64-bit value read from the given address - */ -unsigned long long hv_physaddr_read64(HV_PhysAddr addr, HV_PTE access); - - -/** Write a 64-bit word to the specified physical address. - * The address must be 8-byte aligned. - * Specifying an invalid physical address will lead to client termination. - * @param addr The physical address to write - * @param access The PTE that says how to write the memory - * @param val The 64-bit value to write to the given address - */ -void hv_physaddr_write64(HV_PhysAddr addr, HV_PTE access, - unsigned long long val); - - -/** Get the value of the command-line for the supervisor, if any. - * This will not include the filename of the booted supervisor, but may - * include configured-in boot arguments or the hv_restart() arguments. - * If the buffer is not long enough the hypervisor will NUL the first - * character of the buffer but not write any other data. - * @param buf The virtual address to write the command-line string to. - * @param length The length of buf, in characters. - * @return The actual length of the command line, including the trailing NUL - * (may be larger than "length"). - */ -int hv_get_command_line(HV_VirtAddr buf, int length); - - -/** Set a new value for the command-line for the supervisor, which will - * be returned from subsequent invocations of hv_get_command_line() on - * this tile. - * @param buf The virtual address to read the command-line string from. - * @param length The length of buf, in characters; must be no more than - * HV_COMMAND_LINE_LEN. - * @return Zero if successful, or a hypervisor error code. - */ -HV_Errno hv_set_command_line(HV_VirtAddr buf, int length); - -/** Maximum size of a command line passed to hv_set_command_line(); note - * that a line returned from hv_get_command_line() could be larger than - * this.*/ -#define HV_COMMAND_LINE_LEN 256 - -/** Tell the hypervisor how to cache non-priority pages - * (its own as well as pages explicitly represented in page tables). - * Normally these will be represented as red/black pages, but - * when the supervisor starts to allocate "priority" pages in the PTE - * the hypervisor will need to start marking those pages as (e.g.) "red" - * and non-priority pages as either "black" (if they cache-alias - * with the existing priority pages) or "red/black" (if they don't). - * The bitmask provides information on which parts of the cache - * have been used for pinned pages so far on this tile; if (1 << N) - * appears in the bitmask, that indicates that a 4KB region of the - * cache starting at (N * 4KB) is in use by a "priority" page. - * The portion of cache used by a particular page can be computed - * by taking the page's PA, modulo CHIP_L2_CACHE_SIZE(), and setting - * all the "4KB" bits corresponding to the actual page size. - * @param bitmask A bitmap of priority page set values - */ -void hv_set_caching(unsigned long bitmask); - - -/** Zero out a specified number of pages. - * The va and size must both be multiples of 4096. - * Caches are bypassed and memory is directly set to zero. - * This API is implemented only in the magic hypervisor and is intended - * to provide a performance boost to the minimal supervisor by - * giving it a fast way to zero memory pages when allocating them. - * @param va Virtual address where the page has been mapped - * @param size Number of bytes (must be a page size multiple) - */ -void hv_bzero_page(HV_VirtAddr va, unsigned int size); - - -/** State object for the hypervisor messaging subsystem. */ -typedef struct -{ -#if CHIP_VA_WIDTH() > 32 - __hv64 opaque[2]; /**< No user-serviceable parts inside */ -#else - __hv32 opaque[2]; /**< No user-serviceable parts inside */ -#endif -} -HV_MsgState; - -/** Register to receive incoming messages. - * - * This routine configures the current tile so that it can receive - * incoming messages. It must be called before the client can receive - * messages with the hv_receive_message routine, and must be called on - * each tile which will receive messages. - * - * msgstate is the virtual address of a state object of type HV_MsgState. - * Once the state is registered, the client must not read or write the - * state object; doing so will cause undefined results. - * - * If this routine is called with msgstate set to 0, the client's message - * state will be freed and it will no longer be able to receive messages. - * Note that this may cause the loss of any as-yet-undelivered messages - * for the client. - * - * If another client attempts to send a message to a client which has - * not yet called hv_register_message_state, or which has freed its - * message state, the message will not be delivered, as if the client - * had insufficient buffering. - * - * This routine returns HV_OK if the registration was successful, and - * HV_EINVAL if the supplied state object is unsuitable. Note that some - * errors may not be detected during this routine, but might be detected - * during a subsequent message delivery. - * @param msgstate State object. - **/ -HV_Errno hv_register_message_state(HV_MsgState* msgstate); - -/** Possible message recipient states. */ -typedef enum -{ - HV_TO_BE_SENT, /**< Not sent (not attempted, or recipient not ready) */ - HV_SENT, /**< Successfully sent */ - HV_BAD_RECIP /**< Bad recipient coordinates (permanent error) */ -} HV_Recip_State; - -/** Message recipient. */ -typedef struct -{ - /** X coordinate, relative to supervisor's top-left coordinate */ - unsigned int x:11; - - /** Y coordinate, relative to supervisor's top-left coordinate */ - unsigned int y:11; - - /** Status of this recipient */ - HV_Recip_State state:10; -} HV_Recipient; - -/** Send a message to a set of recipients. - * - * This routine sends a message to a set of recipients. - * - * recips is an array of HV_Recipient structures. Each specifies a tile, - * and a message state; initially, it is expected that the state will - * be set to HV_TO_BE_SENT. nrecip specifies the number of recipients - * in the recips array. - * - * For each recipient whose state is HV_TO_BE_SENT, the hypervisor attempts - * to send that tile the specified message. In order to successfully - * receive the message, the receiver must be a valid tile to which the - * sender has access, must not be the sending tile itself, and must have - * sufficient free buffer space. (The hypervisor guarantees that each - * tile which has called hv_register_message_state() will be able to - * buffer one message from every other tile which can legally send to it; - * more space may be provided but is not guaranteed.) If an invalid tile - * is specified, the recipient's state is set to HV_BAD_RECIP; this is a - * permanent delivery error. If the message is successfully delivered - * to the recipient's buffer, the recipient's state is set to HV_SENT. - * Otherwise, the recipient's state is unchanged. Message delivery is - * synchronous; all attempts to send messages are completed before this - * routine returns. - * - * If no permanent delivery errors were encountered, the routine returns - * the number of messages successfully sent: that is, the number of - * recipients whose states changed from HV_TO_BE_SENT to HV_SENT during - * this operation. If any permanent delivery errors were encountered, - * the routine returns HV_ERECIP. In the event of permanent delivery - * errors, it may be the case that delivery was not attempted to all - * recipients; if any messages were successfully delivered, however, - * recipients' state values will be updated appropriately. - * - * It is explicitly legal to specify a recipient structure whose state - * is not HV_TO_BE_SENT; such a recipient is ignored. One suggested way - * of using hv_send_message to send a message to multiple tiles is to set - * up a list of recipients, and then call the routine repeatedly with the - * same list, each time accumulating the number of messages successfully - * sent, until all messages are sent, a permanent error is encountered, - * or the desired number of attempts have been made. When used in this - * way, the routine will deliver each message no more than once to each - * recipient. - * - * Note that a message being successfully delivered to the recipient's - * buffer space does not guarantee that it is received by the recipient, - * either immediately or at any time in the future; the recipient might - * never call hv_receive_message, or could register a different state - * buffer, losing the message. - * - * Specifying the same recipient more than once in the recipient list - * is an error, which will not result in an error return but which may - * or may not result in more than one message being delivered to the - * recipient tile. - * - * buf and buflen specify the message to be sent. buf is a virtual address - * which must be currently mapped in the client's page table; if not, the - * routine returns HV_EFAULT. buflen must be greater than zero and less - * than or equal to HV_MAX_MESSAGE_SIZE, and nrecip must be less than the - * number of tiles to which the sender has access; if not, the routine - * returns HV_EINVAL. - * @param recips List of recipients. - * @param nrecip Number of recipients. - * @param buf Address of message data. - * @param buflen Length of message data. - **/ -int hv_send_message(HV_Recipient *recips, int nrecip, - HV_VirtAddr buf, int buflen); - -/** Maximum hypervisor message size, in bytes */ -#define HV_MAX_MESSAGE_SIZE 28 - - -/** Return value from hv_receive_message() */ -typedef struct -{ - int msglen; /**< Message length in bytes, or an error code */ - __hv32 source; /**< Code identifying message sender (HV_MSG_xxx) */ -} HV_RcvMsgInfo; - -#define HV_MSG_TILE 0x0 /**< Message source is another tile */ -#define HV_MSG_INTR 0x1 /**< Message source is a driver interrupt */ - -/** Receive a message. - * - * This routine retrieves a message from the client's incoming message - * buffer. - * - * Multiple messages sent from a particular sending tile to a particular - * receiving tile are received in the order that they were sent; however, - * no ordering is guaranteed between messages sent by different tiles. - * - * Whenever the a client's message buffer is empty, the first message - * subsequently received will cause the client's MESSAGE_RCV_DWNCL - * interrupt vector to be invoked through the interrupt downcall mechanism - * (see the description of the hv_downcall_dispatch() routine for details - * on downcalls). - * - * Another message-available downcall will not occur until a call to - * this routine is made when the message buffer is empty, and a message - * subsequently arrives. Note that such a downcall could occur while - * this routine is executing. If the calling code does not wish this - * to happen, it is recommended that this routine be called with the - * INTCTRL_1 interrupt masked, or inside an interrupt critical section. - * - * msgstate is the value previously passed to hv_register_message_state(). - * buf is the virtual address of the buffer into which the message will - * be written; buflen is the length of the buffer. - * - * This routine returns an HV_RcvMsgInfo structure. The msglen member - * of that structure is the length of the message received, zero if no - * message is available, or HV_E2BIG if the message is too large for the - * specified buffer. If the message is too large, it is not consumed, - * and may be retrieved by a subsequent call to this routine specifying - * a sufficiently large buffer. A buffer which is HV_MAX_MESSAGE_SIZE - * bytes long is guaranteed to be able to receive any possible message. - * - * The source member of the HV_RcvMsgInfo structure describes the sender - * of the message. For messages sent by another client tile via an - * hv_send_message() call, this value is HV_MSG_TILE; for messages sent - * as a result of a device interrupt, this value is HV_MSG_INTR. - */ - -HV_RcvMsgInfo hv_receive_message(HV_MsgState msgstate, HV_VirtAddr buf, - int buflen); - - -/** Start remaining tiles owned by this supervisor. Initially, only one tile - * executes the client program; after it calls this service, the other tiles - * are started. This allows the initial tile to do one-time configuration - * of shared data structures without having to lock them against simultaneous - * access. - */ -void hv_start_all_tiles(void); - - -/** Open a hypervisor device. - * - * This service initializes an I/O device and its hypervisor driver software, - * and makes it available for use. The open operation is per-device per-chip; - * once it has been performed, the device handle returned may be used in other - * device services calls made by any tile. - * - * @param name Name of the device. A base device name is just a text string - * (say, "pcie"). If there is more than one instance of a device, the - * base name is followed by a slash and a device number (say, "pcie/0"). - * Some devices may support further structure beneath those components; - * most notably, devices which require control operations do so by - * supporting reads and/or writes to a control device whose name - * includes a trailing "/ctl" (say, "pcie/0/ctl"). - * @param flags Flags (HV_DEV_xxx). - * @return A positive integer device handle, or a negative error code. - */ -int hv_dev_open(HV_VirtAddr name, __hv32 flags); - - -/** Close a hypervisor device. - * - * This service uninitializes an I/O device and its hypervisor driver - * software, and makes it unavailable for use. The close operation is - * per-device per-chip; once it has been performed, the device is no longer - * available. Normally there is no need to ever call the close service. - * - * @param devhdl Device handle of the device to be closed. - * @return Zero if the close is successful, otherwise, a negative error code. - */ -int hv_dev_close(int devhdl); - - -/** Read data from a hypervisor device synchronously. - * - * This service transfers data from a hypervisor device to a memory buffer. - * When the service returns, the data has been written from the memory buffer, - * and the buffer will not be further modified by the driver. - * - * No ordering is guaranteed between requests issued from different tiles. - * - * Devices may choose to support both the synchronous and asynchronous read - * operations, only one of them, or neither of them. - * - * @param devhdl Device handle of the device to be read from. - * @param flags Flags (HV_DEV_xxx). - * @param va Virtual address of the target data buffer. This buffer must - * be mapped in the currently installed page table; if not, HV_EFAULT - * may be returned. - * @param len Number of bytes to be transferred. - * @param offset Driver-dependent offset. For a random-access device, this is - * often a byte offset from the beginning of the device; in other cases, - * like on a control device, it may have a different meaning. - * @return A non-negative value if the read was at least partially successful; - * otherwise, a negative error code. The precise interpretation of - * the return value is driver-dependent, but many drivers will return - * the number of bytes successfully transferred. - */ -int hv_dev_pread(int devhdl, __hv32 flags, HV_VirtAddr va, __hv32 len, - __hv64 offset); - -#define HV_DEV_NB_EMPTY 0x1 /**< Don't block when no bytes of data can - be transferred. */ -#define HV_DEV_NB_PARTIAL 0x2 /**< Don't block when some bytes, but not all - of the requested bytes, can be - transferred. */ -#define HV_DEV_NOCACHE 0x4 /**< The caller warrants that none of the - cache lines which might contain data - from the requested buffer are valid. - Useful with asynchronous operations - only. */ - -#define HV_DEV_ALLFLAGS (HV_DEV_NB_EMPTY | HV_DEV_NB_PARTIAL | \ - HV_DEV_NOCACHE) /**< All HV_DEV_xxx flags */ - -/** Write data to a hypervisor device synchronously. - * - * This service transfers data from a memory buffer to a hypervisor device. - * When the service returns, the data has been read from the memory buffer, - * and the buffer may be overwritten by the client; the data may not - * necessarily have been conveyed to the actual hardware I/O interface. - * - * No ordering is guaranteed between requests issued from different tiles. - * - * Devices may choose to support both the synchronous and asynchronous write - * operations, only one of them, or neither of them. - * - * @param devhdl Device handle of the device to be written to. - * @param flags Flags (HV_DEV_xxx). - * @param va Virtual address of the source data buffer. This buffer must - * be mapped in the currently installed page table; if not, HV_EFAULT - * may be returned. - * @param len Number of bytes to be transferred. - * @param offset Driver-dependent offset. For a random-access device, this is - * often a byte offset from the beginning of the device; in other cases, - * like on a control device, it may have a different meaning. - * @return A non-negative value if the write was at least partially successful; - * otherwise, a negative error code. The precise interpretation of - * the return value is driver-dependent, but many drivers will return - * the number of bytes successfully transferred. - */ -int hv_dev_pwrite(int devhdl, __hv32 flags, HV_VirtAddr va, __hv32 len, - __hv64 offset); - - -/** Interrupt arguments, used in the asynchronous I/O interfaces. */ -#if CHIP_VA_WIDTH() > 32 -typedef __hv64 HV_IntArg; -#else -typedef __hv32 HV_IntArg; -#endif - -/** Interrupt messages are delivered via the mechanism as normal messages, - * but have a message source of HV_DEV_INTR. The message is formatted - * as an HV_IntrMsg structure. - */ - -typedef struct -{ - HV_IntArg intarg; /**< Interrupt argument, passed to the poll/preada/pwritea - services */ - HV_IntArg intdata; /**< Interrupt-specific interrupt data */ -} HV_IntrMsg; - -/** Request an interrupt message when a device condition is satisfied. - * - * This service requests that an interrupt message be delivered to the - * requesting tile when a device becomes readable or writable, or when any - * data queued to the device via previous write operations from this tile - * has been actually sent out on the hardware I/O interface. Devices may - * choose to support any, all, or none of the available conditions. - * - * If multiple conditions are specified, only one message will be - * delivered. If the event mask delivered to that interrupt handler - * indicates that some of the conditions have not yet occurred, the - * client must issue another poll() call if it wishes to wait for those - * conditions. - * - * Only one poll may be outstanding per device handle per tile. If more than - * one tile is polling on the same device and condition, they will all be - * notified when it happens. Because of this, clients may not assume that - * the condition signaled is necessarily still true when they request a - * subsequent service; for instance, the readable data which caused the - * poll call to interrupt may have been read by another tile in the interim. - * - * The notification interrupt message could come directly, or via the - * downcall (intctrl1) method, depending on what the tile is doing - * when the condition is satisfied. Note that it is possible for the - * requested interrupt to be delivered after this service is called but - * before it returns. - * - * @param devhdl Device handle of the device to be polled. - * @param events Flags denoting the events which will cause the interrupt to - * be delivered (HV_DEVPOLL_xxx). - * @param intarg Value which will be delivered as the intarg member of the - * eventual interrupt message; the intdata member will be set to a - * mask of HV_DEVPOLL_xxx values indicating which conditions have been - * satisifed. - * @return Zero if the interrupt was successfully scheduled; otherwise, a - * negative error code. - */ -int hv_dev_poll(int devhdl, __hv32 events, HV_IntArg intarg); - -#define HV_DEVPOLL_READ 0x1 /**< Test device for readability */ -#define HV_DEVPOLL_WRITE 0x2 /**< Test device for writability */ -#define HV_DEVPOLL_FLUSH 0x4 /**< Test device for output drained */ - - -/** Cancel a request for an interrupt when a device event occurs. - * - * This service requests that no interrupt be delivered when the events - * noted in the last-issued poll() call happen. Once this service returns, - * the interrupt has been canceled; however, it is possible for the interrupt - * to be delivered after this service is called but before it returns. - * - * @param devhdl Device handle of the device on which to cancel polling. - * @return Zero if the poll was successfully canceled; otherwise, a negative - * error code. - */ -int hv_dev_poll_cancel(int devhdl); - - -/** NMI information */ -typedef struct -{ - /** Result: negative error, or HV_NMI_RESULT_xxx. */ - int result; - - /** PC from interrupted remote core (if result != HV_NMI_RESULT_FAIL_HV). */ - HV_VirtAddr pc; - -} HV_NMI_Info; - -/** NMI issued successfully. */ -#define HV_NMI_RESULT_OK 0 - -/** NMI not issued: remote tile running at client PL with ICS set. */ -#define HV_NMI_RESULT_FAIL_ICS 1 - -/** NMI not issued: remote tile waiting in hypervisor. */ -#define HV_NMI_RESULT_FAIL_HV 2 - -/** Force an NMI downcall regardless of the ICS bit of the client. */ -#define HV_NMI_FLAG_FORCE 0x1 - -/** Send an NMI interrupt request to a particular tile. - * - * This will cause the NMI to be issued on the remote tile regardless - * of the state of the client interrupt mask. However, if the remote - * tile is in the hypervisor, it will not execute the NMI, and - * HV_NMI_RESULT_FAIL_HV will be returned. Similarly, if the remote - * tile is in a client interrupt critical section at the time of the - * NMI, it will not execute the NMI, and HV_NMI_RESULT_FAIL_ICS will - * be returned. In this second case, however, if HV_NMI_FLAG_FORCE - * is set in flags, then the remote tile will enter its NMI interrupt - * vector regardless. Forcing the NMI vector during an interrupt - * critical section will mean that the client can not safely continue - * execution after handling the interrupt. - * - * @param tile Tile to which the NMI request is sent. - * @param info NMI information which is defined by and interpreted by the - * supervisor, is passed to the specified tile, and is - * stored in the SPR register SYSTEM_SAVE_{CLIENT_PL}_2 on the - * specified tile when entering the NMI handler routine. - * Typically, this parameter stores the NMI type, or an aligned - * VA plus some special bits, etc. - * @param flags Flags (HV_NMI_FLAG_xxx). - * @return Information about the requested NMI. - */ -HV_NMI_Info hv_send_nmi(HV_Coord tile, unsigned long info, __hv64 flags); - - -/** Scatter-gather list for preada/pwritea calls. */ -typedef struct -#if CHIP_VA_WIDTH() <= 32 -__attribute__ ((packed, aligned(4))) -#endif -{ - HV_PhysAddr pa; /**< Client physical address of the buffer segment. */ - HV_PTE pte; /**< Page table entry describing the caching and location - override characteristics of the buffer segment. Some - drivers ignore this element and will require that - the NOCACHE flag be set on their requests. */ - __hv32 len; /**< Length of the buffer segment. */ -} HV_SGL; - -#define HV_SGL_MAXLEN 16 /**< Maximum number of entries in a scatter-gather - list */ - -/** Read data from a hypervisor device asynchronously. - * - * This service transfers data from a hypervisor device to a memory buffer. - * When the service returns, the read has been scheduled. When the read - * completes, an interrupt message will be delivered, and the buffer will - * not be further modified by the driver. - * - * The number of possible outstanding asynchronous requests is defined by - * each driver, but it is recommended that it be at least two requests - * per tile per device. - * - * No ordering is guaranteed between synchronous and asynchronous requests, - * even those issued on the same tile. - * - * The completion interrupt message could come directly, or via the downcall - * (intctrl1) method, depending on what the tile is doing when the read - * completes. Interrupts do not coalesce; one is delivered for each - * asynchronous I/O request. Note that it is possible for the requested - * interrupt to be delivered after this service is called but before it - * returns. - * - * Devices may choose to support both the synchronous and asynchronous read - * operations, only one of them, or neither of them. - * - * @param devhdl Device handle of the device to be read from. - * @param flags Flags (HV_DEV_xxx). - * @param sgl_len Number of elements in the scatter-gather list. - * @param sgl Scatter-gather list describing the memory to which data will be - * written. - * @param offset Driver-dependent offset. For a random-access device, this is - * often a byte offset from the beginning of the device; in other cases, - * like on a control device, it may have a different meaning. - * @param intarg Value which will be delivered as the intarg member of the - * eventual interrupt message; the intdata member will be set to the - * normal return value from the read request. - * @return Zero if the read was successfully scheduled; otherwise, a negative - * error code. Note that some drivers may choose to pre-validate - * their arguments, and may thus detect certain device error - * conditions at this time rather than when the completion notification - * occurs, but this is not required. - */ -int hv_dev_preada(int devhdl, __hv32 flags, __hv32 sgl_len, - HV_SGL sgl[/* sgl_len */], __hv64 offset, HV_IntArg intarg); - - -/** Write data to a hypervisor device asynchronously. - * - * This service transfers data from a memory buffer to a hypervisor - * device. When the service returns, the write has been scheduled. - * When the write completes, an interrupt message will be delivered, - * and the buffer may be overwritten by the client; the data may not - * necessarily have been conveyed to the actual hardware I/O interface. - * - * The number of possible outstanding asynchronous requests is defined by - * each driver, but it is recommended that it be at least two requests - * per tile per device. - * - * No ordering is guaranteed between synchronous and asynchronous requests, - * even those issued on the same tile. - * - * The completion interrupt message could come directly, or via the downcall - * (intctrl1) method, depending on what the tile is doing when the read - * completes. Interrupts do not coalesce; one is delivered for each - * asynchronous I/O request. Note that it is possible for the requested - * interrupt to be delivered after this service is called but before it - * returns. - * - * Devices may choose to support both the synchronous and asynchronous write - * operations, only one of them, or neither of them. - * - * @param devhdl Device handle of the device to be read from. - * @param flags Flags (HV_DEV_xxx). - * @param sgl_len Number of elements in the scatter-gather list. - * @param sgl Scatter-gather list describing the memory from which data will be - * read. - * @param offset Driver-dependent offset. For a random-access device, this is - * often a byte offset from the beginning of the device; in other cases, - * like on a control device, it may have a different meaning. - * @param intarg Value which will be delivered as the intarg member of the - * eventual interrupt message; the intdata member will be set to the - * normal return value from the write request. - * @return Zero if the write was successfully scheduled; otherwise, a negative - * error code. Note that some drivers may choose to pre-validate - * their arguments, and may thus detect certain device error - * conditions at this time rather than when the completion notification - * occurs, but this is not required. - */ -int hv_dev_pwritea(int devhdl, __hv32 flags, __hv32 sgl_len, - HV_SGL sgl[/* sgl_len */], __hv64 offset, HV_IntArg intarg); - - -/** Define a pair of tile and ASID to identify a user process context. */ -typedef struct -{ - /** X coordinate, relative to supervisor's top-left coordinate */ - unsigned int x:11; - - /** Y coordinate, relative to supervisor's top-left coordinate */ - unsigned int y:11; - - /** ASID of the process on this x,y tile */ - HV_ASID asid:10; -} HV_Remote_ASID; - -/** Flush cache and/or TLB state on remote tiles. - * - * @param cache_pa Client physical address to flush from cache (ignored if - * the length encoded in cache_control is zero, or if - * HV_FLUSH_EVICT_L2 is set, or if cache_cpumask is NULL). - * @param cache_control This argument allows you to specify a length of - * physical address space to flush (maximum HV_FLUSH_MAX_CACHE_LEN). - * You can "or" in HV_FLUSH_EVICT_L2 to flush the whole L2 cache. - * You can "or" in HV_FLUSH_EVICT_L1I to flush the whole L1I cache. - * HV_FLUSH_ALL flushes all caches. - * @param cache_cpumask Bitmask (in row-major order, supervisor-relative) of - * tile indices to perform cache flush on. The low bit of the first - * word corresponds to the tile at the upper left-hand corner of the - * supervisor's rectangle. If passed as a NULL pointer, equivalent - * to an empty bitmask. On chips which support hash-for-home caching, - * if passed as -1, equivalent to a mask containing tiles which could - * be doing hash-for-home caching. - * @param tlb_va Virtual address to flush from TLB (ignored if - * tlb_length is zero or tlb_cpumask is NULL). - * @param tlb_length Number of bytes of data to flush from the TLB. - * @param tlb_pgsize Page size to use for TLB flushes. - * tlb_va and tlb_length need not be aligned to this size. - * @param tlb_cpumask Bitmask for tlb flush, like cache_cpumask. - * If passed as a NULL pointer, equivalent to an empty bitmask. - * @param asids Pointer to an HV_Remote_ASID array of tile/ASID pairs to flush. - * @param asidcount Number of HV_Remote_ASID entries in asids[]. - * @return Zero for success, or else HV_EINVAL or HV_EFAULT for errors that - * are detected while parsing the arguments. - */ -int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control, - unsigned long* cache_cpumask, - HV_VirtAddr tlb_va, unsigned long tlb_length, - unsigned long tlb_pgsize, unsigned long* tlb_cpumask, - HV_Remote_ASID* asids, int asidcount); - -/** Include in cache_control to ensure a flush of the entire L2. */ -#define HV_FLUSH_EVICT_L2 (1UL << 31) - -/** Include in cache_control to ensure a flush of the entire L1I. */ -#define HV_FLUSH_EVICT_L1I (1UL << 30) - -/** Maximum legal size to use for the "length" component of cache_control. */ -#define HV_FLUSH_MAX_CACHE_LEN ((1UL << 30) - 1) - -/** Use for cache_control to ensure a flush of all caches. */ -#define HV_FLUSH_ALL -1UL - -#else /* __ASSEMBLER__ */ - -/** Include in cache_control to ensure a flush of the entire L2. */ -#define HV_FLUSH_EVICT_L2 (1 << 31) - -/** Include in cache_control to ensure a flush of the entire L1I. */ -#define HV_FLUSH_EVICT_L1I (1 << 30) - -/** Maximum legal size to use for the "length" component of cache_control. */ -#define HV_FLUSH_MAX_CACHE_LEN ((1 << 30) - 1) - -/** Use for cache_control to ensure a flush of all caches. */ -#define HV_FLUSH_ALL -1 - -#endif /* __ASSEMBLER__ */ - -#ifndef __ASSEMBLER__ - -/** Return a 64-bit value corresponding to the PTE if needed */ -#define hv_pte_val(pte) ((pte).val) - -/** Cast a 64-bit value to an HV_PTE */ -#define hv_pte(val) ((HV_PTE) { val }) - -#endif /* !__ASSEMBLER__ */ - - -/** Bits in the size of an HV_PTE */ -#define HV_LOG2_PTE_SIZE 3 - -/** Size of an HV_PTE */ -#define HV_PTE_SIZE (1 << HV_LOG2_PTE_SIZE) - - -/* Bits in HV_PTE's low word. */ -#define HV_PTE_INDEX_PRESENT 0 /**< PTE is valid */ -#define HV_PTE_INDEX_MIGRATING 1 /**< Page is migrating */ -#define HV_PTE_INDEX_CLIENT0 2 /**< Page client state 0 */ -#define HV_PTE_INDEX_CLIENT1 3 /**< Page client state 1 */ -#define HV_PTE_INDEX_NC 4 /**< L1$/L2$ incoherent with L3$ */ -#define HV_PTE_INDEX_NO_ALLOC_L1 5 /**< Page is uncached in local L1$ */ -#define HV_PTE_INDEX_NO_ALLOC_L2 6 /**< Page is uncached in local L2$ */ -#define HV_PTE_INDEX_CACHED_PRIORITY 7 /**< Page is priority cached */ -#define HV_PTE_INDEX_PAGE 8 /**< PTE describes a page */ -#define HV_PTE_INDEX_GLOBAL 9 /**< Page is global */ -#define HV_PTE_INDEX_USER 10 /**< Page is user-accessible */ -#define HV_PTE_INDEX_ACCESSED 11 /**< Page has been accessed */ -#define HV_PTE_INDEX_DIRTY 12 /**< Page has been written */ - /* Bits 13-14 are reserved for - future use. */ -#define HV_PTE_INDEX_SUPER 15 /**< Pages ganged together for TLB */ -#define HV_PTE_INDEX_MODE 16 /**< Page mode; see HV_PTE_MODE_xxx */ -#define HV_PTE_MODE_BITS 3 /**< Number of bits in mode */ -#define HV_PTE_INDEX_CLIENT2 19 /**< Page client state 2 */ -#define HV_PTE_INDEX_LOTAR 20 /**< Page's LOTAR; must be high bits - of word */ -#define HV_PTE_LOTAR_BITS 12 /**< Number of bits in a LOTAR */ - -/* Bits in HV_PTE's high word. */ -#define HV_PTE_INDEX_READABLE 32 /**< Page is readable */ -#define HV_PTE_INDEX_WRITABLE 33 /**< Page is writable */ -#define HV_PTE_INDEX_EXECUTABLE 34 /**< Page is executable */ -#define HV_PTE_INDEX_PTFN 35 /**< Page's PTFN; must be high bits - of word */ -#define HV_PTE_PTFN_BITS 29 /**< Number of bits in a PTFN */ - -/* - * Legal values for the PTE's mode field - */ -/** Data is not resident in any caches; loads and stores access memory - * directly. - */ -#define HV_PTE_MODE_UNCACHED 1 - -/** Data is resident in the tile's local L1 and/or L2 caches; if a load - * or store misses there, it goes to memory. - * - * The copy in the local L1$/L2$ is not invalidated when the copy in - * memory is changed. - */ -#define HV_PTE_MODE_CACHE_NO_L3 2 - -/** Data is resident in the tile's local L1 and/or L2 caches. If a load - * or store misses there, it goes to an L3 cache in a designated tile; - * if it misses there, it goes to memory. - * - * If the NC bit is not set, the copy in the local L1$/L2$ is invalidated - * when the copy in the remote L3$ is changed. Otherwise, such - * invalidation will not occur. - * - * Chips for which CHIP_HAS_COHERENT_LOCAL_CACHE() is 0 do not support - * invalidation from an L3$ to another tile's L1$/L2$. If the NC bit is - * clear on such a chip, no copy is kept in the local L1$/L2$ in this mode. - */ -#define HV_PTE_MODE_CACHE_TILE_L3 3 - -/** Data is resident in the tile's local L1 and/or L2 caches. If a load - * or store misses there, it goes to an L3 cache in one of a set of - * designated tiles; if it misses there, it goes to memory. Which tile - * is chosen from the set depends upon a hash function applied to the - * physical address. This mode is not supported on chips for which - * CHIP_HAS_CBOX_HOME_MAP() is 0. - * - * If the NC bit is not set, the copy in the local L1$/L2$ is invalidated - * when the copy in the remote L3$ is changed. Otherwise, such - * invalidation will not occur. - * - * Chips for which CHIP_HAS_COHERENT_LOCAL_CACHE() is 0 do not support - * invalidation from an L3$ to another tile's L1$/L2$. If the NC bit is - * clear on such a chip, no copy is kept in the local L1$/L2$ in this mode. - */ -#define HV_PTE_MODE_CACHE_HASH_L3 4 - -/** Data is not resident in memory; accesses are instead made to an I/O - * device, whose tile coordinates are given by the PTE's LOTAR field. - * This mode is only supported on chips for which CHIP_HAS_MMIO() is 1. - * The EXECUTABLE bit may not be set in an MMIO PTE. - */ -#define HV_PTE_MODE_MMIO 5 - - -/* C wants 1ULL so it is typed as __hv64, but the assembler needs just numbers. - * The assembler can't handle shifts greater than 31, but treats them - * as shifts mod 32, so assembler code must be aware of which word - * the bit belongs in when using these macros. - */ -#ifdef __ASSEMBLER__ -#define __HV_PTE_ONE 1 /**< One, for assembler */ -#else -#define __HV_PTE_ONE 1ULL /**< One, for C */ -#endif - -/** Is this PTE present? - * - * If this bit is set, this PTE represents a valid translation or level-2 - * page table pointer. Otherwise, the page table does not contain a - * translation for the subject virtual pages. - * - * If this bit is not set, the other bits in the PTE are not - * interpreted by the hypervisor, and may contain any value. - */ -#define HV_PTE_PRESENT (__HV_PTE_ONE << HV_PTE_INDEX_PRESENT) - -/** Does this PTE map a page? - * - * If this bit is set in a level-0 page table, the entry should be - * interpreted as a level-2 page table entry mapping a jumbo page. - * - * If this bit is set in a level-1 page table, the entry should be - * interpreted as a level-2 page table entry mapping a large page. - * - * This bit should not be modified by the client while PRESENT is set, as - * doing so may race with the hypervisor's update of ACCESSED and DIRTY bits. - * - * In a level-2 page table, this bit is ignored and must be zero. - */ -#define HV_PTE_PAGE (__HV_PTE_ONE << HV_PTE_INDEX_PAGE) - -/** Does this PTE implicitly reference multiple pages? - * - * If this bit is set in the page table (either in the level-2 page table, - * or in a higher level page table in conjunction with the PAGE bit) - * then the PTE specifies a range of contiguous pages, not a single page. - * The hv_set_pte_super_shift() allows you to specify the count for - * each level of the page table. - * - * Note: this bit is not supported on TILEPro systems. - */ -#define HV_PTE_SUPER (__HV_PTE_ONE << HV_PTE_INDEX_SUPER) - -/** Is this a global (non-ASID) mapping? - * - * If this bit is set, the translations established by this PTE will - * not be flushed from the TLB by the hv_flush_asid() service; they - * will be flushed by the hv_flush_page() or hv_flush_pages() services. - * - * Setting this bit for translations which are identical in all page - * tables (for instance, code and data belonging to a client OS) can - * be very beneficial, as it will reduce the number of TLB misses. - * Note that, while it is not an error which will be detected by the - * hypervisor, it is an extremely bad idea to set this bit for - * translations which are _not_ identical in all page tables. - * - * This bit should not be modified by the client while PRESENT is set, as - * doing so may race with the hypervisor's update of ACCESSED and DIRTY bits. - * - * This bit is ignored in level-1 PTEs unless the Page bit is set. - */ -#define HV_PTE_GLOBAL (__HV_PTE_ONE << HV_PTE_INDEX_GLOBAL) - -/** Is this mapping accessible to users? - * - * If this bit is set, code running at any PL will be permitted to - * access the virtual addresses mapped by this PTE. Otherwise, only - * code running at PL 1 or above will be allowed to do so. - * - * This bit should not be modified by the client while PRESENT is set, as - * doing so may race with the hypervisor's update of ACCESSED and DIRTY bits. - * - * This bit is ignored in level-1 PTEs unless the Page bit is set. - */ -#define HV_PTE_USER (__HV_PTE_ONE << HV_PTE_INDEX_USER) - -/** Has this mapping been accessed? - * - * This bit is set by the hypervisor when the memory described by the - * translation is accessed for the first time. It is never cleared by - * the hypervisor, but may be cleared by the client. After the bit - * has been cleared, subsequent references are not guaranteed to set - * it again until the translation has been flushed from the TLB. - * - * This bit is ignored in level-1 PTEs unless the Page bit is set. - */ -#define HV_PTE_ACCESSED (__HV_PTE_ONE << HV_PTE_INDEX_ACCESSED) - -/** Is this mapping dirty? - * - * This bit is set by the hypervisor when the memory described by the - * translation is written for the first time. It is never cleared by - * the hypervisor, but may be cleared by the client. After the bit - * has been cleared, subsequent references are not guaranteed to set - * it again until the translation has been flushed from the TLB. - * - * This bit is ignored in level-1 PTEs unless the Page bit is set. - */ -#define HV_PTE_DIRTY (__HV_PTE_ONE << HV_PTE_INDEX_DIRTY) - -/** Migrating bit in PTE. - * - * This bit is guaranteed not to be inspected or modified by the - * hypervisor. The name is indicative of the suggested use by the client - * to tag pages whose L3 cache is being migrated from one cpu to another. - */ -#define HV_PTE_MIGRATING (__HV_PTE_ONE << HV_PTE_INDEX_MIGRATING) - -/** Client-private bit in PTE. - * - * This bit is guaranteed not to be inspected or modified by the - * hypervisor. - */ -#define HV_PTE_CLIENT0 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT0) - -/** Client-private bit in PTE. - * - * This bit is guaranteed not to be inspected or modified by the - * hypervisor. - */ -#define HV_PTE_CLIENT1 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT1) - -/** Client-private bit in PTE. - * - * This bit is guaranteed not to be inspected or modified by the - * hypervisor. - */ -#define HV_PTE_CLIENT2 (__HV_PTE_ONE << HV_PTE_INDEX_CLIENT2) - -/** Non-coherent (NC) bit in PTE. - * - * If this bit is set, the mapping that is set up will be non-coherent - * (also known as non-inclusive). This means that changes to the L3 - * cache will not cause a local copy to be invalidated. It is generally - * recommended only for read-only mappings. - * - * In level-1 PTEs, if the Page bit is clear, this bit determines how the - * level-2 page table is accessed. - */ -#define HV_PTE_NC (__HV_PTE_ONE << HV_PTE_INDEX_NC) - -/** Is this page prevented from filling the L1$? - * - * If this bit is set, the page described by the PTE will not be cached - * the local cpu's L1 cache. - * - * If CHIP_HAS_NC_AND_NOALLOC_BITS() is not true in for this chip, - * it is illegal to use this attribute, and may cause client termination. - * - * In level-1 PTEs, if the Page bit is clear, this bit - * determines how the level-2 page table is accessed. - */ -#define HV_PTE_NO_ALLOC_L1 (__HV_PTE_ONE << HV_PTE_INDEX_NO_ALLOC_L1) - -/** Is this page prevented from filling the L2$? - * - * If this bit is set, the page described by the PTE will not be cached - * the local cpu's L2 cache. - * - * If CHIP_HAS_NC_AND_NOALLOC_BITS() is not true in for this chip, - * it is illegal to use this attribute, and may cause client termination. - * - * In level-1 PTEs, if the Page bit is clear, this bit determines how the - * level-2 page table is accessed. - */ -#define HV_PTE_NO_ALLOC_L2 (__HV_PTE_ONE << HV_PTE_INDEX_NO_ALLOC_L2) - -/** Is this a priority page? - * - * If this bit is set, the page described by the PTE will be given - * priority in the cache. Normally this translates into allowing the - * page to use only the "red" half of the cache. The client may wish to - * then use the hv_set_caching service to specify that other pages which - * alias this page will use only the "black" half of the cache. - * - * If the Cached Priority bit is clear, the hypervisor uses the - * current hv_set_caching() value to choose how to cache the page. - * - * It is illegal to set the Cached Priority bit if the Non-Cached bit - * is set and the Cached Remotely bit is clear, i.e. if requests to - * the page map directly to memory. - * - * This bit is ignored in level-1 PTEs unless the Page bit is set. - */ -#define HV_PTE_CACHED_PRIORITY (__HV_PTE_ONE << \ - HV_PTE_INDEX_CACHED_PRIORITY) - -/** Is this a readable mapping? - * - * If this bit is set, code will be permitted to read from (e.g., - * issue load instructions against) the virtual addresses mapped by - * this PTE. - * - * It is illegal for this bit to be clear if the Writable bit is set. - * - * This bit is ignored in level-1 PTEs unless the Page bit is set. - */ -#define HV_PTE_READABLE (__HV_PTE_ONE << HV_PTE_INDEX_READABLE) - -/** Is this a writable mapping? - * - * If this bit is set, code will be permitted to write to (e.g., issue - * store instructions against) the virtual addresses mapped by this - * PTE. - * - * This bit is ignored in level-1 PTEs unless the Page bit is set. - */ -#define HV_PTE_WRITABLE (__HV_PTE_ONE << HV_PTE_INDEX_WRITABLE) - -/** Is this an executable mapping? - * - * If this bit is set, code will be permitted to execute from - * (e.g., jump to) the virtual addresses mapped by this PTE. - * - * This bit applies to any processor on the tile, if there are more - * than one. - * - * This bit is ignored in level-1 PTEs unless the Page bit is set. - */ -#define HV_PTE_EXECUTABLE (__HV_PTE_ONE << HV_PTE_INDEX_EXECUTABLE) - -/** The width of a LOTAR's x or y bitfield. */ -#define HV_LOTAR_WIDTH 11 - -/** Converts an x,y pair to a LOTAR value. */ -#define HV_XY_TO_LOTAR(x, y) ((HV_LOTAR)(((x) << HV_LOTAR_WIDTH) | (y))) - -/** Extracts the X component of a lotar. */ -#define HV_LOTAR_X(lotar) ((lotar) >> HV_LOTAR_WIDTH) - -/** Extracts the Y component of a lotar. */ -#define HV_LOTAR_Y(lotar) ((lotar) & ((1 << HV_LOTAR_WIDTH) - 1)) - -#ifndef __ASSEMBLER__ - -/** Define accessor functions for a PTE bit. */ -#define _HV_BIT(name, bit) \ -static __inline int \ -hv_pte_get_##name(HV_PTE pte) \ -{ \ - return (pte.val >> HV_PTE_INDEX_##bit) & 1; \ -} \ - \ -static __inline HV_PTE \ -hv_pte_set_##name(HV_PTE pte) \ -{ \ - pte.val |= 1ULL << HV_PTE_INDEX_##bit; \ - return pte; \ -} \ - \ -static __inline HV_PTE \ -hv_pte_clear_##name(HV_PTE pte) \ -{ \ - pte.val &= ~(1ULL << HV_PTE_INDEX_##bit); \ - return pte; \ -} - -/* Generate accessors to get, set, and clear various PTE flags. - */ -_HV_BIT(present, PRESENT) -_HV_BIT(page, PAGE) -_HV_BIT(super, SUPER) -_HV_BIT(client0, CLIENT0) -_HV_BIT(client1, CLIENT1) -_HV_BIT(client2, CLIENT2) -_HV_BIT(migrating, MIGRATING) -_HV_BIT(nc, NC) -_HV_BIT(readable, READABLE) -_HV_BIT(writable, WRITABLE) -_HV_BIT(executable, EXECUTABLE) -_HV_BIT(accessed, ACCESSED) -_HV_BIT(dirty, DIRTY) -_HV_BIT(no_alloc_l1, NO_ALLOC_L1) -_HV_BIT(no_alloc_l2, NO_ALLOC_L2) -_HV_BIT(cached_priority, CACHED_PRIORITY) -_HV_BIT(global, GLOBAL) -_HV_BIT(user, USER) - -#undef _HV_BIT - -/** Get the page mode from the PTE. - * - * This field generally determines whether and how accesses to the page - * are cached; the HV_PTE_MODE_xxx symbols define the legal values for the - * page mode. The NC, NO_ALLOC_L1, and NO_ALLOC_L2 bits modify this - * general policy. - */ -static __inline unsigned int -hv_pte_get_mode(const HV_PTE pte) -{ - return (((__hv32) pte.val) >> HV_PTE_INDEX_MODE) & - ((1 << HV_PTE_MODE_BITS) - 1); -} - -/** Set the page mode into a PTE. See hv_pte_get_mode. */ -static __inline HV_PTE -hv_pte_set_mode(HV_PTE pte, unsigned int val) -{ - pte.val &= ~(((1ULL << HV_PTE_MODE_BITS) - 1) << HV_PTE_INDEX_MODE); - pte.val |= val << HV_PTE_INDEX_MODE; - return pte; -} - -/** Get the page frame number from the PTE. - * - * This field contains the upper bits of the CPA (client physical - * address) of the target page; the complete CPA is this field with - * HV_LOG2_PAGE_TABLE_ALIGN zero bits appended to it. - * - * For all PTEs in the lowest-level page table, and for all PTEs with - * the Page bit set in all page tables, the CPA must be aligned modulo - * the relevant page size. - */ -static __inline unsigned long -hv_pte_get_ptfn(const HV_PTE pte) -{ - return pte.val >> HV_PTE_INDEX_PTFN; -} - -/** Set the page table frame number into a PTE. See hv_pte_get_ptfn. */ -static __inline HV_PTE -hv_pte_set_ptfn(HV_PTE pte, unsigned long val) -{ - pte.val &= ~(((1ULL << HV_PTE_PTFN_BITS)-1) << HV_PTE_INDEX_PTFN); - pte.val |= (__hv64) val << HV_PTE_INDEX_PTFN; - return pte; -} - -/** Get the client physical address from the PTE. See hv_pte_set_ptfn. */ -static __inline HV_PhysAddr -hv_pte_get_pa(const HV_PTE pte) -{ - return (__hv64) hv_pte_get_ptfn(pte) << HV_LOG2_PAGE_TABLE_ALIGN; -} - -/** Set the client physical address into a PTE. See hv_pte_get_ptfn. */ -static __inline HV_PTE -hv_pte_set_pa(HV_PTE pte, HV_PhysAddr pa) -{ - return hv_pte_set_ptfn(pte, pa >> HV_LOG2_PAGE_TABLE_ALIGN); -} - - -/** Get the remote tile caching this page. - * - * Specifies the remote tile which is providing the L3 cache for this page. - * - * This field is ignored unless the page mode is HV_PTE_MODE_CACHE_TILE_L3. - * - * In level-1 PTEs, if the Page bit is clear, this field determines how the - * level-2 page table is accessed. - */ -static __inline unsigned int -hv_pte_get_lotar(const HV_PTE pte) -{ - unsigned int lotar = ((__hv32) pte.val) >> HV_PTE_INDEX_LOTAR; - - return HV_XY_TO_LOTAR( (lotar >> (HV_PTE_LOTAR_BITS / 2)), - (lotar & ((1 << (HV_PTE_LOTAR_BITS / 2)) - 1)) ); -} - - -/** Set the remote tile caching a page into a PTE. See hv_pte_get_lotar. */ -static __inline HV_PTE -hv_pte_set_lotar(HV_PTE pte, unsigned int val) -{ - unsigned int x = HV_LOTAR_X(val); - unsigned int y = HV_LOTAR_Y(val); - - pte.val &= ~(((1ULL << HV_PTE_LOTAR_BITS)-1) << HV_PTE_INDEX_LOTAR); - pte.val |= (x << (HV_PTE_INDEX_LOTAR + HV_PTE_LOTAR_BITS / 2)) | - (y << HV_PTE_INDEX_LOTAR); - return pte; -} - -#endif /* !__ASSEMBLER__ */ - -/** Converts a client physical address to a ptfn. */ -#define HV_CPA_TO_PTFN(p) ((p) >> HV_LOG2_PAGE_TABLE_ALIGN) - -/** Converts a ptfn to a client physical address. */ -#define HV_PTFN_TO_CPA(p) (((HV_PhysAddr)(p)) << HV_LOG2_PAGE_TABLE_ALIGN) - -#if CHIP_VA_WIDTH() > 32 - -/* - * Note that we currently do not allow customizing the page size - * of the L0 pages, but fix them at 4GB, so we do not use the - * "_HV_xxx" nomenclature for the L0 macros. - */ - -/** Log number of HV_PTE entries in L0 page table */ -#define HV_LOG2_L0_ENTRIES (CHIP_VA_WIDTH() - HV_LOG2_L1_SPAN) - -/** Number of HV_PTE entries in L0 page table */ -#define HV_L0_ENTRIES (1 << HV_LOG2_L0_ENTRIES) - -/** Log size of L0 page table in bytes */ -#define HV_LOG2_L0_SIZE (HV_LOG2_PTE_SIZE + HV_LOG2_L0_ENTRIES) - -/** Size of L0 page table in bytes */ -#define HV_L0_SIZE (1 << HV_LOG2_L0_SIZE) - -#ifdef __ASSEMBLER__ - -/** Index in L0 for a specific VA */ -#define HV_L0_INDEX(va) \ - (((va) >> HV_LOG2_L1_SPAN) & (HV_L0_ENTRIES - 1)) - -#else - -/** Index in L1 for a specific VA */ -#define HV_L0_INDEX(va) \ - (((HV_VirtAddr)(va) >> HV_LOG2_L1_SPAN) & (HV_L0_ENTRIES - 1)) - -#endif - -#endif /* CHIP_VA_WIDTH() > 32 */ - -/** Log number of HV_PTE entries in L1 page table */ -#define _HV_LOG2_L1_ENTRIES(log2_page_size_large) \ - (HV_LOG2_L1_SPAN - log2_page_size_large) - -/** Number of HV_PTE entries in L1 page table */ -#define _HV_L1_ENTRIES(log2_page_size_large) \ - (1 << _HV_LOG2_L1_ENTRIES(log2_page_size_large)) - -/** Log size of L1 page table in bytes */ -#define _HV_LOG2_L1_SIZE(log2_page_size_large) \ - (HV_LOG2_PTE_SIZE + _HV_LOG2_L1_ENTRIES(log2_page_size_large)) - -/** Size of L1 page table in bytes */ -#define _HV_L1_SIZE(log2_page_size_large) \ - (1 << _HV_LOG2_L1_SIZE(log2_page_size_large)) - -/** Log number of HV_PTE entries in level-2 page table */ -#define _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small) \ - (log2_page_size_large - log2_page_size_small) - -/** Number of HV_PTE entries in level-2 page table */ -#define _HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) \ - (1 << _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small)) - -/** Log size of level-2 page table in bytes */ -#define _HV_LOG2_L2_SIZE(log2_page_size_large, log2_page_size_small) \ - (HV_LOG2_PTE_SIZE + \ - _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small)) - -/** Size of level-2 page table in bytes */ -#define _HV_L2_SIZE(log2_page_size_large, log2_page_size_small) \ - (1 << _HV_LOG2_L2_SIZE(log2_page_size_large, log2_page_size_small)) - -#ifdef __ASSEMBLER__ - -#if CHIP_VA_WIDTH() > 32 - -/** Index in L1 for a specific VA */ -#define _HV_L1_INDEX(va, log2_page_size_large) \ - (((va) >> log2_page_size_large) & (_HV_L1_ENTRIES(log2_page_size_large) - 1)) - -#else /* CHIP_VA_WIDTH() > 32 */ - -/** Index in L1 for a specific VA */ -#define _HV_L1_INDEX(va, log2_page_size_large) \ - (((va) >> log2_page_size_large)) - -#endif /* CHIP_VA_WIDTH() > 32 */ - -/** Index in level-2 page table for a specific VA */ -#define _HV_L2_INDEX(va, log2_page_size_large, log2_page_size_small) \ - (((va) >> log2_page_size_small) & \ - (_HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) - 1)) - -#else /* __ASSEMBLER __ */ - -#if CHIP_VA_WIDTH() > 32 - -/** Index in L1 for a specific VA */ -#define _HV_L1_INDEX(va, log2_page_size_large) \ - (((HV_VirtAddr)(va) >> log2_page_size_large) & \ - (_HV_L1_ENTRIES(log2_page_size_large) - 1)) - -#else /* CHIP_VA_WIDTH() > 32 */ - -/** Index in L1 for a specific VA */ -#define _HV_L1_INDEX(va, log2_page_size_large) \ - (((HV_VirtAddr)(va) >> log2_page_size_large)) - -#endif /* CHIP_VA_WIDTH() > 32 */ - -/** Index in level-2 page table for a specific VA */ -#define _HV_L2_INDEX(va, log2_page_size_large, log2_page_size_small) \ - (((HV_VirtAddr)(va) >> log2_page_size_small) & \ - (_HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) - 1)) - -#endif /* __ASSEMBLER __ */ - -/** Position of the PFN field within the PTE (subset of the PTFN). */ -#define _HV_PTE_INDEX_PFN(log2_page_size) \ - (HV_PTE_INDEX_PTFN + (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN)) - -/** Length of the PFN field within the PTE (subset of the PTFN). */ -#define _HV_PTE_INDEX_PFN_BITS(log2_page_size) \ - (HV_PTE_INDEX_PTFN_BITS - (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN)) - -/** Converts a client physical address to a pfn. */ -#define _HV_CPA_TO_PFN(p, log2_page_size) ((p) >> log2_page_size) - -/** Converts a pfn to a client physical address. */ -#define _HV_PFN_TO_CPA(p, log2_page_size) \ - (((HV_PhysAddr)(p)) << log2_page_size) - -/** Converts a ptfn to a pfn. */ -#define _HV_PTFN_TO_PFN(p, log2_page_size) \ - ((p) >> (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN)) - -/** Converts a pfn to a ptfn. */ -#define _HV_PFN_TO_PTFN(p, log2_page_size) \ - ((p) << (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN)) - -#endif /* _HV_HV_H */ diff --git a/arch/tile/include/hv/iorpc.h b/arch/tile/include/hv/iorpc.h deleted file mode 100644 index ddf1604482b3..000000000000 --- a/arch/tile/include/hv/iorpc.h +++ /dev/null @@ -1,714 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ -#ifndef _HV_IORPC_H_ -#define _HV_IORPC_H_ - -/** - * - * Error codes and struct definitions for the IO RPC library. - * - * The hypervisor's IO RPC component provides a convenient way for - * driver authors to proxy system calls between user space, linux, and - * the hypervisor driver. The core of the system is a set of Python - * files that take ".idl" files as input and generates the following - * source code: - * - * - _rpc_call() routines for use in userspace IO libraries. These - * routines take an argument list specified in the .idl file, pack the - * arguments in to a buffer, and read or write that buffer via the - * Linux iorpc driver. - * - * - dispatch_read() and dispatch_write() routines that hypervisor - * drivers can use to implement most of their dev_pread() and - * dev_pwrite() methods. These routines decode the incoming parameter - * blob, permission check and translate parameters where appropriate, - * and then invoke a callback routine for whichever RPC call has - * arrived. The driver simply implements the set of callback - * routines. - * - * The IO RPC system also includes the Linux 'iorpc' driver, which - * proxies calls between the userspace library and the hypervisor - * driver. The Linux driver is almost entirely device agnostic; it - * watches for special flags indicating cases where a memory buffer - * address might need to be translated, etc. As a result, driver - * writers can avoid many of the problem cases related to registering - * hardware resources like memory pages or interrupts. However, the - * drivers must be careful to obey the conventions documented below in - * order to work properly with the generic Linux iorpc driver. - * - * @section iorpc_domains Service Domains - * - * All iorpc-based drivers must support a notion of service domains. - * A service domain is basically an application context - state - * indicating resources that are allocated to that particular app - * which it may access and (perhaps) other applications may not - * access. Drivers can support any number of service domains they - * choose. In some cases the design is limited by a number of service - * domains supported by the IO hardware; in other cases the service - * domains are a purely software concept and the driver chooses a - * maximum number of domains based on how much state memory it is - * willing to preallocate. - * - * For example, the mPIPE driver only supports as many service domains - * as are supported by the mPIPE hardware. This limitation is - * required because the hardware implements its own MMIO protection - * scheme to allow large MMIO mappings while still protecting small - * register ranges within the page that should only be accessed by the - * hypervisor. - * - * In contrast, drivers with no hardware service domain limitations - * (for instance the TRIO shim) can implement an arbitrary number of - * service domains. In these cases, each service domain is limited to - * a carefully restricted set of legal MMIO addresses if necessary to - * keep one application from corrupting another application's state. - * - * @section iorpc_conventions System Call Conventions - * - * The driver's open routine is responsible for allocating a new - * service domain for each hv_dev_open() call. By convention, the - * return value from open() should be the service domain number on - * success, or GXIO_ERR_NO_SVC_DOM if no more service domains are - * available. - * - * The implementations of hv_dev_pread() and hv_dev_pwrite() are - * responsible for validating the devhdl value passed up by the - * client. Since the device handle returned by hv_dev_open() should - * embed the positive service domain number, drivers should make sure - * that DRV_HDL2BITS(devhdl) is a legal service domain. If the client - * passes an illegal service domain number, the routine should return - * GXIO_ERR_INVAL_SVC_DOM. Once the service domain number has been - * validated, the driver can copy to/from the client buffer and call - * the dispatch_read() or dispatch_write() methods created by the RPC - * generator. - * - * The hv_dev_close() implementation should reset all service domain - * state and put the service domain back on a free list for - * reallocation by a future application. In most cases, this will - * require executing a hardware reset or drain flow and denying any - * MMIO regions that were created for the service domain. - * - * @section iorpc_data Special Data Types - * - * The .idl file syntax allows the creation of syscalls with special - * parameters that require permission checks or translations as part - * of the system call path. Because of limitations in the code - * generator, APIs are generally limited to just one of these special - * parameters per system call, and they are sometimes required to be - * the first or last parameter to the call. Special parameters - * include: - * - * @subsection iorpc_mem_buffer MEM_BUFFER - * - * The MEM_BUFFER() datatype allows user space to "register" memory - * buffers with a device. Registering memory accomplishes two tasks: - * Linux keeps track of all buffers that might be modified by a - * hardware device, and the hardware device drivers bind registered - * buffers to particular hardware resources like ingress NotifRings. - * The MEM_BUFFER() idl syntax can take extra flags like ALIGN_64KB, - * ALIGN_SELF_SIZE, and FLAGS indicating that memory buffers must have - * certain alignment or that the user should be able to pass a "memory - * flags" word specifying attributes like nt_hint or IO cache pinning. - * The parser will accept multiple MEM_BUFFER() flags. - * - * Implementations must obey the following conventions when - * registering memory buffers via the iorpc flow. These rules are a - * result of the Linux driver implementation, which needs to keep - * track of how many times a particular page has been registered with - * the hardware so that it can release the page when all those - * registrations are cleared. - * - * - Memory registrations that refer to a resource which has already - * been bound must return GXIO_ERR_ALREADY_INIT. Thus, it is an - * error to register memory twice without resetting (i.e. closing) the - * resource in between. This convention keeps the Linux driver from - * having to track which particular devices a page is bound to. - * - * - At present, a memory registration is only cleared when the - * service domain is reset. In this case, the Linux driver simply - * closes the HV device file handle and then decrements the reference - * counts of all pages that were previously registered with the - * device. - * - * - In the future, we may add a mechanism for unregistering memory. - * One possible implementation would require that the user specify - * which buffer is currently registered. The HV would then verify - * that that page was actually the one currently mapped and return - * success or failure to Linux, which would then only decrement the - * page reference count if the addresses were mapped. Another scheme - * might allow Linux to pass a token to the HV to be returned when the - * resource is unmapped. - * - * @subsection iorpc_interrupt INTERRUPT - * - * The INTERRUPT .idl datatype allows the client to bind hardware - * interrupts to a particular combination of IPI parameters - CPU, IPI - * PL, and event bit number. This data is passed via a special - * datatype so that the Linux driver can validate the CPU and PL and - * the HV generic iorpc code can translate client CPUs to real CPUs. - * - * @subsection iorpc_pollfd_setup POLLFD_SETUP - * - * The POLLFD_SETUP .idl datatype allows the client to set up hardware - * interrupt bindings which are received by Linux but which are made - * visible to user processes as state transitions on a file descriptor; - * this allows user processes to use Linux primitives, such as poll(), to - * await particular hardware events. This data is passed via a special - * datatype so that the Linux driver may recognize the pollable file - * descriptor and translate it to a set of interrupt target information, - * and so that the HV generic iorpc code can translate client CPUs to real - * CPUs. - * - * @subsection iorpc_pollfd POLLFD - * - * The POLLFD .idl datatype allows manipulation of hardware interrupt - * bindings set up via the POLLFD_SETUP datatype; common operations are - * resetting the state of the requested interrupt events, and unbinding any - * bound interrupts. This data is passed via a special datatype so that - * the Linux driver may recognize the pollable file descriptor and - * translate it to an interrupt identifier previously supplied by the - * hypervisor as the result of an earlier pollfd_setup operation. - * - * @subsection iorpc_blob BLOB - * - * The BLOB .idl datatype allows the client to write an arbitrary - * length string of bytes up to the hypervisor driver. This can be - * useful for passing up large, arbitrarily structured data like - * classifier programs. The iorpc stack takes care of validating the - * buffer VA and CPA as the data passes up to the hypervisor. Unlike - * MEM_BUFFER(), the buffer is not registered - Linux does not bump - * page refcounts and the HV driver should not reuse the buffer once - * the system call is complete. - * - * @section iorpc_translation Translating User Space Calls - * - * The ::iorpc_offset structure describes the formatting of the offset - * that is passed to pread() or pwrite() as part of the generated RPC code. - * When the user calls up to Linux, the rpc code fills in all the fields of - * the offset, including a 16-bit opcode, a 16 bit format indicator, and 32 - * bits of user-specified "sub-offset". The opcode indicates which syscall - * is being requested. The format indicates whether there is a "prefix - * struct" at the start of the memory buffer passed to pwrite(), and if so - * what data is in that prefix struct. These prefix structs are used to - * implement special datatypes like MEM_BUFFER() and INTERRUPT - we arrange - * to put data that needs translation and permission checks at the start of - * the buffer so that the Linux driver and generic portions of the HV iorpc - * code can easily access the data. The 32 bits of user-specified - * "sub-offset" are most useful for pread() calls where the user needs to - * also pass in a few bits indicating which register to read, etc. - * - * The Linux iorpc driver watches for system calls that contain prefix - * structs so that it can translate parameters and bump reference - * counts as appropriate. It does not (currently) have any knowledge - * of the per-device opcodes - it doesn't care what operation you're - * doing to mPIPE, so long as it can do all the generic book-keeping. - * The hv/iorpc.h header file defines all of the generic encoding bits - * needed to translate iorpc calls without knowing which particular - * opcode is being issued. - * - * @section iorpc_globals Global iorpc Calls - * - * Implementing mmap() required adding some special iorpc syscalls - * that are only called by the Linux driver, never by userspace. - * These include get_mmio_base() and check_mmio_offset(). These - * routines are described in globals.idl and must be included in every - * iorpc driver. By providing these routines in every driver, Linux's - * mmap implementation can easily get the PTE bits it needs and - * validate the PA offset without needing to know the per-device - * opcodes to perform those tasks. - * - * @section iorpc_kernel Supporting gxio APIs in the Kernel - * - * The iorpc code generator also supports generation of kernel code - * implementing the gxio APIs. This capability is currently used by - * the mPIPE network driver, and will likely be used by the TRIO root - * complex and endpoint drivers and perhaps an in-kernel crypto - * driver. Each driver that wants to instantiate iorpc calls in the - * kernel needs to generate a kernel version of the generate rpc code - * and (probably) copy any related gxio source files into the kernel. - * The mPIPE driver provides a good example of this pattern. - */ - -#ifdef __KERNEL__ -#include -#else -#include -#endif - -#if defined(__HV__) -#include -#elif defined(__KERNEL__) -#include -#include -#else -#include -#endif - - -/** Code indicating translation services required within the RPC path. - * These indicate whether there is a translatable struct at the start - * of the RPC buffer and what information that struct contains. - */ -enum iorpc_format_e -{ - /** No translation required, no prefix struct. */ - IORPC_FORMAT_NONE, - - /** No translation required, no prefix struct, no access to this - * operation from user space. */ - IORPC_FORMAT_NONE_NOUSER, - - /** Prefix struct contains user VA and size. */ - IORPC_FORMAT_USER_MEM, - - /** Prefix struct contains CPA, size, and homing bits. */ - IORPC_FORMAT_KERNEL_MEM, - - /** Prefix struct contains interrupt. */ - IORPC_FORMAT_KERNEL_INTERRUPT, - - /** Prefix struct contains user-level interrupt. */ - IORPC_FORMAT_USER_INTERRUPT, - - /** Prefix struct contains pollfd_setup (interrupt information). */ - IORPC_FORMAT_KERNEL_POLLFD_SETUP, - - /** Prefix struct contains user-level pollfd_setup (file descriptor). */ - IORPC_FORMAT_USER_POLLFD_SETUP, - - /** Prefix struct contains pollfd (interrupt cookie). */ - IORPC_FORMAT_KERNEL_POLLFD, - - /** Prefix struct contains user-level pollfd (file descriptor). */ - IORPC_FORMAT_USER_POLLFD, -}; - - -/** Generate an opcode given format and code. */ -#define IORPC_OPCODE(FORMAT, CODE) (((FORMAT) << 16) | (CODE)) - -/** The offset passed through the read() and write() system calls - combines an opcode with 32 bits of user-specified offset. */ -union iorpc_offset -{ -#ifndef __BIG_ENDIAN__ - uint64_t offset; /**< All bits. */ - - struct - { - uint16_t code; /**< RPC code. */ - uint16_t format; /**< iorpc_format_e */ - uint32_t sub_offset; /**< caller-specified offset. */ - }; - - uint32_t opcode; /**< Opcode combines code & format. */ -#else - uint64_t offset; /**< All bits. */ - - struct - { - uint32_t sub_offset; /**< caller-specified offset. */ - uint16_t format; /**< iorpc_format_e */ - uint16_t code; /**< RPC code. */ - }; - - struct - { - uint32_t padding; - uint32_t opcode; /**< Opcode combines code & format. */ - }; -#endif -}; - - -/** Homing and cache hinting bits that can be used by IO devices. */ -struct iorpc_mem_attr -{ - unsigned int lotar_x:4; /**< lotar X bits (or Gx page_mask). */ - unsigned int lotar_y:4; /**< lotar Y bits (or Gx page_offset). */ - unsigned int hfh:1; /**< Uses hash-for-home. */ - unsigned int nt_hint:1; /**< Non-temporal hint. */ - unsigned int io_pin:1; /**< Only fill 'IO' cache ways. */ -}; - -/** Set the nt_hint bit. */ -#define IORPC_MEM_BUFFER_FLAG_NT_HINT (1 << 0) - -/** Set the IO pin bit. */ -#define IORPC_MEM_BUFFER_FLAG_IO_PIN (1 << 1) - - -/** A structure used to describe memory registration. Different - protection levels describe memory differently, so this union - contains all the different possible descriptions. As a request - moves up the call chain, each layer translates from one - description format to the next. In particular, the Linux iorpc - driver translates user VAs into CPAs and homing parameters. */ -union iorpc_mem_buffer -{ - struct - { - uint64_t va; /**< User virtual address. */ - uint64_t size; /**< Buffer size. */ - unsigned int flags; /**< nt_hint, IO pin. */ - } - user; /**< Buffer as described by user apps. */ - - struct - { - unsigned long long cpa; /**< Client physical address. */ -#if defined(__KERNEL__) || defined(__HV__) - size_t size; /**< Buffer size. */ - HV_PTE pte; /**< PTE describing memory homing. */ -#else - uint64_t size; - uint64_t pte; -#endif - unsigned int flags; /**< nt_hint, IO pin. */ - } - kernel; /**< Buffer as described by kernel. */ - - struct - { - unsigned long long pa; /**< Physical address. */ - size_t size; /**< Buffer size. */ - struct iorpc_mem_attr attr; /**< Homing and locality hint bits. */ - } - hv; /**< Buffer parameters for HV driver. */ -}; - - -/** A structure used to describe interrupts. The format differs slightly - * for user and kernel interrupts. As with the mem_buffer_t, translation - * between the formats is done at each level. */ -union iorpc_interrupt -{ - struct - { - int cpu; /**< CPU. */ - int event; /**< evt_num */ - } - user; /**< Interrupt as described by user applications. */ - - struct - { - int x; /**< X coord. */ - int y; /**< Y coord. */ - int ipi; /**< int_num */ - int event; /**< evt_num */ - } - kernel; /**< Interrupt as described by the kernel. */ - -}; - - -/** A structure used to describe interrupts used with poll(). The format - * differs significantly for requests from user to kernel, and kernel to - * hypervisor. As with the mem_buffer_t, translation between the formats - * is done at each level. */ -union iorpc_pollfd_setup -{ - struct - { - int fd; /**< Pollable file descriptor. */ - } - user; /**< pollfd_setup as described by user applications. */ - - struct - { - int x; /**< X coord. */ - int y; /**< Y coord. */ - int ipi; /**< int_num */ - int event; /**< evt_num */ - } - kernel; /**< pollfd_setup as described by the kernel. */ - -}; - - -/** A structure used to describe previously set up interrupts used with - * poll(). The format differs significantly for requests from user to - * kernel, and kernel to hypervisor. As with the mem_buffer_t, translation - * between the formats is done at each level. */ -union iorpc_pollfd -{ - struct - { - int fd; /**< Pollable file descriptor. */ - } - user; /**< pollfd as described by user applications. */ - - struct - { - int cookie; /**< hv cookie returned by the pollfd_setup operation. */ - } - kernel; /**< pollfd as described by the kernel. */ - -}; - - -/** The various iorpc devices use error codes from -1100 to -1299. - * - * This range is distinct from netio (-700 to -799), the hypervisor - * (-800 to -899), tilepci (-900 to -999), ilib (-1000 to -1099), - * gxcr (-1300 to -1399) and gxpci (-1400 to -1499). - */ -enum gxio_err_e { - - /** Largest iorpc error number. */ - GXIO_ERR_MAX = -1101, - - - /********************************************************/ - /* Generic Error Codes */ - /********************************************************/ - - /** Bad RPC opcode - possible version incompatibility. */ - GXIO_ERR_OPCODE = -1101, - - /** Invalid parameter. */ - GXIO_ERR_INVAL = -1102, - - /** Memory buffer did not meet alignment requirements. */ - GXIO_ERR_ALIGNMENT = -1103, - - /** Memory buffers must be coherent and cacheable. */ - GXIO_ERR_COHERENCE = -1104, - - /** Resource already initialized. */ - GXIO_ERR_ALREADY_INIT = -1105, - - /** No service domains available. */ - GXIO_ERR_NO_SVC_DOM = -1106, - - /** Illegal service domain number. */ - GXIO_ERR_INVAL_SVC_DOM = -1107, - - /** Illegal MMIO address. */ - GXIO_ERR_MMIO_ADDRESS = -1108, - - /** Illegal interrupt binding. */ - GXIO_ERR_INTERRUPT = -1109, - - /** Unreasonable client memory. */ - GXIO_ERR_CLIENT_MEMORY = -1110, - - /** No more IOTLB entries. */ - GXIO_ERR_IOTLB_ENTRY = -1111, - - /** Invalid memory size. */ - GXIO_ERR_INVAL_MEMORY_SIZE = -1112, - - /** Unsupported operation. */ - GXIO_ERR_UNSUPPORTED_OP = -1113, - - /** Insufficient DMA credits. */ - GXIO_ERR_DMA_CREDITS = -1114, - - /** Operation timed out. */ - GXIO_ERR_TIMEOUT = -1115, - - /** No such device or object. */ - GXIO_ERR_NO_DEVICE = -1116, - - /** Device or resource busy. */ - GXIO_ERR_BUSY = -1117, - - /** I/O error. */ - GXIO_ERR_IO = -1118, - - /** Permissions error. */ - GXIO_ERR_PERM = -1119, - - - - /********************************************************/ - /* Test Device Error Codes */ - /********************************************************/ - - /** Illegal register number. */ - GXIO_TEST_ERR_REG_NUMBER = -1120, - - /** Illegal buffer slot. */ - GXIO_TEST_ERR_BUFFER_SLOT = -1121, - - - /********************************************************/ - /* MPIPE Error Codes */ - /********************************************************/ - - - /** Invalid buffer size. */ - GXIO_MPIPE_ERR_INVAL_BUFFER_SIZE = -1131, - - /** Cannot allocate buffer stack. */ - GXIO_MPIPE_ERR_NO_BUFFER_STACK = -1140, - - /** Invalid buffer stack number. */ - GXIO_MPIPE_ERR_BAD_BUFFER_STACK = -1141, - - /** Cannot allocate NotifRing. */ - GXIO_MPIPE_ERR_NO_NOTIF_RING = -1142, - - /** Invalid NotifRing number. */ - GXIO_MPIPE_ERR_BAD_NOTIF_RING = -1143, - - /** Cannot allocate NotifGroup. */ - GXIO_MPIPE_ERR_NO_NOTIF_GROUP = -1144, - - /** Invalid NotifGroup number. */ - GXIO_MPIPE_ERR_BAD_NOTIF_GROUP = -1145, - - /** Cannot allocate bucket. */ - GXIO_MPIPE_ERR_NO_BUCKET = -1146, - - /** Invalid bucket number. */ - GXIO_MPIPE_ERR_BAD_BUCKET = -1147, - - /** Cannot allocate eDMA ring. */ - GXIO_MPIPE_ERR_NO_EDMA_RING = -1148, - - /** Invalid eDMA ring number. */ - GXIO_MPIPE_ERR_BAD_EDMA_RING = -1149, - - /** Invalid channel number. */ - GXIO_MPIPE_ERR_BAD_CHANNEL = -1150, - - /** Bad configuration. */ - GXIO_MPIPE_ERR_BAD_CONFIG = -1151, - - /** Empty iqueue. */ - GXIO_MPIPE_ERR_IQUEUE_EMPTY = -1152, - - /** Empty rules. */ - GXIO_MPIPE_ERR_RULES_EMPTY = -1160, - - /** Full rules. */ - GXIO_MPIPE_ERR_RULES_FULL = -1161, - - /** Corrupt rules. */ - GXIO_MPIPE_ERR_RULES_CORRUPT = -1162, - - /** Invalid rules. */ - GXIO_MPIPE_ERR_RULES_INVALID = -1163, - - /** Classifier is too big. */ - GXIO_MPIPE_ERR_CLASSIFIER_TOO_BIG = -1170, - - /** Classifier is too complex. */ - GXIO_MPIPE_ERR_CLASSIFIER_TOO_COMPLEX = -1171, - - /** Classifier has bad header. */ - GXIO_MPIPE_ERR_CLASSIFIER_BAD_HEADER = -1172, - - /** Classifier has bad contents. */ - GXIO_MPIPE_ERR_CLASSIFIER_BAD_CONTENTS = -1173, - - /** Classifier encountered invalid symbol. */ - GXIO_MPIPE_ERR_CLASSIFIER_INVAL_SYMBOL = -1174, - - /** Classifier encountered invalid bounds. */ - GXIO_MPIPE_ERR_CLASSIFIER_INVAL_BOUNDS = -1175, - - /** Classifier encountered invalid relocation. */ - GXIO_MPIPE_ERR_CLASSIFIER_INVAL_RELOCATION = -1176, - - /** Classifier encountered undefined symbol. */ - GXIO_MPIPE_ERR_CLASSIFIER_UNDEF_SYMBOL = -1177, - - - /********************************************************/ - /* TRIO Error Codes */ - /********************************************************/ - - /** Cannot allocate memory map region. */ - GXIO_TRIO_ERR_NO_MEMORY_MAP = -1180, - - /** Invalid memory map region number. */ - GXIO_TRIO_ERR_BAD_MEMORY_MAP = -1181, - - /** Cannot allocate scatter queue. */ - GXIO_TRIO_ERR_NO_SCATTER_QUEUE = -1182, - - /** Invalid scatter queue number. */ - GXIO_TRIO_ERR_BAD_SCATTER_QUEUE = -1183, - - /** Cannot allocate push DMA ring. */ - GXIO_TRIO_ERR_NO_PUSH_DMA_RING = -1184, - - /** Invalid push DMA ring index. */ - GXIO_TRIO_ERR_BAD_PUSH_DMA_RING = -1185, - - /** Cannot allocate pull DMA ring. */ - GXIO_TRIO_ERR_NO_PULL_DMA_RING = -1186, - - /** Invalid pull DMA ring index. */ - GXIO_TRIO_ERR_BAD_PULL_DMA_RING = -1187, - - /** Cannot allocate PIO region. */ - GXIO_TRIO_ERR_NO_PIO = -1188, - - /** Invalid PIO region index. */ - GXIO_TRIO_ERR_BAD_PIO = -1189, - - /** Cannot allocate ASID. */ - GXIO_TRIO_ERR_NO_ASID = -1190, - - /** Invalid ASID. */ - GXIO_TRIO_ERR_BAD_ASID = -1191, - - - /********************************************************/ - /* MICA Error Codes */ - /********************************************************/ - - /** No such accelerator type. */ - GXIO_MICA_ERR_BAD_ACCEL_TYPE = -1220, - - /** Cannot allocate context. */ - GXIO_MICA_ERR_NO_CONTEXT = -1221, - - /** PKA command queue is full, can't add another command. */ - GXIO_MICA_ERR_PKA_CMD_QUEUE_FULL = -1222, - - /** PKA result queue is empty, can't get a result from the queue. */ - GXIO_MICA_ERR_PKA_RESULT_QUEUE_EMPTY = -1223, - - /********************************************************/ - /* GPIO Error Codes */ - /********************************************************/ - - /** Pin not available. Either the physical pin does not exist, or - * it is reserved by the hypervisor for system usage. */ - GXIO_GPIO_ERR_PIN_UNAVAILABLE = -1240, - - /** Pin busy. The pin exists, and is available for use via GXIO, but - * it has been attached by some other process or driver. */ - GXIO_GPIO_ERR_PIN_BUSY = -1241, - - /** Cannot access unattached pin. One or more of the pins being - * manipulated by this call are not attached to the requesting - * context. */ - GXIO_GPIO_ERR_PIN_UNATTACHED = -1242, - - /** Invalid I/O mode for pin. The wiring of the pin in the system - * is such that the I/O mode or electrical control parameters - * requested could cause damage. */ - GXIO_GPIO_ERR_PIN_INVALID_MODE = -1243, - - /** Smallest iorpc error number. */ - GXIO_ERR_MIN = -1299 -}; - - -#endif /* !_HV_IORPC_H_ */ diff --git a/arch/tile/include/hv/netio_errors.h b/arch/tile/include/hv/netio_errors.h deleted file mode 100644 index e1591bff61b5..000000000000 --- a/arch/tile/include/hv/netio_errors.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * Error codes returned from NetIO routines. - */ - -#ifndef __NETIO_ERRORS_H__ -#define __NETIO_ERRORS_H__ - -/** - * @addtogroup error - * - * @brief The error codes returned by NetIO functions. - * - * NetIO functions return 0 (defined as ::NETIO_NO_ERROR) on success, and - * a negative value if an error occurs. - * - * In cases where a NetIO function failed due to a error reported by - * system libraries, the error code will be the negation of the - * system errno at the time of failure. The @ref netio_strerror() - * function will deliver error strings for both NetIO and system error - * codes. - * - * @{ - */ - -/** The set of all NetIO errors. */ -typedef enum -{ - /** Operation successfully completed. */ - NETIO_NO_ERROR = 0, - - /** A packet was successfully retrieved from an input queue. */ - NETIO_PKT = 0, - - /** Largest NetIO error number. */ - NETIO_ERR_MAX = -701, - - /** The tile is not registered with the IPP. */ - NETIO_NOT_REGISTERED = -701, - - /** No packet was available to retrieve from the input queue. */ - NETIO_NOPKT = -702, - - /** The requested function is not implemented. */ - NETIO_NOT_IMPLEMENTED = -703, - - /** On a registration operation, the target queue already has the maximum - * number of tiles registered for it, and no more may be added. On a - * packet send operation, the output queue is full and nothing more can - * be queued until some of the queued packets are actually transmitted. */ - NETIO_QUEUE_FULL = -704, - - /** The calling process or thread is not bound to exactly one CPU. */ - NETIO_BAD_AFFINITY = -705, - - /** Cannot allocate memory on requested controllers. */ - NETIO_CANNOT_HOME = -706, - - /** On a registration operation, the IPP specified is not configured - * to support the options requested; for instance, the application - * wants a specific type of tagged headers which the configured IPP - * doesn't support. Or, the supplied configuration information is - * not self-consistent, or is out of range; for instance, specifying - * both NETIO_RECV and NETIO_NO_RECV, or asking for more than - * NETIO_MAX_SEND_BUFFERS to be preallocated. On a VLAN or bucket - * configure operation, the number of items, or the base item, was - * out of range. - */ - NETIO_BAD_CONFIG = -707, - - /** Too many tiles have registered to transmit packets. */ - NETIO_TOOMANY_XMIT = -708, - - /** Packet transmission was attempted on a queue which was registered - with transmit disabled. */ - NETIO_UNREG_XMIT = -709, - - /** This tile is already registered with the IPP. */ - NETIO_ALREADY_REGISTERED = -710, - - /** The Ethernet link is down. The application should try again later. */ - NETIO_LINK_DOWN = -711, - - /** An invalid memory buffer has been specified. This may be an unmapped - * virtual address, or one which does not meet alignment requirements. - * For netio_input_register(), this error may be returned when multiple - * processes specify different memory regions to be used for NetIO - * buffers. That can happen if these processes specify explicit memory - * regions with the ::NETIO_FIXED_BUFFER_VA flag, or if tmc_cmem_init() - * has not been called by a common ancestor of the processes. - */ - NETIO_FAULT = -712, - - /** Cannot combine user-managed shared memory and cache coherence. */ - NETIO_BAD_CACHE_CONFIG = -713, - - /** Smallest NetIO error number. */ - NETIO_ERR_MIN = -713, - -#ifndef __DOXYGEN__ - /** Used internally to mean that no response is needed; never returned to - * an application. */ - NETIO_NO_RESPONSE = 1 -#endif -} netio_error_t; - -/** @} */ - -#endif /* __NETIO_ERRORS_H__ */ diff --git a/arch/tile/include/hv/netio_intf.h b/arch/tile/include/hv/netio_intf.h deleted file mode 100644 index 8d20972aba2c..000000000000 --- a/arch/tile/include/hv/netio_intf.h +++ /dev/null @@ -1,2975 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * NetIO interface structures and macros. - */ - -#ifndef __NETIO_INTF_H__ -#define __NETIO_INTF_H__ - -#include - -#ifdef __KERNEL__ -#include -#else -#include -#endif - -#if !defined(__HV__) && !defined(__BOGUX__) && !defined(__KERNEL__) -#include -#define netio_assert assert /**< Enable assertions from macros */ -#else -#define netio_assert(...) ((void)(0)) /**< Disable assertions from macros */ -#endif - -/* - * If none of these symbols are defined, we're building libnetio in an - * environment where we have pthreads, so we'll enable locking. - */ -#if !defined(__HV__) && !defined(__BOGUX__) && !defined(__KERNEL__) && \ - !defined(__NEWLIB__) -#define _NETIO_PTHREAD /**< Include a mutex in netio_queue_t below */ - -/* - * If NETIO_UNLOCKED is defined, we don't do use per-cpu locks on - * per-packet NetIO operations. We still do pthread locking on things - * like netio_input_register, though. This is used for building - * libnetio_unlocked. - */ -#ifndef NETIO_UNLOCKED - -/* Avoid PLT overhead by using our own inlined per-cpu lock. */ -#include -typedef int _netio_percpu_mutex_t; - -static __inline int -_netio_percpu_mutex_init(_netio_percpu_mutex_t* lock) -{ - *lock = 0; - return 0; -} - -static __inline int -_netio_percpu_mutex_lock(_netio_percpu_mutex_t* lock) -{ - while (__builtin_expect(__insn_tns(lock), 0)) - sched_yield(); - return 0; -} - -static __inline int -_netio_percpu_mutex_unlock(_netio_percpu_mutex_t* lock) -{ - *lock = 0; - return 0; -} - -#else /* NETIO_UNLOCKED */ - -/* Don't do any locking for per-packet NetIO operations. */ -typedef int _netio_percpu_mutex_t; -#define _netio_percpu_mutex_init(L) -#define _netio_percpu_mutex_lock(L) -#define _netio_percpu_mutex_unlock(L) - -#endif /* NETIO_UNLOCKED */ -#endif /* !__HV__, !__BOGUX, !__KERNEL__, !__NEWLIB__ */ - -/** How many tiles can register for a given queue. - * @ingroup setup */ -#define NETIO_MAX_TILES_PER_QUEUE 64 - - -/** Largest permissible queue identifier. - * @ingroup setup */ -#define NETIO_MAX_QUEUE_ID 255 - - -#ifndef __DOXYGEN__ - -/* Metadata packet checksum/ethertype flags. */ - -/** The L4 checksum has not been calculated. */ -#define _NETIO_PKT_NO_L4_CSUM_SHIFT 0 -#define _NETIO_PKT_NO_L4_CSUM_RMASK 1 -#define _NETIO_PKT_NO_L4_CSUM_MASK \ - (_NETIO_PKT_NO_L4_CSUM_RMASK << _NETIO_PKT_NO_L4_CSUM_SHIFT) - -/** The L3 checksum has not been calculated. */ -#define _NETIO_PKT_NO_L3_CSUM_SHIFT 1 -#define _NETIO_PKT_NO_L3_CSUM_RMASK 1 -#define _NETIO_PKT_NO_L3_CSUM_MASK \ - (_NETIO_PKT_NO_L3_CSUM_RMASK << _NETIO_PKT_NO_L3_CSUM_SHIFT) - -/** The L3 checksum is incorrect (or perhaps has not been calculated). */ -#define _NETIO_PKT_BAD_L3_CSUM_SHIFT 2 -#define _NETIO_PKT_BAD_L3_CSUM_RMASK 1 -#define _NETIO_PKT_BAD_L3_CSUM_MASK \ - (_NETIO_PKT_BAD_L3_CSUM_RMASK << _NETIO_PKT_BAD_L3_CSUM_SHIFT) - -/** The Ethernet packet type is unrecognized. */ -#define _NETIO_PKT_TYPE_UNRECOGNIZED_SHIFT 3 -#define _NETIO_PKT_TYPE_UNRECOGNIZED_RMASK 1 -#define _NETIO_PKT_TYPE_UNRECOGNIZED_MASK \ - (_NETIO_PKT_TYPE_UNRECOGNIZED_RMASK << \ - _NETIO_PKT_TYPE_UNRECOGNIZED_SHIFT) - -/* Metadata packet type flags. */ - -/** Where the packet type bits are; this field is the index into - * _netio_pkt_info. */ -#define _NETIO_PKT_TYPE_SHIFT 4 -#define _NETIO_PKT_TYPE_RMASK 0x3F - -/** How many VLAN tags the packet has, and, if we have two, which one we - * actually grouped on. A VLAN within a proprietary (Marvell or Broadcom) - * tag is counted here. */ -#define _NETIO_PKT_VLAN_SHIFT 4 -#define _NETIO_PKT_VLAN_RMASK 0x3 -#define _NETIO_PKT_VLAN_MASK \ - (_NETIO_PKT_VLAN_RMASK << _NETIO_PKT_VLAN_SHIFT) -#define _NETIO_PKT_VLAN_NONE 0 /* No VLAN tag. */ -#define _NETIO_PKT_VLAN_ONE 1 /* One VLAN tag. */ -#define _NETIO_PKT_VLAN_TWO_OUTER 2 /* Two VLAN tags, outer one used. */ -#define _NETIO_PKT_VLAN_TWO_INNER 3 /* Two VLAN tags, inner one used. */ - -/** Which proprietary tags the packet has. */ -#define _NETIO_PKT_TAG_SHIFT 6 -#define _NETIO_PKT_TAG_RMASK 0x3 -#define _NETIO_PKT_TAG_MASK \ - (_NETIO_PKT_TAG_RMASK << _NETIO_PKT_TAG_SHIFT) -#define _NETIO_PKT_TAG_NONE 0 /* No proprietary tags. */ -#define _NETIO_PKT_TAG_MRVL 1 /* Marvell HyperG.Stack tags. */ -#define _NETIO_PKT_TAG_MRVL_EXT 2 /* HyperG.Stack extended tags. */ -#define _NETIO_PKT_TAG_BRCM 3 /* Broadcom HiGig tags. */ - -/** Whether a packet has an LLC + SNAP header. */ -#define _NETIO_PKT_SNAP_SHIFT 8 -#define _NETIO_PKT_SNAP_RMASK 0x1 -#define _NETIO_PKT_SNAP_MASK \ - (_NETIO_PKT_SNAP_RMASK << _NETIO_PKT_SNAP_SHIFT) - -/* NOTE: Bits 9 and 10 are unused. */ - -/** Length of any custom data before the L2 header, in words. */ -#define _NETIO_PKT_CUSTOM_LEN_SHIFT 11 -#define _NETIO_PKT_CUSTOM_LEN_RMASK 0x1F -#define _NETIO_PKT_CUSTOM_LEN_MASK \ - (_NETIO_PKT_CUSTOM_LEN_RMASK << _NETIO_PKT_CUSTOM_LEN_SHIFT) - -/** The L4 checksum is incorrect (or perhaps has not been calculated). */ -#define _NETIO_PKT_BAD_L4_CSUM_SHIFT 16 -#define _NETIO_PKT_BAD_L4_CSUM_RMASK 0x1 -#define _NETIO_PKT_BAD_L4_CSUM_MASK \ - (_NETIO_PKT_BAD_L4_CSUM_RMASK << _NETIO_PKT_BAD_L4_CSUM_SHIFT) - -/** Length of the L2 header, in words. */ -#define _NETIO_PKT_L2_LEN_SHIFT 17 -#define _NETIO_PKT_L2_LEN_RMASK 0x1F -#define _NETIO_PKT_L2_LEN_MASK \ - (_NETIO_PKT_L2_LEN_RMASK << _NETIO_PKT_L2_LEN_SHIFT) - - -/* Flags in minimal packet metadata. */ - -/** We need an eDMA checksum on this packet. */ -#define _NETIO_PKT_NEED_EDMA_CSUM_SHIFT 0 -#define _NETIO_PKT_NEED_EDMA_CSUM_RMASK 1 -#define _NETIO_PKT_NEED_EDMA_CSUM_MASK \ - (_NETIO_PKT_NEED_EDMA_CSUM_RMASK << _NETIO_PKT_NEED_EDMA_CSUM_SHIFT) - -/* Data within the packet information table. */ - -/* Note that, for efficiency, code which uses these fields assumes that none - * of the shift values below are zero. See uses below for an explanation. */ - -/** Offset within the L2 header of the innermost ethertype (in halfwords). */ -#define _NETIO_PKT_INFO_ETYPE_SHIFT 6 -#define _NETIO_PKT_INFO_ETYPE_RMASK 0x1F - -/** Offset within the L2 header of the VLAN tag (in halfwords). */ -#define _NETIO_PKT_INFO_VLAN_SHIFT 11 -#define _NETIO_PKT_INFO_VLAN_RMASK 0x1F - -#endif - - -/** The size of a memory buffer representing a small packet. - * @ingroup egress */ -#define SMALL_PACKET_SIZE 256 - -/** The size of a memory buffer representing a large packet. - * @ingroup egress */ -#define LARGE_PACKET_SIZE 2048 - -/** The size of a memory buffer representing a jumbo packet. - * @ingroup egress */ -#define JUMBO_PACKET_SIZE (12 * 1024) - - -/* Common ethertypes. - * @ingroup ingress */ -/** @{ */ -/** The ethertype of IPv4. */ -#define ETHERTYPE_IPv4 (0x0800) -/** The ethertype of ARP. */ -#define ETHERTYPE_ARP (0x0806) -/** The ethertype of VLANs. */ -#define ETHERTYPE_VLAN (0x8100) -/** The ethertype of a Q-in-Q header. */ -#define ETHERTYPE_Q_IN_Q (0x9100) -/** The ethertype of IPv6. */ -#define ETHERTYPE_IPv6 (0x86DD) -/** The ethertype of MPLS. */ -#define ETHERTYPE_MPLS (0x8847) -/** @} */ - - -/** The possible return values of NETIO_PKT_STATUS. - * @ingroup ingress - */ -typedef enum -{ - /** No problems were detected with this packet. */ - NETIO_PKT_STATUS_OK, - /** The packet is undersized; this is expected behavior if the packet's - * ethertype is unrecognized, but otherwise the packet is likely corrupt. */ - NETIO_PKT_STATUS_UNDERSIZE, - /** The packet is oversized and some trailing bytes have been discarded. - This is expected behavior for short packets, since it's impossible to - precisely determine the amount of padding which may have been added to - them to make them meet the minimum Ethernet packet size. */ - NETIO_PKT_STATUS_OVERSIZE, - /** The packet was judged to be corrupt by hardware (for instance, it had - a bad CRC, or part of it was discarded due to lack of buffer space in - the I/O shim) and should be discarded. */ - NETIO_PKT_STATUS_BAD -} netio_pkt_status_t; - - -/** Log2 of how many buckets we have. */ -#define NETIO_LOG2_NUM_BUCKETS (10) - -/** How many buckets we have. - * @ingroup ingress */ -#define NETIO_NUM_BUCKETS (1 << NETIO_LOG2_NUM_BUCKETS) - - -/** - * @brief A group-to-bucket identifier. - * - * @ingroup setup - * - * This tells us what to do with a given group. - */ -typedef union { - /** The header broken down into bits. */ - struct { - /** Whether we should balance on L4, if available */ - unsigned int __balance_on_l4:1; - /** Whether we should balance on L3, if available */ - unsigned int __balance_on_l3:1; - /** Whether we should balance on L2, if available */ - unsigned int __balance_on_l2:1; - /** Reserved for future use */ - unsigned int __reserved:1; - /** The base bucket to use to send traffic */ - unsigned int __bucket_base:NETIO_LOG2_NUM_BUCKETS; - /** The mask to apply to the balancing value. This must be one less - * than a power of two, e.g. 0x3 or 0xFF. - */ - unsigned int __bucket_mask:NETIO_LOG2_NUM_BUCKETS; - /** Pad to 32 bits */ - unsigned int __padding:(32 - 4 - 2 * NETIO_LOG2_NUM_BUCKETS); - } bits; - /** To send out the IDN. */ - unsigned int word; -} -netio_group_t; - - -/** - * @brief A VLAN-to-bucket identifier. - * - * @ingroup setup - * - * This tells us what to do with a given VLAN. - */ -typedef netio_group_t netio_vlan_t; - - -/** - * A bucket-to-queue mapping. - * @ingroup setup - */ -typedef unsigned char netio_bucket_t; - - -/** - * A packet size can always fit in a netio_size_t. - * @ingroup setup - */ -typedef unsigned int netio_size_t; - - -/** - * @brief Ethernet standard (ingress) packet metadata. - * - * @ingroup ingress - * - * This is additional data associated with each packet. - * This structure is opaque and accessed through the @ref ingress. - * - * Also, the buffer population operation currently assumes that standard - * metadata is at least as large as minimal metadata, and will need to be - * modified if that is no longer the case. - */ -typedef struct -{ -#ifdef __DOXYGEN__ - /** This structure is opaque. */ - unsigned char opaque[24]; -#else - /** The overall ordinal of the packet */ - unsigned int __packet_ordinal; - /** The ordinal of the packet within the group */ - unsigned int __group_ordinal; - /** The best flow hash IPP could compute. */ - unsigned int __flow_hash; - /** Flags pertaining to checksum calculation, packet type, etc. */ - unsigned int __flags; - /** The first word of "user data". */ - unsigned int __user_data_0; - /** The second word of "user data". */ - unsigned int __user_data_1; -#endif -} -netio_pkt_metadata_t; - - -/** To ensure that the L3 header is aligned mod 4, the L2 header should be - * aligned mod 4 plus 2, since every supported L2 header is 4n + 2 bytes - * long. The standard way to do this is to simply add 2 bytes of padding - * before the L2 header. - */ -#define NETIO_PACKET_PADDING 2 - - - -/** - * @brief Ethernet minimal (egress) packet metadata. - * - * @ingroup egress - * - * This structure represents information about packets which have - * been processed by @ref netio_populate_buffer() or - * @ref netio_populate_prepend_buffer(). This structure is opaque - * and accessed through the @ref egress. - * - * @internal This structure is actually copied into the memory used by - * standard metadata, which is assumed to be large enough. - */ -typedef struct -{ -#ifdef __DOXYGEN__ - /** This structure is opaque. */ - unsigned char opaque[14]; -#else - /** The offset of the L2 header from the start of the packet data. */ - unsigned short l2_offset; - /** The offset of the L3 header from the start of the packet data. */ - unsigned short l3_offset; - /** Where to write the checksum. */ - unsigned char csum_location; - /** Where to start checksumming from. */ - unsigned char csum_start; - /** Flags pertaining to checksum calculation etc. */ - unsigned short flags; - /** The L2 length of the packet. */ - unsigned short l2_length; - /** The checksum with which to seed the checksum generator. */ - unsigned short csum_seed; - /** How much to checksum. */ - unsigned short csum_length; -#endif -} -netio_pkt_minimal_metadata_t; - - -#ifndef __DOXYGEN__ - -/** - * @brief An I/O notification header. - * - * This is the first word of data received from an I/O shim in a notification - * packet. It contains framing and status information. - */ -typedef union -{ - unsigned int word; /**< The whole word. */ - /** The various fields. */ - struct - { - unsigned int __channel:7; /**< Resource channel. */ - unsigned int __type:4; /**< Type. */ - unsigned int __ack:1; /**< Whether an acknowledgement is needed. */ - unsigned int __reserved:1; /**< Reserved. */ - unsigned int __protocol:1; /**< A protocol-specific word is added. */ - unsigned int __status:2; /**< Status of the transfer. */ - unsigned int __framing:2; /**< Framing of the transfer. */ - unsigned int __transfer_size:14; /**< Transfer size in bytes (total). */ - } bits; -} -__netio_pkt_notif_t; - - -/** - * Returns the base address of the packet. - */ -#define _NETIO_PKT_HANDLE_BASE(p) \ - ((unsigned char*)((p).word & 0xFFFFFFC0)) - -/** - * Returns the base address of the packet. - */ -#define _NETIO_PKT_BASE(p) \ - _NETIO_PKT_HANDLE_BASE(p->__packet) - -/** - * @brief An I/O notification packet (second word) - * - * This is the second word of data received from an I/O shim in a notification - * packet. This is the virtual address of the packet buffer, plus some flag - * bits. (The virtual address of the packet is always 256-byte aligned so we - * have room for 8 bits' worth of flags in the low 8 bits.) - * - * @internal - * NOTE: The low two bits must contain "__queue", so the "packet size" - * (SIZE_SMALL, SIZE_LARGE, or SIZE_JUMBO) can be determined quickly. - * - * If __addr or __offset are moved, _NETIO_PKT_BASE - * (defined right below this) must be changed. - */ -typedef union -{ - unsigned int word; /**< The whole word. */ - /** The various fields. */ - struct - { - /** Which queue the packet will be returned to once it is sent back to - the IPP. This is one of the SIZE_xxx values. */ - unsigned int __queue:2; - - /** The IPP handle of the sending IPP. */ - unsigned int __ipp_handle:2; - - /** Reserved for future use. */ - unsigned int __reserved:1; - - /** If 1, this packet has minimal (egress) metadata; otherwise, it - has standard (ingress) metadata. */ - unsigned int __minimal:1; - - /** Offset of the metadata within the packet. This value is multiplied - * by 64 and added to the base packet address to get the metadata - * address. Note that this field is aligned within the word such that - * you can easily extract the metadata address with a 26-bit mask. */ - unsigned int __offset:2; - - /** The top 24 bits of the packet's virtual address. */ - unsigned int __addr:24; - } bits; -} -__netio_pkt_handle_t; - -#endif /* !__DOXYGEN__ */ - - -/** - * @brief A handle for an I/O packet's storage. - * @ingroup ingress - * - * netio_pkt_handle_t encodes the concept of a ::netio_pkt_t with its - * packet metadata removed. It is a much smaller type that exists to - * facilitate applications where the full ::netio_pkt_t type is too - * large, such as those that cache enormous numbers of packets or wish - * to transmit packet descriptors over the UDN. - * - * Because there is no metadata, most ::netio_pkt_t operations cannot be - * performed on a netio_pkt_handle_t. It supports only - * netio_free_handle() (to free the buffer) and - * NETIO_PKT_CUSTOM_DATA_H() (to access a pointer to its contents). - * The application must acquire any additional metadata it wants from the - * original ::netio_pkt_t and record it separately. - * - * A netio_pkt_handle_t can be extracted from a ::netio_pkt_t by calling - * NETIO_PKT_HANDLE(). An invalid handle (analogous to NULL) can be - * created by assigning the value ::NETIO_PKT_HANDLE_NONE. A handle can - * be tested for validity with NETIO_PKT_HANDLE_IS_VALID(). - */ -typedef struct -{ - unsigned int word; /**< Opaque bits. */ -} netio_pkt_handle_t; - -/** - * @brief A packet descriptor. - * - * @ingroup ingress - * @ingroup egress - * - * This data structure represents a packet. The structure is manipulated - * through the @ref ingress and the @ref egress. - * - * While the contents of a netio_pkt_t are opaque, the structure itself is - * portable. This means that it may be shared between all tiles which have - * done a netio_input_register() call for the interface on which the pkt_t - * was initially received (via netio_get_packet()) or retrieved (via - * netio_get_buffer()). The contents of a netio_pkt_t can be transmitted to - * another tile via shared memory, or via a UDN message, or by other means. - * The destination tile may then use the pkt_t as if it had originally been - * received locally; it may read or write the packet's data, read its - * metadata, free the packet, send the packet, transfer the netio_pkt_t to - * yet another tile, and so forth. - * - * Once a netio_pkt_t has been transferred to a second tile, the first tile - * should not reference the original copy; in particular, if more than one - * tile frees or sends the same netio_pkt_t, the IPP's packet free lists will - * become corrupted. Note also that each tile which reads or modifies - * packet data must obey the memory coherency rules outlined in @ref input. - */ -typedef struct -{ -#ifdef __DOXYGEN__ - /** This structure is opaque. */ - unsigned char opaque[32]; -#else - /** For an ingress packet (one with standard metadata), this is the - * notification header we got from the I/O shim. For an egress packet - * (one with minimal metadata), this word is zero if the packet has not - * been populated, and nonzero if it has. */ - __netio_pkt_notif_t __notif_header; - - /** Virtual address of the packet buffer, plus state flags. */ - __netio_pkt_handle_t __packet; - - /** Metadata associated with the packet. */ - netio_pkt_metadata_t __metadata; -#endif -} -netio_pkt_t; - - -#ifndef __DOXYGEN__ - -#define __NETIO_PKT_NOTIF_HEADER(pkt) ((pkt)->__notif_header) -#define __NETIO_PKT_IPP_HANDLE(pkt) ((pkt)->__packet.bits.__ipp_handle) -#define __NETIO_PKT_QUEUE(pkt) ((pkt)->__packet.bits.__queue) -#define __NETIO_PKT_NOTIF_HEADER_M(mda, pkt) ((pkt)->__notif_header) -#define __NETIO_PKT_IPP_HANDLE_M(mda, pkt) ((pkt)->__packet.bits.__ipp_handle) -#define __NETIO_PKT_MINIMAL(pkt) ((pkt)->__packet.bits.__minimal) -#define __NETIO_PKT_QUEUE_M(mda, pkt) ((pkt)->__packet.bits.__queue) -#define __NETIO_PKT_FLAGS_M(mda, pkt) ((mda)->__flags) - -/* Packet information table, used by the attribute access functions below. */ -extern const uint16_t _netio_pkt_info[]; - -#endif /* __DOXYGEN__ */ - - -#ifndef __DOXYGEN__ -/* These macros are deprecated and will disappear in a future MDE release. */ -#define NETIO_PKT_GOOD_CHECKSUM(pkt) \ - NETIO_PKT_L4_CSUM_CORRECT(pkt) -#define NETIO_PKT_GOOD_CHECKSUM_M(mda, pkt) \ - NETIO_PKT_L4_CSUM_CORRECT_M(mda, pkt) -#endif /* __DOXYGEN__ */ - - -/* Packet attribute access functions. */ - -/** Return a pointer to the metadata for a packet. - * @ingroup ingress - * - * Calling this function once and passing the result to other retrieval - * functions with a "_M" suffix usually improves performance. This - * function must be called on an 'ingress' packet (i.e. one retrieved - * by @ref netio_get_packet(), on which @ref netio_populate_buffer() or - * @ref netio_populate_prepend_buffer have not been called). Use of this - * function on an 'egress' packet will cause an assertion failure. - * - * @param[in] pkt Packet on which to operate. - * @return A pointer to the packet's standard metadata. - */ -static __inline netio_pkt_metadata_t* -NETIO_PKT_METADATA(netio_pkt_t* pkt) -{ - netio_assert(!pkt->__packet.bits.__minimal); - return &pkt->__metadata; -} - - -/** Return a pointer to the minimal metadata for a packet. - * @ingroup egress - * - * Calling this function once and passing the result to other retrieval - * functions with a "_MM" suffix usually improves performance. This - * function must be called on an 'egress' packet (i.e. one on which - * @ref netio_populate_buffer() or @ref netio_populate_prepend_buffer() - * have been called, or one retrieved by @ref netio_get_buffer()). Use of - * this function on an 'ingress' packet will cause an assertion failure. - * - * @param[in] pkt Packet on which to operate. - * @return A pointer to the packet's standard metadata. - */ -static __inline netio_pkt_minimal_metadata_t* -NETIO_PKT_MINIMAL_METADATA(netio_pkt_t* pkt) -{ - netio_assert(pkt->__packet.bits.__minimal); - return (netio_pkt_minimal_metadata_t*) &pkt->__metadata; -} - - -/** Determine whether a packet has 'minimal' metadata. - * @ingroup pktfuncs - * - * This function will return nonzero if the packet is an 'egress' - * packet (i.e. one on which @ref netio_populate_buffer() or - * @ref netio_populate_prepend_buffer() have been called, or one - * retrieved by @ref netio_get_buffer()), and zero if the packet - * is an 'ingress' packet (i.e. one retrieved by @ref netio_get_packet(), - * which has not been converted into an 'egress' packet). - * - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the packet has minimal metadata. - */ -static __inline unsigned int -NETIO_PKT_IS_MINIMAL(netio_pkt_t* pkt) -{ - return pkt->__packet.bits.__minimal; -} - - -/** Return a handle for a packet's storage. - * @ingroup pktfuncs - * - * @param[in] pkt Packet on which to operate. - * @return A handle for the packet's storage. - */ -static __inline netio_pkt_handle_t -NETIO_PKT_HANDLE(netio_pkt_t* pkt) -{ - netio_pkt_handle_t h; - h.word = pkt->__packet.word; - return h; -} - - -/** A special reserved value indicating the absence of a packet handle. - * - * @ingroup pktfuncs - */ -#define NETIO_PKT_HANDLE_NONE ((netio_pkt_handle_t) { 0 }) - - -/** Test whether a packet handle is valid. - * - * Applications may wish to use the reserved value NETIO_PKT_HANDLE_NONE - * to indicate no packet at all. This function tests to see if a packet - * handle is a real handle, not this special reserved value. - * - * @ingroup pktfuncs - * - * @param[in] handle Handle on which to operate. - * @return One if the packet handle is valid, else zero. - */ -static __inline unsigned int -NETIO_PKT_HANDLE_IS_VALID(netio_pkt_handle_t handle) -{ - return handle.word != 0; -} - - - -/** Return a pointer to the start of the packet's custom header. - * A custom header may or may not be present, depending upon the IPP; its - * contents and alignment are also IPP-dependent. Currently, none of the - * standard IPPs supplied by Tilera produce a custom header. If present, - * the custom header precedes the L2 header in the packet buffer. - * @ingroup ingress - * - * @param[in] handle Handle on which to operate. - * @return A pointer to start of the packet. - */ -static __inline unsigned char* -NETIO_PKT_CUSTOM_DATA_H(netio_pkt_handle_t handle) -{ - return _NETIO_PKT_HANDLE_BASE(handle) + NETIO_PACKET_PADDING; -} - - -/** Return the length of the packet's custom header. - * A custom header may or may not be present, depending upon the IPP; its - * contents and alignment are also IPP-dependent. Currently, none of the - * standard IPPs supplied by Tilera produce a custom header. If present, - * the custom header precedes the L2 header in the packet buffer. - * - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The length of the packet's custom header, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_CUSTOM_HEADER_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - /* - * Note that we effectively need to extract a quantity from the flags word - * which is measured in words, and then turn it into bytes by shifting - * it left by 2. We do this all at once by just shifting right two less - * bits, and shifting the mask up two bits. - */ - return ((mda->__flags >> (_NETIO_PKT_CUSTOM_LEN_SHIFT - 2)) & - (_NETIO_PKT_CUSTOM_LEN_RMASK << 2)); -} - - -/** Return the length of the packet, starting with the custom header. - * A custom header may or may not be present, depending upon the IPP; its - * contents and alignment are also IPP-dependent. Currently, none of the - * standard IPPs supplied by Tilera produce a custom header. If present, - * the custom header precedes the L2 header in the packet buffer. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The length of the packet, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_CUSTOM_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return (__NETIO_PKT_NOTIF_HEADER(pkt).bits.__transfer_size - - NETIO_PACKET_PADDING); -} - - -/** Return a pointer to the start of the packet's custom header. - * A custom header may or may not be present, depending upon the IPP; its - * contents and alignment are also IPP-dependent. Currently, none of the - * standard IPPs supplied by Tilera produce a custom header. If present, - * the custom header precedes the L2 header in the packet buffer. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return A pointer to start of the packet. - */ -static __inline unsigned char* -NETIO_PKT_CUSTOM_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return NETIO_PKT_CUSTOM_DATA_H(NETIO_PKT_HANDLE(pkt)); -} - - -/** Return the length of the packet's L2 (Ethernet plus VLAN or SNAP) header. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The length of the packet's L2 header, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_L2_HEADER_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - /* - * Note that we effectively need to extract a quantity from the flags word - * which is measured in words, and then turn it into bytes by shifting - * it left by 2. We do this all at once by just shifting right two less - * bits, and shifting the mask up two bits. We then add two bytes. - */ - return ((mda->__flags >> (_NETIO_PKT_L2_LEN_SHIFT - 2)) & - (_NETIO_PKT_L2_LEN_RMASK << 2)) + 2; -} - - -/** Return the length of the packet, starting with the L2 (Ethernet) header. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The length of the packet, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_L2_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return (NETIO_PKT_CUSTOM_LENGTH_M(mda, pkt) - - NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda,pkt)); -} - - -/** Return a pointer to the start of the packet's L2 (Ethernet) header. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return A pointer to start of the packet. - */ -static __inline unsigned char* -NETIO_PKT_L2_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return (NETIO_PKT_CUSTOM_DATA_M(mda, pkt) + - NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt)); -} - - -/** Retrieve the length of the packet, starting with the L3 (generally, - * the IP) header. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return Length of the packet's L3 header and data, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_L3_LENGTH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return (NETIO_PKT_L2_LENGTH_M(mda, pkt) - - NETIO_PKT_L2_HEADER_LENGTH_M(mda,pkt)); -} - - -/** Return a pointer to the packet's L3 (generally, the IP) header. - * @ingroup ingress - * - * Note that we guarantee word alignment of the L3 header. - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return A pointer to the packet's L3 header. - */ -static __inline unsigned char* -NETIO_PKT_L3_DATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return (NETIO_PKT_L2_DATA_M(mda, pkt) + - NETIO_PKT_L2_HEADER_LENGTH_M(mda, pkt)); -} - - -/** Return the ordinal of the packet. - * @ingroup ingress - * - * Each packet is given an ordinal number when it is delivered by the IPP. - * In the medium term, the ordinal is unique and monotonically increasing, - * being incremented by 1 for each packet; the ordinal of the first packet - * delivered after the IPP starts is zero. (Since the ordinal is of finite - * size, given enough input packets, it will eventually wrap around to zero; - * in the long term, therefore, ordinals are not unique.) The ordinals - * handed out by different IPPs are not disjoint, so two packets from - * different IPPs may have identical ordinals. Packets dropped by the - * IPP or by the I/O shim are not assigned ordinals. - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The packet's per-IPP packet ordinal. - */ -static __inline unsigned int -NETIO_PKT_ORDINAL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return mda->__packet_ordinal; -} - - -/** Return the per-group ordinal of the packet. - * @ingroup ingress - * - * Each packet is given a per-group ordinal number when it is - * delivered by the IPP. By default, the group is the packet's VLAN, - * although IPP can be recompiled to use different values. In - * the medium term, the ordinal is unique and monotonically - * increasing, being incremented by 1 for each packet; the ordinal of - * the first packet distributed to a particular group is zero. - * (Since the ordinal is of finite size, given enough input packets, - * it will eventually wrap around to zero; in the long term, - * therefore, ordinals are not unique.) The ordinals handed out by - * different IPPs are not disjoint, so two packets from different IPPs - * may have identical ordinals; similarly, packets distributed to - * different groups may have identical ordinals. Packets dropped by - * the IPP or by the I/O shim are not assigned ordinals. - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The packet's per-IPP, per-group ordinal. - */ -static __inline unsigned int -NETIO_PKT_GROUP_ORDINAL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return mda->__group_ordinal; -} - - -/** Return the VLAN ID assigned to the packet. - * @ingroup ingress - * - * This value is usually contained within the packet header. - * - * This value will be zero if the packet does not have a VLAN tag, or if - * this value was not extracted from the packet. - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The packet's VLAN ID. - */ -static __inline unsigned short -NETIO_PKT_VLAN_ID_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - int vl = (mda->__flags >> _NETIO_PKT_VLAN_SHIFT) & _NETIO_PKT_VLAN_RMASK; - unsigned short* pkt_p; - int index; - unsigned short val; - - if (vl == _NETIO_PKT_VLAN_NONE) - return 0; - - pkt_p = (unsigned short*) NETIO_PKT_L2_DATA_M(mda, pkt); - index = (mda->__flags >> _NETIO_PKT_TYPE_SHIFT) & _NETIO_PKT_TYPE_RMASK; - - val = pkt_p[(_netio_pkt_info[index] >> _NETIO_PKT_INFO_VLAN_SHIFT) & - _NETIO_PKT_INFO_VLAN_RMASK]; - -#ifdef __TILECC__ - return (__insn_bytex(val) >> 16) & 0xFFF; -#else - return (__builtin_bswap32(val) >> 16) & 0xFFF; -#endif -} - - -/** Return the ethertype of the packet. - * @ingroup ingress - * - * This value is usually contained within the packet header. - * - * This value is reliable if @ref NETIO_PKT_ETHERTYPE_RECOGNIZED_M() - * returns true, and otherwise, may not be well defined. - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The packet's ethertype. - */ -static __inline unsigned short -NETIO_PKT_ETHERTYPE_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - unsigned short* pkt_p = (unsigned short*) NETIO_PKT_L2_DATA_M(mda, pkt); - int index = (mda->__flags >> _NETIO_PKT_TYPE_SHIFT) & _NETIO_PKT_TYPE_RMASK; - - unsigned short val = - pkt_p[(_netio_pkt_info[index] >> _NETIO_PKT_INFO_ETYPE_SHIFT) & - _NETIO_PKT_INFO_ETYPE_RMASK]; - - return __builtin_bswap32(val) >> 16; -} - - -/** Return the flow hash computed on the packet. - * @ingroup ingress - * - * For TCP and UDP packets, this hash is calculated by hashing together - * the "5-tuple" values, specifically the source IP address, destination - * IP address, protocol type, source port and destination port. - * The hash value is intended to be helpful for millions of distinct - * flows. - * - * For IPv4 or IPv6 packets which are neither TCP nor UDP, the flow hash is - * derived by hashing together the source and destination IP addresses. - * - * For MPLS-encapsulated packets, the flow hash is derived by hashing - * the first MPLS label. - * - * For all other packets the flow hash is computed from the source - * and destination Ethernet addresses. - * - * The hash is symmetric, meaning it produces the same value if the - * source and destination are swapped. The only exceptions are - * tunneling protocols 0x04 (IP in IP Encapsulation), 0x29 (Simple - * Internet Protocol), 0x2F (General Routing Encapsulation) and 0x32 - * (Encap Security Payload), which use only the destination address - * since the source address is not meaningful. - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The packet's 32-bit flow hash. - */ -static __inline unsigned int -NETIO_PKT_FLOW_HASH_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return mda->__flow_hash; -} - - -/** Return the first word of "user data" for the packet. - * - * The contents of the user data words depend on the IPP. - * - * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the first - * word of user data contains the least significant bits of the 64-bit - * arrival cycle count (see @c get_cycle_count_low()). - * - * See the System Programmer's Guide for details. - * - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The packet's first word of "user data". - */ -static __inline unsigned int -NETIO_PKT_USER_DATA_0_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return mda->__user_data_0; -} - - -/** Return the second word of "user data" for the packet. - * - * The contents of the user data words depend on the IPP. - * - * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the second - * word of user data contains the most significant bits of the 64-bit - * arrival cycle count (see @c get_cycle_count_high()). - * - * See the System Programmer's Guide for details. - * - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The packet's second word of "user data". - */ -static __inline unsigned int -NETIO_PKT_USER_DATA_1_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return mda->__user_data_1; -} - - -/** Determine whether the L4 (TCP/UDP) checksum was calculated. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the L4 checksum was calculated. - */ -static __inline unsigned int -NETIO_PKT_L4_CSUM_CALCULATED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return !(mda->__flags & _NETIO_PKT_NO_L4_CSUM_MASK); -} - - -/** Determine whether the L4 (TCP/UDP) checksum was calculated and found to - * be correct. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the checksum was calculated and is correct. - */ -static __inline unsigned int -NETIO_PKT_L4_CSUM_CORRECT_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return !(mda->__flags & - (_NETIO_PKT_BAD_L4_CSUM_MASK | _NETIO_PKT_NO_L4_CSUM_MASK)); -} - - -/** Determine whether the L3 (IP) checksum was calculated. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the L3 (IP) checksum was calculated. -*/ -static __inline unsigned int -NETIO_PKT_L3_CSUM_CALCULATED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return !(mda->__flags & _NETIO_PKT_NO_L3_CSUM_MASK); -} - - -/** Determine whether the L3 (IP) checksum was calculated and found to be - * correct. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the checksum was calculated and is correct. - */ -static __inline unsigned int -NETIO_PKT_L3_CSUM_CORRECT_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return !(mda->__flags & - (_NETIO_PKT_BAD_L3_CSUM_MASK | _NETIO_PKT_NO_L3_CSUM_MASK)); -} - - -/** Determine whether the ethertype was recognized and L3 packet data was - * processed. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the ethertype was recognized and L3 packet data was - * processed. - */ -static __inline unsigned int -NETIO_PKT_ETHERTYPE_RECOGNIZED_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return !(mda->__flags & _NETIO_PKT_TYPE_UNRECOGNIZED_MASK); -} - - -/** Retrieve the status of a packet and any errors that may have occurred - * during ingress processing (length mismatches, CRC errors, etc.). - * @ingroup ingress - * - * Note that packets for which @ref NETIO_PKT_ETHERTYPE_RECOGNIZED() - * returns zero are always reported as underlength, as there is no a priori - * means to determine their length. Normally, applications should use - * @ref NETIO_PKT_BAD_M() instead of explicitly checking status with this - * function. - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return The packet's status. - */ -static __inline netio_pkt_status_t -NETIO_PKT_STATUS_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return (netio_pkt_status_t) __NETIO_PKT_NOTIF_HEADER(pkt).bits.__status; -} - - -/** Report whether a packet is bad (i.e., was shorter than expected based on - * its headers, or had a bad CRC). - * @ingroup ingress - * - * Note that this function does not verify L3 or L4 checksums. - * - * @param[in] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the packet is bad and should be discarded. - */ -static __inline unsigned int -NETIO_PKT_BAD_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return ((NETIO_PKT_STATUS_M(mda, pkt) & 1) && - (NETIO_PKT_ETHERTYPE_RECOGNIZED_M(mda, pkt) || - NETIO_PKT_STATUS_M(mda, pkt) == NETIO_PKT_STATUS_BAD)); -} - - -/** Return the length of the packet, starting with the L2 (Ethernet) header. - * @ingroup egress - * - * @param[in] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - * @return The length of the packet, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_L2_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt) -{ - return mmd->l2_length; -} - - -/** Return the length of the L2 (Ethernet) header. - * @ingroup egress - * - * @param[in] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - * @return The length of the packet's L2 header, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_L2_HEADER_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, - netio_pkt_t* pkt) -{ - return mmd->l3_offset - mmd->l2_offset; -} - - -/** Return the length of the packet, starting with the L3 (IP) header. - * @ingroup egress - * - * @param[in] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - * @return Length of the packet's L3 header and data, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_L3_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt) -{ - return (NETIO_PKT_L2_LENGTH_MM(mmd, pkt) - - NETIO_PKT_L2_HEADER_LENGTH_MM(mmd, pkt)); -} - - -/** Return a pointer to the packet's L3 (generally, the IP) header. - * @ingroup egress - * - * Note that we guarantee word alignment of the L3 header. - * - * @param[in] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - * @return A pointer to the packet's L3 header. - */ -static __inline unsigned char* -NETIO_PKT_L3_DATA_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt) -{ - return _NETIO_PKT_BASE(pkt) + mmd->l3_offset; -} - - -/** Return a pointer to the packet's L2 (Ethernet) header. - * @ingroup egress - * - * @param[in] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - * @return A pointer to start of the packet. - */ -static __inline unsigned char* -NETIO_PKT_L2_DATA_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt) -{ - return _NETIO_PKT_BASE(pkt) + mmd->l2_offset; -} - - -/** Retrieve the status of a packet and any errors that may have occurred - * during ingress processing (length mismatches, CRC errors, etc.). - * @ingroup ingress - * - * Note that packets for which @ref NETIO_PKT_ETHERTYPE_RECOGNIZED() - * returns zero are always reported as underlength, as there is no a priori - * means to determine their length. Normally, applications should use - * @ref NETIO_PKT_BAD() instead of explicitly checking status with this - * function. - * - * @param[in] pkt Packet on which to operate. - * @return The packet's status. - */ -static __inline netio_pkt_status_t -NETIO_PKT_STATUS(netio_pkt_t* pkt) -{ - netio_assert(!pkt->__packet.bits.__minimal); - - return (netio_pkt_status_t) __NETIO_PKT_NOTIF_HEADER(pkt).bits.__status; -} - - -/** Report whether a packet is bad (i.e., was shorter than expected based on - * its headers, or had a bad CRC). - * @ingroup ingress - * - * Note that this function does not verify L3 or L4 checksums. - * - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the packet is bad and should be discarded. - */ -static __inline unsigned int -NETIO_PKT_BAD(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_BAD_M(mda, pkt); -} - - -/** Return the length of the packet's custom header. - * A custom header may or may not be present, depending upon the IPP; its - * contents and alignment are also IPP-dependent. Currently, none of the - * standard IPPs supplied by Tilera produce a custom header. If present, - * the custom header precedes the L2 header in the packet buffer. - * @ingroup pktfuncs - * - * @param[in] pkt Packet on which to operate. - * @return The length of the packet's custom header, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_CUSTOM_HEADER_LENGTH(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt); -} - - -/** Return the length of the packet, starting with the custom header. - * A custom header may or may not be present, depending upon the IPP; its - * contents and alignment are also IPP-dependent. Currently, none of the - * standard IPPs supplied by Tilera produce a custom header. If present, - * the custom header precedes the L2 header in the packet buffer. - * @ingroup pktfuncs - * - * @param[in] pkt Packet on which to operate. - * @return The length of the packet, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_CUSTOM_LENGTH(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_CUSTOM_LENGTH_M(mda, pkt); -} - - -/** Return a pointer to the packet's custom header. - * A custom header may or may not be present, depending upon the IPP; its - * contents and alignment are also IPP-dependent. Currently, none of the - * standard IPPs supplied by Tilera produce a custom header. If present, - * the custom header precedes the L2 header in the packet buffer. - * @ingroup pktfuncs - * - * @param[in] pkt Packet on which to operate. - * @return A pointer to start of the packet. - */ -static __inline unsigned char* -NETIO_PKT_CUSTOM_DATA(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_CUSTOM_DATA_M(mda, pkt); -} - - -/** Return the length of the packet's L2 (Ethernet plus VLAN or SNAP) header. - * @ingroup pktfuncs - * - * @param[in] pkt Packet on which to operate. - * @return The length of the packet's L2 header, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_L2_HEADER_LENGTH(netio_pkt_t* pkt) -{ - if (NETIO_PKT_IS_MINIMAL(pkt)) - { - netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); - - return NETIO_PKT_L2_HEADER_LENGTH_MM(mmd, pkt); - } - else - { - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_L2_HEADER_LENGTH_M(mda, pkt); - } -} - - -/** Return the length of the packet, starting with the L2 (Ethernet) header. - * @ingroup pktfuncs - * - * @param[in] pkt Packet on which to operate. - * @return The length of the packet, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_L2_LENGTH(netio_pkt_t* pkt) -{ - if (NETIO_PKT_IS_MINIMAL(pkt)) - { - netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); - - return NETIO_PKT_L2_LENGTH_MM(mmd, pkt); - } - else - { - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_L2_LENGTH_M(mda, pkt); - } -} - - -/** Return a pointer to the packet's L2 (Ethernet) header. - * @ingroup pktfuncs - * - * @param[in] pkt Packet on which to operate. - * @return A pointer to start of the packet. - */ -static __inline unsigned char* -NETIO_PKT_L2_DATA(netio_pkt_t* pkt) -{ - if (NETIO_PKT_IS_MINIMAL(pkt)) - { - netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); - - return NETIO_PKT_L2_DATA_MM(mmd, pkt); - } - else - { - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_L2_DATA_M(mda, pkt); - } -} - - -/** Retrieve the length of the packet, starting with the L3 (generally, the IP) - * header. - * @ingroup pktfuncs - * - * @param[in] pkt Packet on which to operate. - * @return Length of the packet's L3 header and data, in bytes. - */ -static __inline netio_size_t -NETIO_PKT_L3_LENGTH(netio_pkt_t* pkt) -{ - if (NETIO_PKT_IS_MINIMAL(pkt)) - { - netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); - - return NETIO_PKT_L3_LENGTH_MM(mmd, pkt); - } - else - { - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_L3_LENGTH_M(mda, pkt); - } -} - - -/** Return a pointer to the packet's L3 (generally, the IP) header. - * @ingroup pktfuncs - * - * Note that we guarantee word alignment of the L3 header. - * - * @param[in] pkt Packet on which to operate. - * @return A pointer to the packet's L3 header. - */ -static __inline unsigned char* -NETIO_PKT_L3_DATA(netio_pkt_t* pkt) -{ - if (NETIO_PKT_IS_MINIMAL(pkt)) - { - netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); - - return NETIO_PKT_L3_DATA_MM(mmd, pkt); - } - else - { - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_L3_DATA_M(mda, pkt); - } -} - - -/** Return the ordinal of the packet. - * @ingroup ingress - * - * Each packet is given an ordinal number when it is delivered by the IPP. - * In the medium term, the ordinal is unique and monotonically increasing, - * being incremented by 1 for each packet; the ordinal of the first packet - * delivered after the IPP starts is zero. (Since the ordinal is of finite - * size, given enough input packets, it will eventually wrap around to zero; - * in the long term, therefore, ordinals are not unique.) The ordinals - * handed out by different IPPs are not disjoint, so two packets from - * different IPPs may have identical ordinals. Packets dropped by the - * IPP or by the I/O shim are not assigned ordinals. - * - * - * @param[in] pkt Packet on which to operate. - * @return The packet's per-IPP packet ordinal. - */ -static __inline unsigned int -NETIO_PKT_ORDINAL(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_ORDINAL_M(mda, pkt); -} - - -/** Return the per-group ordinal of the packet. - * @ingroup ingress - * - * Each packet is given a per-group ordinal number when it is - * delivered by the IPP. By default, the group is the packet's VLAN, - * although IPP can be recompiled to use different values. In - * the medium term, the ordinal is unique and monotonically - * increasing, being incremented by 1 for each packet; the ordinal of - * the first packet distributed to a particular group is zero. - * (Since the ordinal is of finite size, given enough input packets, - * it will eventually wrap around to zero; in the long term, - * therefore, ordinals are not unique.) The ordinals handed out by - * different IPPs are not disjoint, so two packets from different IPPs - * may have identical ordinals; similarly, packets distributed to - * different groups may have identical ordinals. Packets dropped by - * the IPP or by the I/O shim are not assigned ordinals. - * - * @param[in] pkt Packet on which to operate. - * @return The packet's per-IPP, per-group ordinal. - */ -static __inline unsigned int -NETIO_PKT_GROUP_ORDINAL(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_GROUP_ORDINAL_M(mda, pkt); -} - - -/** Return the VLAN ID assigned to the packet. - * @ingroup ingress - * - * This is usually also contained within the packet header. If the packet - * does not have a VLAN tag, the VLAN ID returned by this function is zero. - * - * @param[in] pkt Packet on which to operate. - * @return The packet's VLAN ID. - */ -static __inline unsigned short -NETIO_PKT_VLAN_ID(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_VLAN_ID_M(mda, pkt); -} - - -/** Return the ethertype of the packet. - * @ingroup ingress - * - * This value is reliable if @ref NETIO_PKT_ETHERTYPE_RECOGNIZED() - * returns true, and otherwise, may not be well defined. - * - * @param[in] pkt Packet on which to operate. - * @return The packet's ethertype. - */ -static __inline unsigned short -NETIO_PKT_ETHERTYPE(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_ETHERTYPE_M(mda, pkt); -} - - -/** Return the flow hash computed on the packet. - * @ingroup ingress - * - * For TCP and UDP packets, this hash is calculated by hashing together - * the "5-tuple" values, specifically the source IP address, destination - * IP address, protocol type, source port and destination port. - * The hash value is intended to be helpful for millions of distinct - * flows. - * - * For IPv4 or IPv6 packets which are neither TCP nor UDP, the flow hash is - * derived by hashing together the source and destination IP addresses. - * - * For MPLS-encapsulated packets, the flow hash is derived by hashing - * the first MPLS label. - * - * For all other packets the flow hash is computed from the source - * and destination Ethernet addresses. - * - * The hash is symmetric, meaning it produces the same value if the - * source and destination are swapped. The only exceptions are - * tunneling protocols 0x04 (IP in IP Encapsulation), 0x29 (Simple - * Internet Protocol), 0x2F (General Routing Encapsulation) and 0x32 - * (Encap Security Payload), which use only the destination address - * since the source address is not meaningful. - * - * @param[in] pkt Packet on which to operate. - * @return The packet's 32-bit flow hash. - */ -static __inline unsigned int -NETIO_PKT_FLOW_HASH(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_FLOW_HASH_M(mda, pkt); -} - - -/** Return the first word of "user data" for the packet. - * - * The contents of the user data words depend on the IPP. - * - * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the first - * word of user data contains the least significant bits of the 64-bit - * arrival cycle count (see @c get_cycle_count_low()). - * - * See the System Programmer's Guide for details. - * - * @ingroup ingress - * - * @param[in] pkt Packet on which to operate. - * @return The packet's first word of "user data". - */ -static __inline unsigned int -NETIO_PKT_USER_DATA_0(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_USER_DATA_0_M(mda, pkt); -} - - -/** Return the second word of "user data" for the packet. - * - * The contents of the user data words depend on the IPP. - * - * When using the standard ipp1, ipp2, or ipp4 sub-drivers, the second - * word of user data contains the most significant bits of the 64-bit - * arrival cycle count (see @c get_cycle_count_high()). - * - * See the System Programmer's Guide for details. - * - * @ingroup ingress - * - * @param[in] pkt Packet on which to operate. - * @return The packet's second word of "user data". - */ -static __inline unsigned int -NETIO_PKT_USER_DATA_1(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_USER_DATA_1_M(mda, pkt); -} - - -/** Determine whether the L4 (TCP/UDP) checksum was calculated. - * @ingroup ingress - * - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the L4 checksum was calculated. - */ -static __inline unsigned int -NETIO_PKT_L4_CSUM_CALCULATED(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_L4_CSUM_CALCULATED_M(mda, pkt); -} - - -/** Determine whether the L4 (TCP/UDP) checksum was calculated and found to - * be correct. - * @ingroup ingress - * - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the checksum was calculated and is correct. - */ -static __inline unsigned int -NETIO_PKT_L4_CSUM_CORRECT(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_L4_CSUM_CORRECT_M(mda, pkt); -} - - -/** Determine whether the L3 (IP) checksum was calculated. - * @ingroup ingress - * - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the L3 (IP) checksum was calculated. -*/ -static __inline unsigned int -NETIO_PKT_L3_CSUM_CALCULATED(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_L3_CSUM_CALCULATED_M(mda, pkt); -} - - -/** Determine whether the L3 (IP) checksum was calculated and found to be - * correct. - * @ingroup ingress - * - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the checksum was calculated and is correct. - */ -static __inline unsigned int -NETIO_PKT_L3_CSUM_CORRECT(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_L3_CSUM_CORRECT_M(mda, pkt); -} - - -/** Determine whether the Ethertype was recognized and L3 packet data was - * processed. - * @ingroup ingress - * - * @param[in] pkt Packet on which to operate. - * @return Nonzero if the Ethertype was recognized and L3 packet data was - * processed. - */ -static __inline unsigned int -NETIO_PKT_ETHERTYPE_RECOGNIZED(netio_pkt_t* pkt) -{ - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_ETHERTYPE_RECOGNIZED_M(mda, pkt); -} - - -/** Set an egress packet's L2 length, using a metadata pointer to speed the - * computation. - * @ingroup egress - * - * @param[in,out] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - * @param[in] len Packet L2 length, in bytes. - */ -static __inline void -NETIO_PKT_SET_L2_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt, - int len) -{ - mmd->l2_length = len; -} - - -/** Set an egress packet's L2 length. - * @ingroup egress - * - * @param[in,out] pkt Packet on which to operate. - * @param[in] len Packet L2 length, in bytes. - */ -static __inline void -NETIO_PKT_SET_L2_LENGTH(netio_pkt_t* pkt, int len) -{ - netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); - - NETIO_PKT_SET_L2_LENGTH_MM(mmd, pkt, len); -} - - -/** Set an egress packet's L2 header length, using a metadata pointer to - * speed the computation. - * @ingroup egress - * - * It is not normally necessary to call this routine; only the L2 length, - * not the header length, is needed to transmit a packet. It may be useful if - * the egress packet will later be processed by code which expects to use - * functions like @ref NETIO_PKT_L3_DATA() to get a pointer to the L3 payload. - * - * @param[in,out] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - * @param[in] len Packet L2 header length, in bytes. - */ -static __inline void -NETIO_PKT_SET_L2_HEADER_LENGTH_MM(netio_pkt_minimal_metadata_t* mmd, - netio_pkt_t* pkt, int len) -{ - mmd->l3_offset = mmd->l2_offset + len; -} - - -/** Set an egress packet's L2 header length. - * @ingroup egress - * - * It is not normally necessary to call this routine; only the L2 length, - * not the header length, is needed to transmit a packet. It may be useful if - * the egress packet will later be processed by code which expects to use - * functions like @ref NETIO_PKT_L3_DATA() to get a pointer to the L3 payload. - * - * @param[in,out] pkt Packet on which to operate. - * @param[in] len Packet L2 header length, in bytes. - */ -static __inline void -NETIO_PKT_SET_L2_HEADER_LENGTH(netio_pkt_t* pkt, int len) -{ - netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); - - NETIO_PKT_SET_L2_HEADER_LENGTH_MM(mmd, pkt, len); -} - - -/** Set up an egress packet for hardware checksum computation, using a - * metadata pointer to speed the operation. - * @ingroup egress - * - * NetIO provides the ability to automatically calculate a standard - * 16-bit Internet checksum on transmitted packets. The application - * may specify the point in the packet where the checksum starts, the - * number of bytes to be checksummed, and the two bytes in the packet - * which will be replaced with the completed checksum. (If the range - * of bytes to be checksummed includes the bytes to be replaced, the - * initial values of those bytes will be included in the checksum.) - * - * For some protocols, the packet checksum covers data which is not present - * in the packet, or is at least not contiguous to the main data payload. - * For instance, the TCP checksum includes a "pseudo-header" which includes - * the source and destination IP addresses of the packet. To accommodate - * this, the checksum engine may be "seeded" with an initial value, which - * the application would need to compute based on the specific protocol's - * requirements. Note that the seed is given in host byte order (little- - * endian), not network byte order (big-endian); code written to compute a - * pseudo-header checksum in network byte order will need to byte-swap it - * before use as the seed. - * - * Note that the checksum is computed as part of the transmission process, - * so it will not be present in the packet upon completion of this routine. - * - * @param[in,out] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - * @param[in] start Offset within L2 packet of the first byte to include in - * the checksum. - * @param[in] length Number of bytes to include in the checksum. - * the checksum. - * @param[in] location Offset within L2 packet of the first of the two bytes - * to be replaced with the calculated checksum. - * @param[in] seed Initial value of the running checksum before any of the - * packet data is added. - */ -static __inline void -NETIO_PKT_DO_EGRESS_CSUM_MM(netio_pkt_minimal_metadata_t* mmd, - netio_pkt_t* pkt, int start, int length, - int location, uint16_t seed) -{ - mmd->csum_start = start; - mmd->csum_length = length; - mmd->csum_location = location; - mmd->csum_seed = seed; - mmd->flags |= _NETIO_PKT_NEED_EDMA_CSUM_MASK; -} - - -/** Set up an egress packet for hardware checksum computation. - * @ingroup egress - * - * NetIO provides the ability to automatically calculate a standard - * 16-bit Internet checksum on transmitted packets. The application - * may specify the point in the packet where the checksum starts, the - * number of bytes to be checksummed, and the two bytes in the packet - * which will be replaced with the completed checksum. (If the range - * of bytes to be checksummed includes the bytes to be replaced, the - * initial values of those bytes will be included in the checksum.) - * - * For some protocols, the packet checksum covers data which is not present - * in the packet, or is at least not contiguous to the main data payload. - * For instance, the TCP checksum includes a "pseudo-header" which includes - * the source and destination IP addresses of the packet. To accommodate - * this, the checksum engine may be "seeded" with an initial value, which - * the application would need to compute based on the specific protocol's - * requirements. Note that the seed is given in host byte order (little- - * endian), not network byte order (big-endian); code written to compute a - * pseudo-header checksum in network byte order will need to byte-swap it - * before use as the seed. - * - * Note that the checksum is computed as part of the transmission process, - * so it will not be present in the packet upon completion of this routine. - * - * @param[in,out] pkt Packet on which to operate. - * @param[in] start Offset within L2 packet of the first byte to include in - * the checksum. - * @param[in] length Number of bytes to include in the checksum. - * the checksum. - * @param[in] location Offset within L2 packet of the first of the two bytes - * to be replaced with the calculated checksum. - * @param[in] seed Initial value of the running checksum before any of the - * packet data is added. - */ -static __inline void -NETIO_PKT_DO_EGRESS_CSUM(netio_pkt_t* pkt, int start, int length, - int location, uint16_t seed) -{ - netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); - - NETIO_PKT_DO_EGRESS_CSUM_MM(mmd, pkt, start, length, location, seed); -} - - -/** Return the number of bytes which could be prepended to a packet, using a - * metadata pointer to speed the operation. - * See @ref netio_populate_prepend_buffer() to get a full description of - * prepending. - * - * @param[in,out] mda Pointer to packet's standard metadata. - * @param[in] pkt Packet on which to operate. - */ -static __inline int -NETIO_PKT_PREPEND_AVAIL_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ - return (pkt->__packet.bits.__offset << 6) + - NETIO_PKT_CUSTOM_HEADER_LENGTH_M(mda, pkt); -} - - -/** Return the number of bytes which could be prepended to a packet, using a - * metadata pointer to speed the operation. - * See @ref netio_populate_prepend_buffer() to get a full description of - * prepending. - * @ingroup egress - * - * @param[in,out] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - */ -static __inline int -NETIO_PKT_PREPEND_AVAIL_MM(netio_pkt_minimal_metadata_t* mmd, netio_pkt_t* pkt) -{ - return (pkt->__packet.bits.__offset << 6) + mmd->l2_offset; -} - - -/** Return the number of bytes which could be prepended to a packet. - * See @ref netio_populate_prepend_buffer() to get a full description of - * prepending. - * @ingroup egress - * - * @param[in] pkt Packet on which to operate. - */ -static __inline int -NETIO_PKT_PREPEND_AVAIL(netio_pkt_t* pkt) -{ - if (NETIO_PKT_IS_MINIMAL(pkt)) - { - netio_pkt_minimal_metadata_t* mmd = NETIO_PKT_MINIMAL_METADATA(pkt); - - return NETIO_PKT_PREPEND_AVAIL_MM(mmd, pkt); - } - else - { - netio_pkt_metadata_t* mda = NETIO_PKT_METADATA(pkt); - - return NETIO_PKT_PREPEND_AVAIL_M(mda, pkt); - } -} - - -/** Flush a packet's minimal metadata from the cache, using a metadata pointer - * to speed the operation. - * @ingroup egress - * - * @param[in] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_FLUSH_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd, - netio_pkt_t* pkt) -{ -} - - -/** Invalidate a packet's minimal metadata from the cache, using a metadata - * pointer to speed the operation. - * @ingroup egress - * - * @param[in] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_INV_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd, - netio_pkt_t* pkt) -{ -} - - -/** Flush and then invalidate a packet's minimal metadata from the cache, - * using a metadata pointer to speed the operation. - * @ingroup egress - * - * @param[in] mmd Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_FLUSH_INV_MINIMAL_METADATA_MM(netio_pkt_minimal_metadata_t* mmd, - netio_pkt_t* pkt) -{ -} - - -/** Flush a packet's metadata from the cache, using a metadata pointer - * to speed the operation. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's minimal metadata. - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_FLUSH_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ -} - - -/** Invalidate a packet's metadata from the cache, using a metadata - * pointer to speed the operation. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's metadata. - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_INV_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ -} - - -/** Flush and then invalidate a packet's metadata from the cache, - * using a metadata pointer to speed the operation. - * @ingroup ingress - * - * @param[in] mda Pointer to packet's metadata. - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_FLUSH_INV_METADATA_M(netio_pkt_metadata_t* mda, netio_pkt_t* pkt) -{ -} - - -/** Flush a packet's minimal metadata from the cache. - * @ingroup egress - * - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_FLUSH_MINIMAL_METADATA(netio_pkt_t* pkt) -{ -} - - -/** Invalidate a packet's minimal metadata from the cache. - * @ingroup egress - * - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_INV_MINIMAL_METADATA(netio_pkt_t* pkt) -{ -} - - -/** Flush and then invalidate a packet's minimal metadata from the cache. - * @ingroup egress - * - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_FLUSH_INV_MINIMAL_METADATA(netio_pkt_t* pkt) -{ -} - - -/** Flush a packet's metadata from the cache. - * @ingroup ingress - * - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_FLUSH_METADATA(netio_pkt_t* pkt) -{ -} - - -/** Invalidate a packet's metadata from the cache. - * @ingroup ingress - * - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_INV_METADATA(netio_pkt_t* pkt) -{ -} - - -/** Flush and then invalidate a packet's metadata from the cache. - * @ingroup ingress - * - * @param[in] pkt Packet on which to operate. - */ -static __inline void -NETIO_PKT_FLUSH_INV_METADATA(netio_pkt_t* pkt) -{ -} - -/** Number of NUMA nodes we can distribute buffers to. - * @ingroup setup */ -#define NETIO_NUM_NODE_WEIGHTS 16 - -/** - * @brief An object for specifying the characteristics of NetIO communication - * endpoint. - * - * @ingroup setup - * - * The @ref netio_input_register() function uses this structure to define - * how an application tile will communicate with an IPP. - * - * - * Future updates to NetIO may add new members to this structure, - * which can affect the success of the registration operation. Thus, - * if dynamically initializing the structure, applications are urged to - * zero it out first, for example: - * - * @code - * netio_input_config_t config; - * memset(&config, 0, sizeof (config)); - * config.flags = NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE; - * config.num_receive_packets = NETIO_MAX_RECEIVE_PKTS; - * config.queue_id = 0; - * . - * . - * . - * @endcode - * - * since that guarantees that any unused structure members, including - * members which did not exist when the application was first developed, - * will not have unexpected values. - * - * If statically initializing the structure, we strongly recommend use of - * C99-style named initializers, for example: - * - * @code - * netio_input_config_t config = { - * .flags = NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE, - * .num_receive_packets = NETIO_MAX_RECEIVE_PKTS, - * .queue_id = 0, - * }, - * @endcode - * - * instead of the old-style structure initialization: - * - * @code - * // Bad example! Currently equivalent to the above, but don't do this. - * netio_input_config_t config = { - * NETIO_RECV | NETIO_XMIT_CSUM | NETIO_TAG_NONE, NETIO_MAX_RECEIVE_PKTS, 0 - * }, - * @endcode - * - * since the C99 style requires no changes to the code if elements of the - * config structure are rearranged. (It also makes the initialization much - * easier to understand.) - * - * Except for items which address a particular tile's transmit or receive - * characteristics, such as the ::NETIO_RECV flag, applications are advised - * to specify the same set of configuration data on all registrations. - * This prevents differing results if multiple tiles happen to do their - * registration operations in a different order on different invocations of - * the application. This is particularly important for things like link - * management flags, and buffer size and homing specifications. - * - * Unless the ::NETIO_FIXED_BUFFER_VA flag is specified in flags, the NetIO - * buffer pool is automatically created and mapped into the application's - * virtual address space at an address chosen by the operating system, - * using the common memory (cmem) facility in the Tilera Multicore - * Components library. The cmem facility allows multiple processes to gain - * access to shared memory which is mapped into each process at an - * identical virtual address. In order for this to work, the processes - * must have a common ancestor, which must create the common memory using - * tmc_cmem_init(). - * - * In programs using the iLib process creation API, or in programs which use - * only one process (which include programs using the pthreads library), - * tmc_cmem_init() is called automatically. All other applications - * must call it explicitly, before any child processes which might call - * netio_input_register() are created. - */ -typedef struct -{ - /** Registration characteristics. - - This value determines several characteristics of the registration; - flags for different types of behavior are ORed together to make the - final flag value. Generally applications should specify exactly - one flag from each of the following categories: - - - Whether the application will be receiving packets on this queue - (::NETIO_RECV or ::NETIO_NO_RECV). - - - Whether the application will be transmitting packets on this queue, - and if so, whether it will request egress checksum calculation - (::NETIO_XMIT, ::NETIO_XMIT_CSUM, or ::NETIO_NO_XMIT). It is - legal to call netio_get_buffer() without one of the XMIT flags, - as long as ::NETIO_RECV is specified; in this case, the retrieved - buffers must be passed to another tile for transmission. - - - Whether the application expects any vendor-specific tags in - its packets' L2 headers (::NETIO_TAG_NONE, ::NETIO_TAG_BRCM, - or ::NETIO_TAG_MRVL). This must match the configuration of the - target IPP. - - To accommodate applications written to previous versions of the NetIO - interface, none of the flags above are currently required; if omitted, - NetIO behaves more or less as if ::NETIO_RECV | ::NETIO_XMIT_CSUM | - ::NETIO_TAG_NONE were used. However, explicit specification of - the relevant flags allows NetIO to do a better job of resource - allocation, allows earlier detection of certain configuration errors, - and may enable advanced features or higher performance in the future, - so their use is strongly recommended. - - Note that specifying ::NETIO_NO_RECV along with ::NETIO_NO_XMIT - is a special case, intended primarily for use by programs which - retrieve network statistics or do link management operations. - When these flags are both specified, the resulting queue may not - be used with NetIO routines other than netio_get(), netio_set(), - and netio_input_unregister(). See @ref link for more information - on link management. - - Other flags are optional; their use is described below. - */ - int flags; - - /** Interface name. This is a string which identifies the specific - Ethernet controller hardware to be used. The format of the string - is a device type and a device index, separated by a slash; so, - the first 10 Gigabit Ethernet controller is named "xgbe/0", while - the second 10/100/1000 Megabit Ethernet controller is named "gbe/1". - */ - const char* interface; - - /** Receive packet queue size. This specifies the maximum number - of ingress packets that can be received on this queue without - being retrieved by @ref netio_get_packet(). If the IPP's distribution - algorithm calls for a packet to be sent to this queue, and this - number of packets are already pending there, the new packet - will either be discarded, or sent to another tile registered - for the same queue_id (see @ref drops). This value must - be at least ::NETIO_MIN_RECEIVE_PKTS, can always be at least - ::NETIO_MAX_RECEIVE_PKTS, and may be larger than that on certain - interfaces. - */ - int num_receive_packets; - - /** The queue ID being requested. Legal values for this range from 0 - to ::NETIO_MAX_QUEUE_ID, inclusive. ::NETIO_MAX_QUEUE_ID is always - greater than or equal to the number of tiles; this allows one queue - for each tile, plus at least one additional queue. Some applications - may wish to use the additional queue as a destination for unwanted - packets, since packets delivered to queues for which no tiles have - registered are discarded. - */ - unsigned int queue_id; - - /** Maximum number of small send buffers to be held in the local empty - buffer cache. This specifies the size of the area which holds - empty small egress buffers requested from the IPP but not yet - retrieved via @ref netio_get_buffer(). This value must be greater - than zero if the application will ever use @ref netio_get_buffer() - to allocate empty small egress buffers; it may be no larger than - ::NETIO_MAX_SEND_BUFFERS. See @ref epp for more details on empty - buffer caching. - */ - int num_send_buffers_small_total; - - /** Number of small send buffers to be preallocated at registration. - If this value is nonzero, the specified number of empty small egress - buffers will be requested from the IPP during the netio_input_register - operation; this may speed the execution of @ref netio_get_buffer(). - This may be no larger than @ref num_send_buffers_small_total. See @ref - epp for more details on empty buffer caching. - */ - int num_send_buffers_small_prealloc; - - /** Maximum number of large send buffers to be held in the local empty - buffer cache. This specifies the size of the area which holds empty - large egress buffers requested from the IPP but not yet retrieved via - @ref netio_get_buffer(). This value must be greater than zero if the - application will ever use @ref netio_get_buffer() to allocate empty - large egress buffers; it may be no larger than ::NETIO_MAX_SEND_BUFFERS. - See @ref epp for more details on empty buffer caching. - */ - int num_send_buffers_large_total; - - /** Number of large send buffers to be preallocated at registration. - If this value is nonzero, the specified number of empty large egress - buffers will be requested from the IPP during the netio_input_register - operation; this may speed the execution of @ref netio_get_buffer(). - This may be no larger than @ref num_send_buffers_large_total. See @ref - epp for more details on empty buffer caching. - */ - int num_send_buffers_large_prealloc; - - /** Maximum number of jumbo send buffers to be held in the local empty - buffer cache. This specifies the size of the area which holds empty - jumbo egress buffers requested from the IPP but not yet retrieved via - @ref netio_get_buffer(). This value must be greater than zero if the - application will ever use @ref netio_get_buffer() to allocate empty - jumbo egress buffers; it may be no larger than ::NETIO_MAX_SEND_BUFFERS. - See @ref epp for more details on empty buffer caching. - */ - int num_send_buffers_jumbo_total; - - /** Number of jumbo send buffers to be preallocated at registration. - If this value is nonzero, the specified number of empty jumbo egress - buffers will be requested from the IPP during the netio_input_register - operation; this may speed the execution of @ref netio_get_buffer(). - This may be no larger than @ref num_send_buffers_jumbo_total. See @ref - epp for more details on empty buffer caching. - */ - int num_send_buffers_jumbo_prealloc; - - /** Total packet buffer size. This determines the total size, in bytes, - of the NetIO buffer pool. Note that the maximum number of available - buffers of each size is determined during hypervisor configuration - (see the System Programmer's Guide for details); this just - influences how much host memory is allocated for those buffers. - - The buffer pool is allocated from common memory, which will be - automatically initialized if needed. If your buffer pool is larger - than 240 MB, you might need to explicitly call @c tmc_cmem_init(), - as described in the Application Libraries Reference Manual (UG227). - - Packet buffers are currently allocated in chunks of 16 MB; this - value will be rounded up to the next larger multiple of 16 MB. - If this value is zero, a default of 32 MB will be used; this was - the value used by previous versions of NetIO. Note that taking this - default also affects the placement of buffers on Linux NUMA nodes. - See @ref buffer_node_weights for an explanation of buffer placement. - - In order to successfully allocate packet buffers, Linux must have - available huge pages on the relevant Linux NUMA nodes. See the - System Programmer's Guide for information on configuring - huge page support in Linux. - */ - uint64_t total_buffer_size; - - /** Buffer placement weighting factors. - - This array specifies the relative amount of buffering to place - on each of the available Linux NUMA nodes. This array is - indexed by the NUMA node, and the values in the array are - proportional to the amount of buffer space to allocate on that - node. - - If memory striping is enabled in the Hypervisor, then there is - only one logical NUMA node (node 0). In that case, NetIO will by - default ignore the suggested buffer node weights, and buffers - will be striped across the physical memory controllers. See - UG209 System Programmer's Guide for a description of the - hypervisor option that controls memory striping. - - If memory striping is disabled, then there are up to four NUMA - nodes, corresponding to the four DDRAM controllers in the TILE - processor architecture. See UG100 Tile Processor Architecture - Overview for a diagram showing the location of each of the DDRAM - controllers relative to the tile array. - - For instance, if memory striping is disabled, the following - configuration strucure: - - @code - netio_input_config_t config = { - . - . - . - .total_buffer_size = 4 * 16 * 1024 * 1024; - .buffer_node_weights = { 1, 0, 1, 0 }, - }, - @endcode - - would result in 32 MB of buffers being placed on controller 0, and - 32 MB on controller 2. (Since buffers are allocated in units of - 16 MB, some sets of weights will not be able to be matched exactly.) - - For the weights to be effective, @ref total_buffer_size must be - nonzero. If @ref total_buffer_size is zero, causing the default - 32 MB of buffer space to be used, then any specified weights will - be ignored, and buffers will positioned as they were in previous - versions of NetIO: - - - For xgbe/0 and gbe/0, 16 MB of buffers will be placed on controller 1, - and the other 16 MB will be placed on controller 2. - - - For xgbe/1 and gbe/1, 16 MB of buffers will be placed on controller 2, - and the other 16 MB will be placed on controller 3. - - If @ref total_buffer_size is nonzero, but all weights are zero, - then all buffer space will be allocated on Linux NUMA node zero. - - By default, the specified buffer placement is treated as a hint; - if sufficient free memory is not available on the specified - controllers, the buffers will be allocated elsewhere. However, - if the ::NETIO_STRICT_HOMING flag is specified in @ref flags, then a - failure to allocate buffer space exactly as requested will cause the - registration operation to fail with an error of ::NETIO_CANNOT_HOME. - - Note that maximal network performance cannot be achieved with - only one memory controller. - */ - uint8_t buffer_node_weights[NETIO_NUM_NODE_WEIGHTS]; - - /** Fixed virtual address for packet buffers. Only valid when - ::NETIO_FIXED_BUFFER_VA is specified in @ref flags; see the - description of that flag for details. - */ - void* fixed_buffer_va; - - /** - Maximum number of outstanding send packet requests. This value is - only relevant when an EPP is in use; it determines the number of - slots in the EPP's outgoing packet queue which this tile is allowed - to consume, and thus the number of packets which may be sent before - the sending tile must wait for an acknowledgment from the EPP. - Modifying this value is generally only helpful when using @ref - netio_send_packet_vector(), where it can help improve performance by - allowing a single vector send operation to process more packets. - Typically it is not specified, and the default, which divides the - outgoing packet slots evenly between all tiles on the chip, is used. - - If a registration asks for more outgoing packet queue slots than are - available, ::NETIO_TOOMANY_XMIT will be returned. The total number - of packet queue slots which are available for all tiles for each EPP - is subject to change, but is currently ::NETIO_TOTAL_SENDS_OUTSTANDING. - - - This value is ignored if ::NETIO_XMIT is not specified in flags. - If you want to specify a large value here for a specific tile, you are - advised to specify NETIO_NO_XMIT on other, non-transmitting tiles so - that they do not consume a default number of packet slots. Any tile - transmitting is required to have at least ::NETIO_MIN_SENDS_OUTSTANDING - slots allocated to it; values less than that will be silently - increased by the NetIO library. - */ - int num_sends_outstanding; -} -netio_input_config_t; - - -/** Registration flags; used in the @ref netio_input_config_t structure. - * @addtogroup setup - */ -/** @{ */ - -/** Fail a registration request if we can't put packet buffers - on the specified memory controllers. */ -#define NETIO_STRICT_HOMING 0x00000002 - -/** This application expects no tags on its L2 headers. */ -#define NETIO_TAG_NONE 0x00000004 - -/** This application expects Marvell extended tags on its L2 headers. */ -#define NETIO_TAG_MRVL 0x00000008 - -/** This application expects Broadcom tags on its L2 headers. */ -#define NETIO_TAG_BRCM 0x00000010 - -/** This registration may call routines which receive packets. */ -#define NETIO_RECV 0x00000020 - -/** This registration may not call routines which receive packets. */ -#define NETIO_NO_RECV 0x00000040 - -/** This registration may call routines which transmit packets. */ -#define NETIO_XMIT 0x00000080 - -/** This registration may call routines which transmit packets with - checksum acceleration. */ -#define NETIO_XMIT_CSUM 0x00000100 - -/** This registration may not call routines which transmit packets. */ -#define NETIO_NO_XMIT 0x00000200 - -/** This registration wants NetIO buffers mapped at an application-specified - virtual address. - - NetIO buffers are by default created by the TMC common memory facility, - which must be configured by a common ancestor of all processes sharing - a network interface. When this flag is specified, NetIO buffers are - instead mapped at an address chosen by the application (and specified - in @ref netio_input_config_t::fixed_buffer_va). This allows multiple - unrelated but cooperating processes to share a NetIO interface. - All processes sharing the same interface must specify this flag, - and all must specify the same fixed virtual address. - - @ref netio_input_config_t::fixed_buffer_va must be a - multiple of 16 MB, and the packet buffers will occupy @ref - netio_input_config_t::total_buffer_size bytes of virtual address - space, beginning at that address. If any of those virtual addresses - are currently occupied by other memory objects, like application or - shared library code or data, @ref netio_input_register() will return - ::NETIO_FAULT. While it is impossible to provide a fixed_buffer_va - which will work for all applications, a good first guess might be to - use 0xb0000000 minus @ref netio_input_config_t::total_buffer_size. - If that fails, it might be helpful to consult the running application's - virtual address description file (/proc/pid/maps) to see - which regions of virtual address space are available. - */ -#define NETIO_FIXED_BUFFER_VA 0x00000400 - -/** This registration call will not complete unless the network link - is up. The process will wait several seconds for this to happen (the - precise interval is link-dependent), but if the link does not come up, - ::NETIO_LINK_DOWN will be returned. This flag is the default if - ::NETIO_NOREQUIRE_LINK_UP is not specified. Note that this flag by - itself does not request that the link be brought up; that can be done - with the ::NETIO_AUTO_LINK_UPDN or ::NETIO_AUTO_LINK_UP flags (the - latter is the default if no NETIO_AUTO_LINK_xxx flags are specified), - or by explicitly setting the link's desired state via netio_set(). - If the link is not brought up by one of those methods, and this flag - is specified, the registration operation will return ::NETIO_LINK_DOWN. - This flag is ignored if it is specified along with ::NETIO_NO_XMIT and - ::NETIO_NO_RECV. See @ref link for more information on link - management. - */ -#define NETIO_REQUIRE_LINK_UP 0x00000800 - -/** This registration call will complete even if the network link is not up. - Whenever the link is not up, packets will not be sent or received: - netio_get_packet() will return ::NETIO_NOPKT once all queued packets - have been drained, and netio_send_packet() and similar routines will - return NETIO_QUEUE_FULL once the outgoing packet queue in the EPP - or the I/O shim is full. See @ref link for more information on link - management. - */ -#define NETIO_NOREQUIRE_LINK_UP 0x00001000 - -#ifndef __DOXYGEN__ -/* - * These are part of the implementation of the NETIO_AUTO_LINK_xxx flags, - * but should not be used directly by applications, and are thus not - * documented. - */ -#define _NETIO_AUTO_UP 0x00002000 -#define _NETIO_AUTO_DN 0x00004000 -#define _NETIO_AUTO_PRESENT 0x00008000 -#endif - -/** Set the desired state of the link to up, allowing any speeds which are - supported by the link hardware, as part of this registration operation. - Do not take down the link automatically. This is the default if - no other NETIO_AUTO_LINK_xxx flags are specified. This flag is ignored - if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV. - See @ref link for more information on link management. - */ -#define NETIO_AUTO_LINK_UP (_NETIO_AUTO_PRESENT | _NETIO_AUTO_UP) - -/** Set the desired state of the link to up, allowing any speeds which are - supported by the link hardware, as part of this registration operation. - Set the desired state of the link to down the next time no tiles are - registered for packet reception or transmission. This flag is ignored - if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV. - See @ref link for more information on link management. - */ -#define NETIO_AUTO_LINK_UPDN (_NETIO_AUTO_PRESENT | _NETIO_AUTO_UP | \ - _NETIO_AUTO_DN) - -/** Set the desired state of the link to down the next time no tiles are - registered for packet reception or transmission. This flag is ignored - if it is specified along with ::NETIO_NO_XMIT and ::NETIO_NO_RECV. - See @ref link for more information on link management. - */ -#define NETIO_AUTO_LINK_DN (_NETIO_AUTO_PRESENT | _NETIO_AUTO_DN) - -/** Do not bring up the link automatically as part of this registration - operation. Do not take down the link automatically. This flag - is ignored if it is specified along with ::NETIO_NO_XMIT and - ::NETIO_NO_RECV. See @ref link for more information on link management. - */ -#define NETIO_AUTO_LINK_NONE _NETIO_AUTO_PRESENT - - -/** Minimum number of receive packets. */ -#define NETIO_MIN_RECEIVE_PKTS 16 - -/** Lower bound on the maximum number of receive packets; may be higher - than this on some interfaces. */ -#define NETIO_MAX_RECEIVE_PKTS 128 - -/** Maximum number of send buffers, per packet size. */ -#define NETIO_MAX_SEND_BUFFERS 16 - -/** Number of EPP queue slots, and thus outstanding sends, per EPP. */ -#define NETIO_TOTAL_SENDS_OUTSTANDING 2015 - -/** Minimum number of EPP queue slots, and thus outstanding sends, per - * transmitting tile. */ -#define NETIO_MIN_SENDS_OUTSTANDING 16 - - -/**@}*/ - -#ifndef __DOXYGEN__ - -/** - * An object for providing Ethernet packets to a process. - */ -struct __netio_queue_impl_t; - -/** - * An object for managing the user end of a NetIO queue. - */ -struct __netio_queue_user_impl_t; - -#endif /* !__DOXYGEN__ */ - - -/** A netio_queue_t describes a NetIO communications endpoint. - * @ingroup setup - */ -typedef struct -{ -#ifdef __DOXYGEN__ - uint8_t opaque[8]; /**< This is an opaque structure. */ -#else - struct __netio_queue_impl_t* __system_part; /**< The system part. */ - struct __netio_queue_user_impl_t* __user_part; /**< The user part. */ -#ifdef _NETIO_PTHREAD - _netio_percpu_mutex_t lock; /**< Queue lock. */ -#endif -#endif -} -netio_queue_t; - - -/** - * @brief Packet send context. - * - * @ingroup egress - * - * Packet send context for use with netio_send_packet_prepare and _commit. - */ -typedef struct -{ -#ifdef __DOXYGEN__ - uint8_t opaque[44]; /**< This is an opaque structure. */ -#else - uint8_t flags; /**< Defined below */ - uint8_t datalen; /**< Number of valid words pointed to by data. */ - uint32_t request[9]; /**< Request to be sent to the EPP or shim. Note - that this is smaller than the 11-word maximum - request size, since some constant values are - not saved in the context. */ - uint32_t *data; /**< Data to be sent to the EPP or shim via IDN. */ -#endif -} -netio_send_pkt_context_t; - - -#ifndef __DOXYGEN__ -#define SEND_PKT_CTX_USE_EPP 1 /**< We're sending to an EPP. */ -#define SEND_PKT_CTX_SEND_CSUM 2 /**< Request includes a checksum. */ -#endif - -/** - * @brief Packet vector entry. - * - * @ingroup egress - * - * This data structure is used with netio_send_packet_vector() to send multiple - * packets with one NetIO call. The structure should be initialized by - * calling netio_pkt_vector_set(), rather than by setting the fields - * directly. - * - * This structure is guaranteed to be a power of two in size, no - * bigger than one L2 cache line, and to be aligned modulo its size. - */ -typedef struct -#ifndef __DOXYGEN__ -__attribute__((aligned(8))) -#endif -{ - /** Reserved for use by the user application. When initialized with - * the netio_set_pkt_vector_entry() function, this field is guaranteed - * to be visible to readers only after all other fields are already - * visible. This way it can be used as a valid flag or generation - * counter. */ - uint8_t user_data; - - /* Structure members below this point should not be accessed directly by - * applications, as they may change in the future. */ - - /** Low 8 bits of the packet address to send. The high bits are - * acquired from the 'handle' field. */ - uint8_t buffer_address_low; - - /** Number of bytes to transmit. */ - uint16_t size; - - /** The raw handle from a netio_pkt_t. If this is NETIO_PKT_HANDLE_NONE, - * this vector entry will be skipped and no packet will be transmitted. */ - netio_pkt_handle_t handle; -} -netio_pkt_vector_entry_t; - - -/** - * @brief Initialize fields in a packet vector entry. - * - * @ingroup egress - * - * @param[out] v Pointer to the vector entry to be initialized. - * @param[in] pkt Packet to be transmitted when the vector entry is passed to - * netio_send_packet_vector(). Note that the packet's attributes - * (e.g., its L2 offset and length) are captured at the time this - * routine is called; subsequent changes in those attributes will not - * be reflected in the packet which is actually transmitted. - * Changes in the packet's contents, however, will be so reflected. - * If this is NULL, no packet will be transmitted. - * @param[in] user_data User data to be set in the vector entry. - * This function guarantees that the "user_data" field will become - * visible to a reader only after all other fields have become visible. - * This allows a structure in a ring buffer to be written and read - * by a polling reader without any locks or other synchronization. - */ -static __inline void -netio_pkt_vector_set(volatile netio_pkt_vector_entry_t* v, netio_pkt_t* pkt, - uint8_t user_data) -{ - if (pkt) - { - if (NETIO_PKT_IS_MINIMAL(pkt)) - { - netio_pkt_minimal_metadata_t* mmd = - (netio_pkt_minimal_metadata_t*) &pkt->__metadata; - v->buffer_address_low = (uintptr_t) NETIO_PKT_L2_DATA_MM(mmd, pkt) & 0xFF; - v->size = NETIO_PKT_L2_LENGTH_MM(mmd, pkt); - } - else - { - netio_pkt_metadata_t* mda = &pkt->__metadata; - v->buffer_address_low = (uintptr_t) NETIO_PKT_L2_DATA_M(mda, pkt) & 0xFF; - v->size = NETIO_PKT_L2_LENGTH_M(mda, pkt); - } - v->handle.word = pkt->__packet.word; - } - else - { - v->handle.word = 0; /* Set handle to NETIO_PKT_HANDLE_NONE. */ - } - - __asm__("" : : : "memory"); - - v->user_data = user_data; -} - - -/** - * Flags and structures for @ref netio_get() and @ref netio_set(). - * @ingroup config - */ - -/** @{ */ -/** Parameter class; addr is a NETIO_PARAM_xxx value. */ -#define NETIO_PARAM 0 -/** Interface MAC address. This address is only valid with @ref netio_get(). - * The value is a 6-byte MAC address. Depending upon the overall system - * design, a MAC address may or may not be available for each interface. */ -#define NETIO_PARAM_MAC 0 - -/** Determine whether to suspend output on the receipt of pause frames. - * If the value is nonzero, the I/O shim will suspend output when a pause - * frame is received. If the value is zero, pause frames will be ignored. */ -#define NETIO_PARAM_PAUSE_IN 1 - -/** Determine whether to send pause frames if the I/O shim packet FIFOs are - * nearly full. If the value is zero, pause frames are not sent. If - * the value is nonzero, it is the delay value which will be sent in any - * pause frames which are output, in units of 512 bit times. */ -#define NETIO_PARAM_PAUSE_OUT 2 - -/** Jumbo frame support. The value is a 4-byte integer. If the value is - * nonzero, the MAC will accept frames of up to 10240 bytes. If the value - * is zero, the MAC will only accept frames of up to 1544 bytes. */ -#define NETIO_PARAM_JUMBO 3 - -/** I/O shim's overflow statistics register. The value is two 16-bit integers. - * The first 16-bit value (or the low 16 bits, if the value is treated as a - * 32-bit number) is the count of packets which were completely dropped and - * not delivered by the shim. The second 16-bit value (or the high 16 bits, - * if the value is treated as a 32-bit number) is the count of packets - * which were truncated and thus only partially delivered by the shim. This - * register is automatically reset to zero after it has been read. - */ -#define NETIO_PARAM_OVERFLOW 4 - -/** IPP statistics. This address is only valid with @ref netio_get(). The - * value is a netio_stat_t structure. Unlike the I/O shim statistics, the - * IPP statistics are not all reset to zero on read; see the description - * of the netio_stat_t for details. */ -#define NETIO_PARAM_STAT 5 - -/** Possible link state. The value is a combination of "NETIO_LINK_xxx" - * flags. With @ref netio_get(), this will indicate which flags are - * actually supported by the hardware. - * - * For historical reasons, specifying this value to netio_set() will have - * the same behavior as using ::NETIO_PARAM_LINK_CONFIG, but this usage is - * discouraged. - */ -#define NETIO_PARAM_LINK_POSSIBLE_STATE 6 - -/** Link configuration. The value is a combination of "NETIO_LINK_xxx" flags. - * With @ref netio_set(), this will attempt to immediately bring up the - * link using whichever of the requested flags are supported by the - * hardware, or take down the link if the flags are zero; if this is - * not possible, an error will be returned. Many programs will want - * to use ::NETIO_PARAM_LINK_DESIRED_STATE instead. - * - * For historical reasons, specifying this value to netio_get() will - * have the same behavior as using ::NETIO_PARAM_LINK_POSSIBLE_STATE, - * but this usage is discouraged. - */ -#define NETIO_PARAM_LINK_CONFIG NETIO_PARAM_LINK_POSSIBLE_STATE - -/** Current link state. This address is only valid with @ref netio_get(). - * The value is zero or more of the "NETIO_LINK_xxx" flags, ORed together. - * If the link is down, the value ANDed with NETIO_LINK_SPEED will be - * zero; if the link is up, the value ANDed with NETIO_LINK_SPEED will - * result in exactly one of the NETIO_LINK_xxx values, indicating the - * current speed. */ -#define NETIO_PARAM_LINK_CURRENT_STATE 7 - -/** Variant symbol for current state, retained for compatibility with - * pre-MDE-2.1 programs. */ -#define NETIO_PARAM_LINK_STATUS NETIO_PARAM_LINK_CURRENT_STATE - -/** Packet Coherence protocol. This address is only valid with @ref netio_get(). - * The value is nonzero if the interface is configured for cache-coherent DMA. - */ -#define NETIO_PARAM_COHERENT 8 - -/** Desired link state. The value is a conbination of "NETIO_LINK_xxx" - * flags, which specify the desired state for the link. With @ref - * netio_set(), this will, in the background, attempt to bring up the link - * using whichever of the requested flags are reasonable, or take down the - * link if the flags are zero. The actual link up or down operation may - * happen after this call completes. If the link state changes in the - * future, the system will continue to try to get back to the desired link - * state; for instance, if the link is brought up successfully, and then - * the network cable is disconnected, the link will go down. However, the - * desired state of the link is still up, so if the cable is reconnected, - * the link will be brought up again. - * - * With @ref netio_get(), this will indicate the desired state for the - * link, as set with a previous netio_set() call, or implicitly by a - * netio_input_register() or netio_input_unregister() operation. This may - * not reflect the current state of the link; to get that, use - * ::NETIO_PARAM_LINK_CURRENT_STATE. */ -#define NETIO_PARAM_LINK_DESIRED_STATE 9 - -/** NetIO statistics structure. Retrieved using the ::NETIO_PARAM_STAT - * address passed to @ref netio_get(). */ -typedef struct -{ - /** Number of packets which have been received by the IPP and forwarded - * to a tile's receive queue for processing. This value wraps at its - * maximum, and is not cleared upon read. */ - uint32_t packets_received; - - /** Number of packets which have been dropped by the IPP, because they could - * not be received, or could not be forwarded to a tile. The former happens - * when the IPP does not have a free packet buffer of suitable size for an - * incoming frame. The latter happens when all potential destination tiles - * for a packet, as defined by the group, bucket, and queue configuration, - * have full receive queues. This value wraps at its maximum, and is not - * cleared upon read. */ - uint32_t packets_dropped; - - /* - * Note: the #defines after each of the following four one-byte values - * denote their location within the third word of the netio_stat_t. They - * are intended for use only by the IPP implementation and are thus omitted - * from the Doxygen output. - */ - - /** Number of packets dropped because no worker was able to accept a new - * packet. This value saturates at its maximum, and is cleared upon - * read. */ - uint8_t drops_no_worker; -#ifndef __DOXYGEN__ -#define NETIO_STAT_DROPS_NO_WORKER 0 -#endif - - /** Number of packets dropped because no small buffers were available. - * This value saturates at its maximum, and is cleared upon read. */ - uint8_t drops_no_smallbuf; -#ifndef __DOXYGEN__ -#define NETIO_STAT_DROPS_NO_SMALLBUF 1 -#endif - - /** Number of packets dropped because no large buffers were available. - * This value saturates at its maximum, and is cleared upon read. */ - uint8_t drops_no_largebuf; -#ifndef __DOXYGEN__ -#define NETIO_STAT_DROPS_NO_LARGEBUF 2 -#endif - - /** Number of packets dropped because no jumbo buffers were available. - * This value saturates at its maximum, and is cleared upon read. */ - uint8_t drops_no_jumbobuf; -#ifndef __DOXYGEN__ -#define NETIO_STAT_DROPS_NO_JUMBOBUF 3 -#endif -} -netio_stat_t; - - -/** Link can run, should run, or is running at 10 Mbps. */ -#define NETIO_LINK_10M 0x01 - -/** Link can run, should run, or is running at 100 Mbps. */ -#define NETIO_LINK_100M 0x02 - -/** Link can run, should run, or is running at 1 Gbps. */ -#define NETIO_LINK_1G 0x04 - -/** Link can run, should run, or is running at 10 Gbps. */ -#define NETIO_LINK_10G 0x08 - -/** Link should run at the highest speed supported by the link and by - * the device connected to the link. Only usable as a value for - * the link's desired state; never returned as a value for the current - * or possible states. */ -#define NETIO_LINK_ANYSPEED 0x10 - -/** All legal link speeds. */ -#define NETIO_LINK_SPEED (NETIO_LINK_10M | \ - NETIO_LINK_100M | \ - NETIO_LINK_1G | \ - NETIO_LINK_10G | \ - NETIO_LINK_ANYSPEED) - - -/** MAC register class. Addr is a register offset within the MAC. - * Registers within the XGbE and GbE MACs are documented in the Tile - * Processor I/O Device Guide (UG104). MAC registers start at address - * 0x4000, and do not include the MAC_INTERFACE registers. */ -#define NETIO_MAC 1 - -/** MDIO register class (IEEE 802.3 clause 22 format). Addr is the "addr" - * member of a netio_mdio_addr_t structure. */ -#define NETIO_MDIO 2 - -/** MDIO register class (IEEE 802.3 clause 45 format). Addr is the "addr" - * member of a netio_mdio_addr_t structure. */ -#define NETIO_MDIO_CLAUSE45 3 - -/** NetIO MDIO address type. Retrieved or provided using the ::NETIO_MDIO - * address passed to @ref netio_get() or @ref netio_set(). */ -typedef union -{ - struct - { - unsigned int reg:16; /**< MDIO register offset. For clause 22 access, - must be less than 32. */ - unsigned int phy:5; /**< Which MDIO PHY to access. */ - unsigned int dev:5; /**< Which MDIO device to access within that PHY. - Applicable for clause 45 access only; ignored - for clause 22 access. */ - } - bits; /**< Container for bitfields. */ - uint64_t addr; /**< Value to pass to @ref netio_get() or - * @ref netio_set(). */ -} -netio_mdio_addr_t; - -/** @} */ - -#endif /* __NETIO_INTF_H__ */ diff --git a/arch/tile/include/hv/syscall_public.h b/arch/tile/include/hv/syscall_public.h deleted file mode 100644 index 9cc0837e69fd..000000000000 --- a/arch/tile/include/hv/syscall_public.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file syscall.h - * Indices for the hypervisor system calls that are intended to be called - * directly, rather than only through hypervisor-generated "glue" code. - */ - -#ifndef _SYS_HV_INCLUDE_SYSCALL_PUBLIC_H -#define _SYS_HV_INCLUDE_SYSCALL_PUBLIC_H - -/** Fast syscall flag bit location. When this bit is set, the hypervisor - * handles the syscall specially. - */ -#define HV_SYS_FAST_SHIFT 14 - -/** Fast syscall flag bit mask. */ -#define HV_SYS_FAST_MASK (1 << HV_SYS_FAST_SHIFT) - -/** Bit location for flagging fast syscalls that can be called from PL0. */ -#define HV_SYS_FAST_PLO_SHIFT 13 - -/** Fast syscall allowing PL0 bit mask. */ -#define HV_SYS_FAST_PL0_MASK (1 << HV_SYS_FAST_PLO_SHIFT) - -/** Perform an MF that waits for all victims to reach DRAM. */ -#define HV_SYS_fence_incoherent (51 | HV_SYS_FAST_MASK \ - | HV_SYS_FAST_PL0_MASK) - -#endif /* !_SYS_HV_INCLUDE_SYSCALL_PUBLIC_H */ diff --git a/arch/tile/include/uapi/arch/abi.h b/arch/tile/include/uapi/arch/abi.h deleted file mode 100644 index df161a484730..000000000000 --- a/arch/tile/include/uapi/arch/abi.h +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file - * - * ABI-related register definitions. - */ - -#ifndef __ARCH_ABI_H__ - -#ifndef __tile__ /* support uncommon use of arch headers in non-tile builds */ -# include -# define __INT_REG_BITS CHIP_WORD_SIZE() -#endif - -#include - -/* __need_int_reg_t is deprecated: just include */ -#ifndef __need_int_reg_t - -#define __ARCH_ABI_H__ - -#ifndef __ASSEMBLER__ -/** Unsigned type that can hold a register. */ -typedef __uint_reg_t uint_reg_t; - -/** Signed type that can hold a register. */ -typedef __int_reg_t int_reg_t; -#endif - -/** String prefix to use for printf(). */ -#define INT_REG_FMT __INT_REG_FMT - -/** Number of bits in a register. */ -#define INT_REG_BITS __INT_REG_BITS - - -/* Registers 0 - 55 are "normal", but some perform special roles. */ - -#define TREG_FP 52 /**< Frame pointer. */ -#define TREG_TP 53 /**< Thread pointer. */ -#define TREG_SP 54 /**< Stack pointer. */ -#define TREG_LR 55 /**< Link to calling function PC. */ - -/** Index of last normal general-purpose register. */ -#define TREG_LAST_GPR 55 - -/* Registers 56 - 62 are "special" network registers. */ - -#define TREG_SN 56 /**< Static network access. */ -#define TREG_IDN0 57 /**< IDN demux 0 access. */ -#define TREG_IDN1 58 /**< IDN demux 1 access. */ -#define TREG_UDN0 59 /**< UDN demux 0 access. */ -#define TREG_UDN1 60 /**< UDN demux 1 access. */ -#define TREG_UDN2 61 /**< UDN demux 2 access. */ -#define TREG_UDN3 62 /**< UDN demux 3 access. */ - -/* Register 63 is the "special" zero register. */ - -#define TREG_ZERO 63 /**< "Zero" register; always reads as "0". */ - - -/** By convention, this register is used to hold the syscall number. */ -#define TREG_SYSCALL_NR 10 - -/** Name of register that holds the syscall number, for use in assembly. */ -#define TREG_SYSCALL_NR_NAME r10 - - -/** - * The ABI requires callers to allocate a caller state save area of - * this many bytes at the bottom of each stack frame. - */ -#define C_ABI_SAVE_AREA_SIZE (2 * (INT_REG_BITS / 8)) - -/** - * The operand to an 'info' opcode directing the backtracer to not - * try to find the calling frame. - */ -#define INFO_OP_CANNOT_BACKTRACE 2 - - -#endif /* !__need_int_reg_t */ - -/* Make sure we later can get all the definitions and declarations. */ -#undef __need_int_reg_t - -#endif /* !__ARCH_ABI_H__ */ diff --git a/arch/tile/include/uapi/arch/chip.h b/arch/tile/include/uapi/arch/chip.h deleted file mode 100644 index 7f55c6856c89..000000000000 --- a/arch/tile/include/uapi/arch/chip.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#if __tile_chip__ == 1 -#include -#elif defined(__tilegx__) -#include -#else -#error Unexpected Tilera chip type -#endif diff --git a/arch/tile/include/uapi/arch/chip_tilegx.h b/arch/tile/include/uapi/arch/chip_tilegx.h deleted file mode 100644 index c2a71a43b21c..000000000000 --- a/arch/tile/include/uapi/arch/chip_tilegx.h +++ /dev/null @@ -1,259 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* - * @file - * Global header file. - * This header file specifies defines for TILE-Gx. - */ - -#ifndef __ARCH_CHIP_H__ -#define __ARCH_CHIP_H__ - -/** Specify chip version. - * When possible, prefer the CHIP_xxx symbols below for future-proofing. - * This is intended for cross-compiling; native compilation should - * use the predefined __tile_chip__ symbol. - */ -#define TILE_CHIP 10 - -/** Specify chip revision. - * This provides for the case of a respin of a particular chip type; - * the normal value for this symbol is "0". - * This is intended for cross-compiling; native compilation should - * use the predefined __tile_chip_rev__ symbol. - */ -#define TILE_CHIP_REV 0 - -/** The name of this architecture. */ -#define CHIP_ARCH_NAME "tilegx" - -/** The ELF e_machine type for binaries for this chip. */ -#define CHIP_ELF_TYPE() EM_TILEGX - -/** The alternate ELF e_machine type for binaries for this chip. */ -#define CHIP_COMPAT_ELF_TYPE() 0x2597 - -/** What is the native word size of the machine? */ -#define CHIP_WORD_SIZE() 64 - -/** How many bits of a virtual address are used. Extra bits must be - * the sign extension of the low bits. - */ -#define CHIP_VA_WIDTH() 42 - -/** How many bits are in a physical address? */ -#define CHIP_PA_WIDTH() 40 - -/** Size of the L2 cache, in bytes. */ -#define CHIP_L2_CACHE_SIZE() 262144 - -/** Log size of an L2 cache line in bytes. */ -#define CHIP_L2_LOG_LINE_SIZE() 6 - -/** Size of an L2 cache line, in bytes. */ -#define CHIP_L2_LINE_SIZE() (1 << CHIP_L2_LOG_LINE_SIZE()) - -/** Associativity of the L2 cache. */ -#define CHIP_L2_ASSOC() 8 - -/** Size of the L1 data cache, in bytes. */ -#define CHIP_L1D_CACHE_SIZE() 32768 - -/** Log size of an L1 data cache line in bytes. */ -#define CHIP_L1D_LOG_LINE_SIZE() 6 - -/** Size of an L1 data cache line, in bytes. */ -#define CHIP_L1D_LINE_SIZE() (1 << CHIP_L1D_LOG_LINE_SIZE()) - -/** Associativity of the L1 data cache. */ -#define CHIP_L1D_ASSOC() 2 - -/** Size of the L1 instruction cache, in bytes. */ -#define CHIP_L1I_CACHE_SIZE() 32768 - -/** Log size of an L1 instruction cache line in bytes. */ -#define CHIP_L1I_LOG_LINE_SIZE() 6 - -/** Size of an L1 instruction cache line, in bytes. */ -#define CHIP_L1I_LINE_SIZE() (1 << CHIP_L1I_LOG_LINE_SIZE()) - -/** Associativity of the L1 instruction cache. */ -#define CHIP_L1I_ASSOC() 2 - -/** Stride with which flush instructions must be issued. */ -#define CHIP_FLUSH_STRIDE() CHIP_L2_LINE_SIZE() - -/** Stride with which inv instructions must be issued. */ -#define CHIP_INV_STRIDE() CHIP_L2_LINE_SIZE() - -/** Stride with which finv instructions must be issued. */ -#define CHIP_FINV_STRIDE() CHIP_L2_LINE_SIZE() - -/** Can the local cache coherently cache data that is homed elsewhere? */ -#define CHIP_HAS_COHERENT_LOCAL_CACHE() 1 - -/** How many simultaneous outstanding victims can the L2 cache have? */ -#define CHIP_MAX_OUTSTANDING_VICTIMS() 128 - -/** Does the TLB support the NC and NOALLOC bits? */ -#define CHIP_HAS_NC_AND_NOALLOC_BITS() 1 - -/** Does the chip support hash-for-home caching? */ -#define CHIP_HAS_CBOX_HOME_MAP() 1 - -/** Number of entries in the chip's home map tables. */ -#define CHIP_CBOX_HOME_MAP_SIZE() 128 - -/** Do uncacheable requests miss in the cache regardless of whether - * there is matching data? */ -#define CHIP_HAS_ENFORCED_UNCACHEABLE_REQUESTS() 1 - -/** Does the mf instruction wait for victims? */ -#define CHIP_HAS_MF_WAITS_FOR_VICTIMS() 0 - -/** Does the chip have an "inv" instruction that doesn't also flush? */ -#define CHIP_HAS_INV() 1 - -/** Does the chip have a "wh64" instruction? */ -#define CHIP_HAS_WH64() 1 - -/** Does this chip have a 'dword_align' instruction? */ -#define CHIP_HAS_DWORD_ALIGN() 0 - -/** Number of performance counters. */ -#define CHIP_PERFORMANCE_COUNTERS() 4 - -/** Does this chip have auxiliary performance counters? */ -#define CHIP_HAS_AUX_PERF_COUNTERS() 1 - -/** Is the CBOX_MSR1 SPR supported? */ -#define CHIP_HAS_CBOX_MSR1() 0 - -/** Is the TILE_RTF_HWM SPR supported? */ -#define CHIP_HAS_TILE_RTF_HWM() 1 - -/** Is the TILE_WRITE_PENDING SPR supported? */ -#define CHIP_HAS_TILE_WRITE_PENDING() 0 - -/** Is the PROC_STATUS SPR supported? */ -#define CHIP_HAS_PROC_STATUS_SPR() 1 - -/** Is the DSTREAM_PF SPR supported? */ -#define CHIP_HAS_DSTREAM_PF() 1 - -/** Log of the number of mshims we have. */ -#define CHIP_LOG_NUM_MSHIMS() 2 - -/** Are the bases of the interrupt vector areas fixed? */ -#define CHIP_HAS_FIXED_INTVEC_BASE() 0 - -/** Are the interrupt masks split up into 2 SPRs? */ -#define CHIP_HAS_SPLIT_INTR_MASK() 0 - -/** Is the cycle count split up into 2 SPRs? */ -#define CHIP_HAS_SPLIT_CYCLE() 0 - -/** Does the chip have a static network? */ -#define CHIP_HAS_SN() 0 - -/** Does the chip have a static network processor? */ -#define CHIP_HAS_SN_PROC() 0 - -/** Size of the L1 static network processor instruction cache, in bytes. */ -/* #define CHIP_L1SNI_CACHE_SIZE() -- does not apply to chip 10 */ - -/** Does the chip have DMA support in each tile? */ -#define CHIP_HAS_TILE_DMA() 0 - -/** Does the chip have the second revision of the directly accessible - * dynamic networks? This encapsulates a number of characteristics, - * including the absence of the catch-all, the absence of inline message - * tags, the absence of support for network context-switching, and so on. - */ -#define CHIP_HAS_REV1_XDN() 1 - -/** Does the chip have cmpexch and similar (fetchadd, exch, etc.)? */ -#define CHIP_HAS_CMPEXCH() 1 - -/** Does the chip have memory-mapped I/O support? */ -#define CHIP_HAS_MMIO() 1 - -/** Does the chip have post-completion interrupts? */ -#define CHIP_HAS_POST_COMPLETION_INTERRUPTS() 1 - -/** Does the chip have native single step support? */ -#define CHIP_HAS_SINGLE_STEP() 1 - -#ifndef __OPEN_SOURCE__ /* features only relevant to hypervisor-level code */ - -/** How many entries are present in the instruction TLB? */ -#define CHIP_ITLB_ENTRIES() 16 - -/** How many entries are present in the data TLB? */ -#define CHIP_DTLB_ENTRIES() 32 - -/** How many MAF entries does the XAUI shim have? */ -#define CHIP_XAUI_MAF_ENTRIES() 32 - -/** Does the memory shim have a source-id table? */ -#define CHIP_HAS_MSHIM_SRCID_TABLE() 0 - -/** Does the L1 instruction cache clear on reset? */ -#define CHIP_HAS_L1I_CLEAR_ON_RESET() 1 - -/** Does the chip come out of reset with valid coordinates on all tiles? - * Note that if defined, this also implies that the upper left is 1,1. - */ -#define CHIP_HAS_VALID_TILE_COORD_RESET() 1 - -/** Does the chip have unified packet formats? */ -#define CHIP_HAS_UNIFIED_PACKET_FORMATS() 1 - -/** Does the chip support write reordering? */ -#define CHIP_HAS_WRITE_REORDERING() 1 - -/** Does the chip support Y-X routing as well as X-Y? */ -#define CHIP_HAS_Y_X_ROUTING() 1 - -/** Is INTCTRL_3 managed with the correct MPL? */ -#define CHIP_HAS_INTCTRL_3_STATUS_FIX() 1 - -/** Is it possible to configure the chip to be big-endian? */ -#define CHIP_HAS_BIG_ENDIAN_CONFIG() 1 - -/** Is the CACHE_RED_WAY_OVERRIDDEN SPR supported? */ -#define CHIP_HAS_CACHE_RED_WAY_OVERRIDDEN() 0 - -/** Is the DIAG_TRACE_WAY SPR supported? */ -#define CHIP_HAS_DIAG_TRACE_WAY() 0 - -/** Is the MEM_STRIPE_CONFIG SPR supported? */ -#define CHIP_HAS_MEM_STRIPE_CONFIG() 1 - -/** Are the TLB_PERF SPRs supported? */ -#define CHIP_HAS_TLB_PERF() 1 - -/** Is the VDN_SNOOP_SHIM_CTL SPR supported? */ -#define CHIP_HAS_VDN_SNOOP_SHIM_CTL() 0 - -/** Does the chip support rev1 DMA packets? */ -#define CHIP_HAS_REV1_DMA_PACKETS() 1 - -/** Does the chip have an IPI shim? */ -#define CHIP_HAS_IPI() 1 - -#endif /* !__OPEN_SOURCE__ */ -#endif /* __ARCH_CHIP_H__ */ diff --git a/arch/tile/include/uapi/arch/chip_tilepro.h b/arch/tile/include/uapi/arch/chip_tilepro.h deleted file mode 100644 index a8a3ed144dfe..000000000000 --- a/arch/tile/include/uapi/arch/chip_tilepro.h +++ /dev/null @@ -1,259 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* - * @file - * Global header file. - * This header file specifies defines for TILEPro. - */ - -#ifndef __ARCH_CHIP_H__ -#define __ARCH_CHIP_H__ - -/** Specify chip version. - * When possible, prefer the CHIP_xxx symbols below for future-proofing. - * This is intended for cross-compiling; native compilation should - * use the predefined __tile_chip__ symbol. - */ -#define TILE_CHIP 1 - -/** Specify chip revision. - * This provides for the case of a respin of a particular chip type; - * the normal value for this symbol is "0". - * This is intended for cross-compiling; native compilation should - * use the predefined __tile_chip_rev__ symbol. - */ -#define TILE_CHIP_REV 0 - -/** The name of this architecture. */ -#define CHIP_ARCH_NAME "tilepro" - -/** The ELF e_machine type for binaries for this chip. */ -#define CHIP_ELF_TYPE() EM_TILEPRO - -/** The alternate ELF e_machine type for binaries for this chip. */ -#define CHIP_COMPAT_ELF_TYPE() 0x2507 - -/** What is the native word size of the machine? */ -#define CHIP_WORD_SIZE() 32 - -/** How many bits of a virtual address are used. Extra bits must be - * the sign extension of the low bits. - */ -#define CHIP_VA_WIDTH() 32 - -/** How many bits are in a physical address? */ -#define CHIP_PA_WIDTH() 36 - -/** Size of the L2 cache, in bytes. */ -#define CHIP_L2_CACHE_SIZE() 65536 - -/** Log size of an L2 cache line in bytes. */ -#define CHIP_L2_LOG_LINE_SIZE() 6 - -/** Size of an L2 cache line, in bytes. */ -#define CHIP_L2_LINE_SIZE() (1 << CHIP_L2_LOG_LINE_SIZE()) - -/** Associativity of the L2 cache. */ -#define CHIP_L2_ASSOC() 4 - -/** Size of the L1 data cache, in bytes. */ -#define CHIP_L1D_CACHE_SIZE() 8192 - -/** Log size of an L1 data cache line in bytes. */ -#define CHIP_L1D_LOG_LINE_SIZE() 4 - -/** Size of an L1 data cache line, in bytes. */ -#define CHIP_L1D_LINE_SIZE() (1 << CHIP_L1D_LOG_LINE_SIZE()) - -/** Associativity of the L1 data cache. */ -#define CHIP_L1D_ASSOC() 2 - -/** Size of the L1 instruction cache, in bytes. */ -#define CHIP_L1I_CACHE_SIZE() 16384 - -/** Log size of an L1 instruction cache line in bytes. */ -#define CHIP_L1I_LOG_LINE_SIZE() 6 - -/** Size of an L1 instruction cache line, in bytes. */ -#define CHIP_L1I_LINE_SIZE() (1 << CHIP_L1I_LOG_LINE_SIZE()) - -/** Associativity of the L1 instruction cache. */ -#define CHIP_L1I_ASSOC() 1 - -/** Stride with which flush instructions must be issued. */ -#define CHIP_FLUSH_STRIDE() CHIP_L2_LINE_SIZE() - -/** Stride with which inv instructions must be issued. */ -#define CHIP_INV_STRIDE() CHIP_L2_LINE_SIZE() - -/** Stride with which finv instructions must be issued. */ -#define CHIP_FINV_STRIDE() CHIP_L2_LINE_SIZE() - -/** Can the local cache coherently cache data that is homed elsewhere? */ -#define CHIP_HAS_COHERENT_LOCAL_CACHE() 1 - -/** How many simultaneous outstanding victims can the L2 cache have? */ -#define CHIP_MAX_OUTSTANDING_VICTIMS() 4 - -/** Does the TLB support the NC and NOALLOC bits? */ -#define CHIP_HAS_NC_AND_NOALLOC_BITS() 1 - -/** Does the chip support hash-for-home caching? */ -#define CHIP_HAS_CBOX_HOME_MAP() 1 - -/** Number of entries in the chip's home map tables. */ -#define CHIP_CBOX_HOME_MAP_SIZE() 64 - -/** Do uncacheable requests miss in the cache regardless of whether - * there is matching data? */ -#define CHIP_HAS_ENFORCED_UNCACHEABLE_REQUESTS() 1 - -/** Does the mf instruction wait for victims? */ -#define CHIP_HAS_MF_WAITS_FOR_VICTIMS() 0 - -/** Does the chip have an "inv" instruction that doesn't also flush? */ -#define CHIP_HAS_INV() 1 - -/** Does the chip have a "wh64" instruction? */ -#define CHIP_HAS_WH64() 1 - -/** Does this chip have a 'dword_align' instruction? */ -#define CHIP_HAS_DWORD_ALIGN() 1 - -/** Number of performance counters. */ -#define CHIP_PERFORMANCE_COUNTERS() 4 - -/** Does this chip have auxiliary performance counters? */ -#define CHIP_HAS_AUX_PERF_COUNTERS() 1 - -/** Is the CBOX_MSR1 SPR supported? */ -#define CHIP_HAS_CBOX_MSR1() 1 - -/** Is the TILE_RTF_HWM SPR supported? */ -#define CHIP_HAS_TILE_RTF_HWM() 1 - -/** Is the TILE_WRITE_PENDING SPR supported? */ -#define CHIP_HAS_TILE_WRITE_PENDING() 1 - -/** Is the PROC_STATUS SPR supported? */ -#define CHIP_HAS_PROC_STATUS_SPR() 1 - -/** Is the DSTREAM_PF SPR supported? */ -#define CHIP_HAS_DSTREAM_PF() 0 - -/** Log of the number of mshims we have. */ -#define CHIP_LOG_NUM_MSHIMS() 2 - -/** Are the bases of the interrupt vector areas fixed? */ -#define CHIP_HAS_FIXED_INTVEC_BASE() 1 - -/** Are the interrupt masks split up into 2 SPRs? */ -#define CHIP_HAS_SPLIT_INTR_MASK() 1 - -/** Is the cycle count split up into 2 SPRs? */ -#define CHIP_HAS_SPLIT_CYCLE() 1 - -/** Does the chip have a static network? */ -#define CHIP_HAS_SN() 1 - -/** Does the chip have a static network processor? */ -#define CHIP_HAS_SN_PROC() 0 - -/** Size of the L1 static network processor instruction cache, in bytes. */ -/* #define CHIP_L1SNI_CACHE_SIZE() -- does not apply to chip 1 */ - -/** Does the chip have DMA support in each tile? */ -#define CHIP_HAS_TILE_DMA() 1 - -/** Does the chip have the second revision of the directly accessible - * dynamic networks? This encapsulates a number of characteristics, - * including the absence of the catch-all, the absence of inline message - * tags, the absence of support for network context-switching, and so on. - */ -#define CHIP_HAS_REV1_XDN() 0 - -/** Does the chip have cmpexch and similar (fetchadd, exch, etc.)? */ -#define CHIP_HAS_CMPEXCH() 0 - -/** Does the chip have memory-mapped I/O support? */ -#define CHIP_HAS_MMIO() 0 - -/** Does the chip have post-completion interrupts? */ -#define CHIP_HAS_POST_COMPLETION_INTERRUPTS() 0 - -/** Does the chip have native single step support? */ -#define CHIP_HAS_SINGLE_STEP() 0 - -#ifndef __OPEN_SOURCE__ /* features only relevant to hypervisor-level code */ - -/** How many entries are present in the instruction TLB? */ -#define CHIP_ITLB_ENTRIES() 16 - -/** How many entries are present in the data TLB? */ -#define CHIP_DTLB_ENTRIES() 16 - -/** How many MAF entries does the XAUI shim have? */ -#define CHIP_XAUI_MAF_ENTRIES() 32 - -/** Does the memory shim have a source-id table? */ -#define CHIP_HAS_MSHIM_SRCID_TABLE() 0 - -/** Does the L1 instruction cache clear on reset? */ -#define CHIP_HAS_L1I_CLEAR_ON_RESET() 1 - -/** Does the chip come out of reset with valid coordinates on all tiles? - * Note that if defined, this also implies that the upper left is 1,1. - */ -#define CHIP_HAS_VALID_TILE_COORD_RESET() 1 - -/** Does the chip have unified packet formats? */ -#define CHIP_HAS_UNIFIED_PACKET_FORMATS() 1 - -/** Does the chip support write reordering? */ -#define CHIP_HAS_WRITE_REORDERING() 1 - -/** Does the chip support Y-X routing as well as X-Y? */ -#define CHIP_HAS_Y_X_ROUTING() 1 - -/** Is INTCTRL_3 managed with the correct MPL? */ -#define CHIP_HAS_INTCTRL_3_STATUS_FIX() 1 - -/** Is it possible to configure the chip to be big-endian? */ -#define CHIP_HAS_BIG_ENDIAN_CONFIG() 1 - -/** Is the CACHE_RED_WAY_OVERRIDDEN SPR supported? */ -#define CHIP_HAS_CACHE_RED_WAY_OVERRIDDEN() 1 - -/** Is the DIAG_TRACE_WAY SPR supported? */ -#define CHIP_HAS_DIAG_TRACE_WAY() 1 - -/** Is the MEM_STRIPE_CONFIG SPR supported? */ -#define CHIP_HAS_MEM_STRIPE_CONFIG() 1 - -/** Are the TLB_PERF SPRs supported? */ -#define CHIP_HAS_TLB_PERF() 1 - -/** Is the VDN_SNOOP_SHIM_CTL SPR supported? */ -#define CHIP_HAS_VDN_SNOOP_SHIM_CTL() 1 - -/** Does the chip support rev1 DMA packets? */ -#define CHIP_HAS_REV1_DMA_PACKETS() 1 - -/** Does the chip have an IPI shim? */ -#define CHIP_HAS_IPI() 0 - -#endif /* !__OPEN_SOURCE__ */ -#endif /* __ARCH_CHIP_H__ */ diff --git a/arch/tile/include/uapi/arch/icache.h b/arch/tile/include/uapi/arch/icache.h deleted file mode 100644 index ff85a5d77f16..000000000000 --- a/arch/tile/include/uapi/arch/icache.h +++ /dev/null @@ -1,94 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - */ - -/** - * @file - * - * Support for invalidating bytes in the instruction cache. - */ - -#ifndef __ARCH_ICACHE_H__ -#define __ARCH_ICACHE_H__ - -#include - - -/** - * Invalidate the instruction cache for the given range of memory. - * - * @param addr The start of memory to be invalidated. - * @param size The number of bytes to be invalidated. - * @param page_size The system's page size, e.g. getpagesize() in userspace. - * This value must be a power of two no larger than the page containing - * the code to be invalidated. If the value is smaller than the actual page - * size, this function will still work, but may run slower than necessary. - */ -static __inline void -invalidate_icache(const void* addr, unsigned long size, - unsigned long page_size) -{ - const unsigned long cache_way_size = - CHIP_L1I_CACHE_SIZE() / CHIP_L1I_ASSOC(); - unsigned long max_useful_size; - const char* start, *end; - long num_passes; - - if (__builtin_expect(size == 0, 0)) - return; - -#ifdef __tilegx__ - /* Limit the number of bytes visited to avoid redundant iterations. */ - max_useful_size = (page_size < cache_way_size) ? page_size : cache_way_size; - - /* No PA aliasing is possible, so one pass always suffices. */ - num_passes = 1; -#else - /* Limit the number of bytes visited to avoid redundant iterations. */ - max_useful_size = cache_way_size; - - /* - * Compute how many passes we need (we'll treat 0 as if it were 1). - * This works because we know the page size is a power of two. - */ - num_passes = cache_way_size >> __builtin_ctzl(page_size); -#endif - - if (__builtin_expect(size > max_useful_size, 0)) - size = max_useful_size; - - /* Locate the first and last bytes to be invalidated. */ - start = (const char *)((unsigned long)addr & -CHIP_L1I_LINE_SIZE()); - end = (const char*)addr + size - 1; - - __insn_mf(); - - do - { - const char* p; - - for (p = start; p <= end; p += CHIP_L1I_LINE_SIZE()) - __insn_icoh(p); - - start += page_size; - end += page_size; - } - while (--num_passes > 0); - - __insn_drain(); -} - - -#endif /* __ARCH_ICACHE_H__ */ diff --git a/arch/tile/include/uapi/arch/interrupts.h b/arch/tile/include/uapi/arch/interrupts.h deleted file mode 100644 index c288b5d82b4d..000000000000 --- a/arch/tile/include/uapi/arch/interrupts.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifdef __tilegx__ -#include -#else -#include -#endif diff --git a/arch/tile/include/uapi/arch/interrupts_32.h b/arch/tile/include/uapi/arch/interrupts_32.h deleted file mode 100644 index a748752cec16..000000000000 --- a/arch/tile/include/uapi/arch/interrupts_32.h +++ /dev/null @@ -1,310 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef __ARCH_INTERRUPTS_H__ -#define __ARCH_INTERRUPTS_H__ - -#ifndef __KERNEL__ -/** Mask for an interrupt. */ -/* Note: must handle breaking interrupts into high and low words manually. */ -#define INT_MASK_LO(intno) (1 << (intno)) -#define INT_MASK_HI(intno) (1 << ((intno) - 32)) - -#ifndef __ASSEMBLER__ -#define INT_MASK(intno) (1ULL << (intno)) -#endif -#endif - - -/** Where a given interrupt executes */ -#define INTERRUPT_VECTOR(i, pl) (0xFC000000 + ((pl) << 24) + ((i) << 8)) - -/** Where to store a vector for a given interrupt. */ -#define USER_INTERRUPT_VECTOR(i) INTERRUPT_VECTOR(i, 0) - -/** The base address of user-level interrupts. */ -#define USER_INTERRUPT_VECTOR_BASE INTERRUPT_VECTOR(0, 0) - - -/** Additional synthetic interrupt. */ -#define INT_BREAKPOINT (63) - -#define INT_ITLB_MISS 0 -#define INT_MEM_ERROR 1 -#define INT_ILL 2 -#define INT_GPV 3 -#define INT_SN_ACCESS 4 -#define INT_IDN_ACCESS 5 -#define INT_UDN_ACCESS 6 -#define INT_IDN_REFILL 7 -#define INT_UDN_REFILL 8 -#define INT_IDN_COMPLETE 9 -#define INT_UDN_COMPLETE 10 -#define INT_SWINT_3 11 -#define INT_SWINT_2 12 -#define INT_SWINT_1 13 -#define INT_SWINT_0 14 -#define INT_UNALIGN_DATA 15 -#define INT_DTLB_MISS 16 -#define INT_DTLB_ACCESS 17 -#define INT_DMATLB_MISS 18 -#define INT_DMATLB_ACCESS 19 -#define INT_SNITLB_MISS 20 -#define INT_SN_NOTIFY 21 -#define INT_SN_FIREWALL 22 -#define INT_IDN_FIREWALL 23 -#define INT_UDN_FIREWALL 24 -#define INT_TILE_TIMER 25 -#define INT_IDN_TIMER 26 -#define INT_UDN_TIMER 27 -#define INT_DMA_NOTIFY 28 -#define INT_IDN_CA 29 -#define INT_UDN_CA 30 -#define INT_IDN_AVAIL 31 -#define INT_UDN_AVAIL 32 -#define INT_PERF_COUNT 33 -#define INT_INTCTRL_3 34 -#define INT_INTCTRL_2 35 -#define INT_INTCTRL_1 36 -#define INT_INTCTRL_0 37 -#define INT_BOOT_ACCESS 38 -#define INT_WORLD_ACCESS 39 -#define INT_I_ASID 40 -#define INT_D_ASID 41 -#define INT_DMA_ASID 42 -#define INT_SNI_ASID 43 -#define INT_DMA_CPL 44 -#define INT_SN_CPL 45 -#define INT_DOUBLE_FAULT 46 -#define INT_SN_STATIC_ACCESS 47 -#define INT_AUX_PERF_COUNT 48 - -#define NUM_INTERRUPTS 49 - -#ifndef __ASSEMBLER__ -#define QUEUED_INTERRUPTS ( \ - (1ULL << INT_MEM_ERROR) | \ - (1ULL << INT_DMATLB_MISS) | \ - (1ULL << INT_DMATLB_ACCESS) | \ - (1ULL << INT_SNITLB_MISS) | \ - (1ULL << INT_SN_NOTIFY) | \ - (1ULL << INT_SN_FIREWALL) | \ - (1ULL << INT_IDN_FIREWALL) | \ - (1ULL << INT_UDN_FIREWALL) | \ - (1ULL << INT_TILE_TIMER) | \ - (1ULL << INT_IDN_TIMER) | \ - (1ULL << INT_UDN_TIMER) | \ - (1ULL << INT_DMA_NOTIFY) | \ - (1ULL << INT_IDN_CA) | \ - (1ULL << INT_UDN_CA) | \ - (1ULL << INT_IDN_AVAIL) | \ - (1ULL << INT_UDN_AVAIL) | \ - (1ULL << INT_PERF_COUNT) | \ - (1ULL << INT_INTCTRL_3) | \ - (1ULL << INT_INTCTRL_2) | \ - (1ULL << INT_INTCTRL_1) | \ - (1ULL << INT_INTCTRL_0) | \ - (1ULL << INT_BOOT_ACCESS) | \ - (1ULL << INT_WORLD_ACCESS) | \ - (1ULL << INT_I_ASID) | \ - (1ULL << INT_D_ASID) | \ - (1ULL << INT_DMA_ASID) | \ - (1ULL << INT_SNI_ASID) | \ - (1ULL << INT_DMA_CPL) | \ - (1ULL << INT_SN_CPL) | \ - (1ULL << INT_DOUBLE_FAULT) | \ - (1ULL << INT_AUX_PERF_COUNT) | \ - 0) -#define NONQUEUED_INTERRUPTS ( \ - (1ULL << INT_ITLB_MISS) | \ - (1ULL << INT_ILL) | \ - (1ULL << INT_GPV) | \ - (1ULL << INT_SN_ACCESS) | \ - (1ULL << INT_IDN_ACCESS) | \ - (1ULL << INT_UDN_ACCESS) | \ - (1ULL << INT_IDN_REFILL) | \ - (1ULL << INT_UDN_REFILL) | \ - (1ULL << INT_IDN_COMPLETE) | \ - (1ULL << INT_UDN_COMPLETE) | \ - (1ULL << INT_SWINT_3) | \ - (1ULL << INT_SWINT_2) | \ - (1ULL << INT_SWINT_1) | \ - (1ULL << INT_SWINT_0) | \ - (1ULL << INT_UNALIGN_DATA) | \ - (1ULL << INT_DTLB_MISS) | \ - (1ULL << INT_DTLB_ACCESS) | \ - (1ULL << INT_SN_STATIC_ACCESS) | \ - 0) -#define CRITICAL_MASKED_INTERRUPTS ( \ - (1ULL << INT_MEM_ERROR) | \ - (1ULL << INT_DMATLB_MISS) | \ - (1ULL << INT_DMATLB_ACCESS) | \ - (1ULL << INT_SNITLB_MISS) | \ - (1ULL << INT_SN_NOTIFY) | \ - (1ULL << INT_SN_FIREWALL) | \ - (1ULL << INT_IDN_FIREWALL) | \ - (1ULL << INT_UDN_FIREWALL) | \ - (1ULL << INT_TILE_TIMER) | \ - (1ULL << INT_IDN_TIMER) | \ - (1ULL << INT_UDN_TIMER) | \ - (1ULL << INT_DMA_NOTIFY) | \ - (1ULL << INT_IDN_CA) | \ - (1ULL << INT_UDN_CA) | \ - (1ULL << INT_IDN_AVAIL) | \ - (1ULL << INT_UDN_AVAIL) | \ - (1ULL << INT_PERF_COUNT) | \ - (1ULL << INT_INTCTRL_3) | \ - (1ULL << INT_INTCTRL_2) | \ - (1ULL << INT_INTCTRL_1) | \ - (1ULL << INT_INTCTRL_0) | \ - (1ULL << INT_AUX_PERF_COUNT) | \ - 0) -#define CRITICAL_UNMASKED_INTERRUPTS ( \ - (1ULL << INT_ITLB_MISS) | \ - (1ULL << INT_ILL) | \ - (1ULL << INT_GPV) | \ - (1ULL << INT_SN_ACCESS) | \ - (1ULL << INT_IDN_ACCESS) | \ - (1ULL << INT_UDN_ACCESS) | \ - (1ULL << INT_IDN_REFILL) | \ - (1ULL << INT_UDN_REFILL) | \ - (1ULL << INT_IDN_COMPLETE) | \ - (1ULL << INT_UDN_COMPLETE) | \ - (1ULL << INT_SWINT_3) | \ - (1ULL << INT_SWINT_2) | \ - (1ULL << INT_SWINT_1) | \ - (1ULL << INT_SWINT_0) | \ - (1ULL << INT_UNALIGN_DATA) | \ - (1ULL << INT_DTLB_MISS) | \ - (1ULL << INT_DTLB_ACCESS) | \ - (1ULL << INT_BOOT_ACCESS) | \ - (1ULL << INT_WORLD_ACCESS) | \ - (1ULL << INT_I_ASID) | \ - (1ULL << INT_D_ASID) | \ - (1ULL << INT_DMA_ASID) | \ - (1ULL << INT_SNI_ASID) | \ - (1ULL << INT_DMA_CPL) | \ - (1ULL << INT_SN_CPL) | \ - (1ULL << INT_DOUBLE_FAULT) | \ - (1ULL << INT_SN_STATIC_ACCESS) | \ - 0) -#define MASKABLE_INTERRUPTS ( \ - (1ULL << INT_MEM_ERROR) | \ - (1ULL << INT_IDN_REFILL) | \ - (1ULL << INT_UDN_REFILL) | \ - (1ULL << INT_IDN_COMPLETE) | \ - (1ULL << INT_UDN_COMPLETE) | \ - (1ULL << INT_DMATLB_MISS) | \ - (1ULL << INT_DMATLB_ACCESS) | \ - (1ULL << INT_SNITLB_MISS) | \ - (1ULL << INT_SN_NOTIFY) | \ - (1ULL << INT_SN_FIREWALL) | \ - (1ULL << INT_IDN_FIREWALL) | \ - (1ULL << INT_UDN_FIREWALL) | \ - (1ULL << INT_TILE_TIMER) | \ - (1ULL << INT_IDN_TIMER) | \ - (1ULL << INT_UDN_TIMER) | \ - (1ULL << INT_DMA_NOTIFY) | \ - (1ULL << INT_IDN_CA) | \ - (1ULL << INT_UDN_CA) | \ - (1ULL << INT_IDN_AVAIL) | \ - (1ULL << INT_UDN_AVAIL) | \ - (1ULL << INT_PERF_COUNT) | \ - (1ULL << INT_INTCTRL_3) | \ - (1ULL << INT_INTCTRL_2) | \ - (1ULL << INT_INTCTRL_1) | \ - (1ULL << INT_INTCTRL_0) | \ - (1ULL << INT_AUX_PERF_COUNT) | \ - 0) -#define UNMASKABLE_INTERRUPTS ( \ - (1ULL << INT_ITLB_MISS) | \ - (1ULL << INT_ILL) | \ - (1ULL << INT_GPV) | \ - (1ULL << INT_SN_ACCESS) | \ - (1ULL << INT_IDN_ACCESS) | \ - (1ULL << INT_UDN_ACCESS) | \ - (1ULL << INT_SWINT_3) | \ - (1ULL << INT_SWINT_2) | \ - (1ULL << INT_SWINT_1) | \ - (1ULL << INT_SWINT_0) | \ - (1ULL << INT_UNALIGN_DATA) | \ - (1ULL << INT_DTLB_MISS) | \ - (1ULL << INT_DTLB_ACCESS) | \ - (1ULL << INT_BOOT_ACCESS) | \ - (1ULL << INT_WORLD_ACCESS) | \ - (1ULL << INT_I_ASID) | \ - (1ULL << INT_D_ASID) | \ - (1ULL << INT_DMA_ASID) | \ - (1ULL << INT_SNI_ASID) | \ - (1ULL << INT_DMA_CPL) | \ - (1ULL << INT_SN_CPL) | \ - (1ULL << INT_DOUBLE_FAULT) | \ - (1ULL << INT_SN_STATIC_ACCESS) | \ - 0) -#define SYNC_INTERRUPTS ( \ - (1ULL << INT_ITLB_MISS) | \ - (1ULL << INT_ILL) | \ - (1ULL << INT_GPV) | \ - (1ULL << INT_SN_ACCESS) | \ - (1ULL << INT_IDN_ACCESS) | \ - (1ULL << INT_UDN_ACCESS) | \ - (1ULL << INT_IDN_REFILL) | \ - (1ULL << INT_UDN_REFILL) | \ - (1ULL << INT_IDN_COMPLETE) | \ - (1ULL << INT_UDN_COMPLETE) | \ - (1ULL << INT_SWINT_3) | \ - (1ULL << INT_SWINT_2) | \ - (1ULL << INT_SWINT_1) | \ - (1ULL << INT_SWINT_0) | \ - (1ULL << INT_UNALIGN_DATA) | \ - (1ULL << INT_DTLB_MISS) | \ - (1ULL << INT_DTLB_ACCESS) | \ - (1ULL << INT_SN_STATIC_ACCESS) | \ - 0) -#define NON_SYNC_INTERRUPTS ( \ - (1ULL << INT_MEM_ERROR) | \ - (1ULL << INT_DMATLB_MISS) | \ - (1ULL << INT_DMATLB_ACCESS) | \ - (1ULL << INT_SNITLB_MISS) | \ - (1ULL << INT_SN_NOTIFY) | \ - (1ULL << INT_SN_FIREWALL) | \ - (1ULL << INT_IDN_FIREWALL) | \ - (1ULL << INT_UDN_FIREWALL) | \ - (1ULL << INT_TILE_TIMER) | \ - (1ULL << INT_IDN_TIMER) | \ - (1ULL << INT_UDN_TIMER) | \ - (1ULL << INT_DMA_NOTIFY) | \ - (1ULL << INT_IDN_CA) | \ - (1ULL << INT_UDN_CA) | \ - (1ULL << INT_IDN_AVAIL) | \ - (1ULL << INT_UDN_AVAIL) | \ - (1ULL << INT_PERF_COUNT) | \ - (1ULL << INT_INTCTRL_3) | \ - (1ULL << INT_INTCTRL_2) | \ - (1ULL << INT_INTCTRL_1) | \ - (1ULL << INT_INTCTRL_0) | \ - (1ULL << INT_BOOT_ACCESS) | \ - (1ULL << INT_WORLD_ACCESS) | \ - (1ULL << INT_I_ASID) | \ - (1ULL << INT_D_ASID) | \ - (1ULL << INT_DMA_ASID) | \ - (1ULL << INT_SNI_ASID) | \ - (1ULL << INT_DMA_CPL) | \ - (1ULL << INT_SN_CPL) | \ - (1ULL << INT_DOUBLE_FAULT) | \ - (1ULL << INT_AUX_PERF_COUNT) | \ - 0) -#endif /* !__ASSEMBLER__ */ -#endif /* !__ARCH_INTERRUPTS_H__ */ diff --git a/arch/tile/include/uapi/arch/interrupts_64.h b/arch/tile/include/uapi/arch/interrupts_64.h deleted file mode 100644 index 142eaff3c244..000000000000 --- a/arch/tile/include/uapi/arch/interrupts_64.h +++ /dev/null @@ -1,279 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef __ARCH_INTERRUPTS_H__ -#define __ARCH_INTERRUPTS_H__ - -#ifndef __KERNEL__ -/** Mask for an interrupt. */ -#ifdef __ASSEMBLER__ -/* Note: must handle breaking interrupts into high and low words manually. */ -#define INT_MASK(intno) (1 << (intno)) -#else -#define INT_MASK(intno) (1ULL << (intno)) -#endif -#endif - - -/** Where a given interrupt executes */ -#define INTERRUPT_VECTOR(i, pl) (0xFC000000 + ((pl) << 24) + ((i) << 8)) - -/** Where to store a vector for a given interrupt. */ -#define USER_INTERRUPT_VECTOR(i) INTERRUPT_VECTOR(i, 0) - -/** The base address of user-level interrupts. */ -#define USER_INTERRUPT_VECTOR_BASE INTERRUPT_VECTOR(0, 0) - - -/** Additional synthetic interrupt. */ -#define INT_BREAKPOINT (63) - -#define INT_MEM_ERROR 0 -#define INT_SINGLE_STEP_3 1 -#define INT_SINGLE_STEP_2 2 -#define INT_SINGLE_STEP_1 3 -#define INT_SINGLE_STEP_0 4 -#define INT_IDN_COMPLETE 5 -#define INT_UDN_COMPLETE 6 -#define INT_ITLB_MISS 7 -#define INT_ILL 8 -#define INT_GPV 9 -#define INT_IDN_ACCESS 10 -#define INT_UDN_ACCESS 11 -#define INT_SWINT_3 12 -#define INT_SWINT_2 13 -#define INT_SWINT_1 14 -#define INT_SWINT_0 15 -#define INT_ILL_TRANS 16 -#define INT_UNALIGN_DATA 17 -#define INT_DTLB_MISS 18 -#define INT_DTLB_ACCESS 19 -#define INT_IDN_FIREWALL 20 -#define INT_UDN_FIREWALL 21 -#define INT_TILE_TIMER 22 -#define INT_AUX_TILE_TIMER 23 -#define INT_IDN_TIMER 24 -#define INT_UDN_TIMER 25 -#define INT_IDN_AVAIL 26 -#define INT_UDN_AVAIL 27 -#define INT_IPI_3 28 -#define INT_IPI_2 29 -#define INT_IPI_1 30 -#define INT_IPI_0 31 -#define INT_PERF_COUNT 32 -#define INT_AUX_PERF_COUNT 33 -#define INT_INTCTRL_3 34 -#define INT_INTCTRL_2 35 -#define INT_INTCTRL_1 36 -#define INT_INTCTRL_0 37 -#define INT_BOOT_ACCESS 38 -#define INT_WORLD_ACCESS 39 -#define INT_I_ASID 40 -#define INT_D_ASID 41 -#define INT_DOUBLE_FAULT 42 - -#define NUM_INTERRUPTS 43 - -#ifndef __ASSEMBLER__ -#define QUEUED_INTERRUPTS ( \ - (1ULL << INT_MEM_ERROR) | \ - (1ULL << INT_IDN_COMPLETE) | \ - (1ULL << INT_UDN_COMPLETE) | \ - (1ULL << INT_IDN_FIREWALL) | \ - (1ULL << INT_UDN_FIREWALL) | \ - (1ULL << INT_TILE_TIMER) | \ - (1ULL << INT_AUX_TILE_TIMER) | \ - (1ULL << INT_IDN_TIMER) | \ - (1ULL << INT_UDN_TIMER) | \ - (1ULL << INT_IDN_AVAIL) | \ - (1ULL << INT_UDN_AVAIL) | \ - (1ULL << INT_IPI_3) | \ - (1ULL << INT_IPI_2) | \ - (1ULL << INT_IPI_1) | \ - (1ULL << INT_IPI_0) | \ - (1ULL << INT_PERF_COUNT) | \ - (1ULL << INT_AUX_PERF_COUNT) | \ - (1ULL << INT_INTCTRL_3) | \ - (1ULL << INT_INTCTRL_2) | \ - (1ULL << INT_INTCTRL_1) | \ - (1ULL << INT_INTCTRL_0) | \ - (1ULL << INT_BOOT_ACCESS) | \ - (1ULL << INT_WORLD_ACCESS) | \ - (1ULL << INT_I_ASID) | \ - (1ULL << INT_D_ASID) | \ - (1ULL << INT_DOUBLE_FAULT) | \ - 0) -#define NONQUEUED_INTERRUPTS ( \ - (1ULL << INT_SINGLE_STEP_3) | \ - (1ULL << INT_SINGLE_STEP_2) | \ - (1ULL << INT_SINGLE_STEP_1) | \ - (1ULL << INT_SINGLE_STEP_0) | \ - (1ULL << INT_ITLB_MISS) | \ - (1ULL << INT_ILL) | \ - (1ULL << INT_GPV) | \ - (1ULL << INT_IDN_ACCESS) | \ - (1ULL << INT_UDN_ACCESS) | \ - (1ULL << INT_SWINT_3) | \ - (1ULL << INT_SWINT_2) | \ - (1ULL << INT_SWINT_1) | \ - (1ULL << INT_SWINT_0) | \ - (1ULL << INT_ILL_TRANS) | \ - (1ULL << INT_UNALIGN_DATA) | \ - (1ULL << INT_DTLB_MISS) | \ - (1ULL << INT_DTLB_ACCESS) | \ - 0) -#define CRITICAL_MASKED_INTERRUPTS ( \ - (1ULL << INT_MEM_ERROR) | \ - (1ULL << INT_SINGLE_STEP_3) | \ - (1ULL << INT_SINGLE_STEP_2) | \ - (1ULL << INT_SINGLE_STEP_1) | \ - (1ULL << INT_SINGLE_STEP_0) | \ - (1ULL << INT_IDN_COMPLETE) | \ - (1ULL << INT_UDN_COMPLETE) | \ - (1ULL << INT_IDN_FIREWALL) | \ - (1ULL << INT_UDN_FIREWALL) | \ - (1ULL << INT_TILE_TIMER) | \ - (1ULL << INT_AUX_TILE_TIMER) | \ - (1ULL << INT_IDN_TIMER) | \ - (1ULL << INT_UDN_TIMER) | \ - (1ULL << INT_IDN_AVAIL) | \ - (1ULL << INT_UDN_AVAIL) | \ - (1ULL << INT_IPI_3) | \ - (1ULL << INT_IPI_2) | \ - (1ULL << INT_IPI_1) | \ - (1ULL << INT_IPI_0) | \ - (1ULL << INT_PERF_COUNT) | \ - (1ULL << INT_AUX_PERF_COUNT) | \ - (1ULL << INT_INTCTRL_3) | \ - (1ULL << INT_INTCTRL_2) | \ - (1ULL << INT_INTCTRL_1) | \ - (1ULL << INT_INTCTRL_0) | \ - 0) -#define CRITICAL_UNMASKED_INTERRUPTS ( \ - (1ULL << INT_ITLB_MISS) | \ - (1ULL << INT_ILL) | \ - (1ULL << INT_GPV) | \ - (1ULL << INT_IDN_ACCESS) | \ - (1ULL << INT_UDN_ACCESS) | \ - (1ULL << INT_SWINT_3) | \ - (1ULL << INT_SWINT_2) | \ - (1ULL << INT_SWINT_1) | \ - (1ULL << INT_SWINT_0) | \ - (1ULL << INT_ILL_TRANS) | \ - (1ULL << INT_UNALIGN_DATA) | \ - (1ULL << INT_DTLB_MISS) | \ - (1ULL << INT_DTLB_ACCESS) | \ - (1ULL << INT_BOOT_ACCESS) | \ - (1ULL << INT_WORLD_ACCESS) | \ - (1ULL << INT_I_ASID) | \ - (1ULL << INT_D_ASID) | \ - (1ULL << INT_DOUBLE_FAULT) | \ - 0) -#define MASKABLE_INTERRUPTS ( \ - (1ULL << INT_MEM_ERROR) | \ - (1ULL << INT_SINGLE_STEP_3) | \ - (1ULL << INT_SINGLE_STEP_2) | \ - (1ULL << INT_SINGLE_STEP_1) | \ - (1ULL << INT_SINGLE_STEP_0) | \ - (1ULL << INT_IDN_COMPLETE) | \ - (1ULL << INT_UDN_COMPLETE) | \ - (1ULL << INT_IDN_FIREWALL) | \ - (1ULL << INT_UDN_FIREWALL) | \ - (1ULL << INT_TILE_TIMER) | \ - (1ULL << INT_AUX_TILE_TIMER) | \ - (1ULL << INT_IDN_TIMER) | \ - (1ULL << INT_UDN_TIMER) | \ - (1ULL << INT_IDN_AVAIL) | \ - (1ULL << INT_UDN_AVAIL) | \ - (1ULL << INT_IPI_3) | \ - (1ULL << INT_IPI_2) | \ - (1ULL << INT_IPI_1) | \ - (1ULL << INT_IPI_0) | \ - (1ULL << INT_PERF_COUNT) | \ - (1ULL << INT_AUX_PERF_COUNT) | \ - (1ULL << INT_INTCTRL_3) | \ - (1ULL << INT_INTCTRL_2) | \ - (1ULL << INT_INTCTRL_1) | \ - (1ULL << INT_INTCTRL_0) | \ - 0) -#define UNMASKABLE_INTERRUPTS ( \ - (1ULL << INT_ITLB_MISS) | \ - (1ULL << INT_ILL) | \ - (1ULL << INT_GPV) | \ - (1ULL << INT_IDN_ACCESS) | \ - (1ULL << INT_UDN_ACCESS) | \ - (1ULL << INT_SWINT_3) | \ - (1ULL << INT_SWINT_2) | \ - (1ULL << INT_SWINT_1) | \ - (1ULL << INT_SWINT_0) | \ - (1ULL << INT_ILL_TRANS) | \ - (1ULL << INT_UNALIGN_DATA) | \ - (1ULL << INT_DTLB_MISS) | \ - (1ULL << INT_DTLB_ACCESS) | \ - (1ULL << INT_BOOT_ACCESS) | \ - (1ULL << INT_WORLD_ACCESS) | \ - (1ULL << INT_I_ASID) | \ - (1ULL << INT_D_ASID) | \ - (1ULL << INT_DOUBLE_FAULT) | \ - 0) -#define SYNC_INTERRUPTS ( \ - (1ULL << INT_SINGLE_STEP_3) | \ - (1ULL << INT_SINGLE_STEP_2) | \ - (1ULL << INT_SINGLE_STEP_1) | \ - (1ULL << INT_SINGLE_STEP_0) | \ - (1ULL << INT_IDN_COMPLETE) | \ - (1ULL << INT_UDN_COMPLETE) | \ - (1ULL << INT_ITLB_MISS) | \ - (1ULL << INT_ILL) | \ - (1ULL << INT_GPV) | \ - (1ULL << INT_IDN_ACCESS) | \ - (1ULL << INT_UDN_ACCESS) | \ - (1ULL << INT_SWINT_3) | \ - (1ULL << INT_SWINT_2) | \ - (1ULL << INT_SWINT_1) | \ - (1ULL << INT_SWINT_0) | \ - (1ULL << INT_ILL_TRANS) | \ - (1ULL << INT_UNALIGN_DATA) | \ - (1ULL << INT_DTLB_MISS) | \ - (1ULL << INT_DTLB_ACCESS) | \ - 0) -#define NON_SYNC_INTERRUPTS ( \ - (1ULL << INT_MEM_ERROR) | \ - (1ULL << INT_IDN_FIREWALL) | \ - (1ULL << INT_UDN_FIREWALL) | \ - (1ULL << INT_TILE_TIMER) | \ - (1ULL << INT_AUX_TILE_TIMER) | \ - (1ULL << INT_IDN_TIMER) | \ - (1ULL << INT_UDN_TIMER) | \ - (1ULL << INT_IDN_AVAIL) | \ - (1ULL << INT_UDN_AVAIL) | \ - (1ULL << INT_IPI_3) | \ - (1ULL << INT_IPI_2) | \ - (1ULL << INT_IPI_1) | \ - (1ULL << INT_IPI_0) | \ - (1ULL << INT_PERF_COUNT) | \ - (1ULL << INT_AUX_PERF_COUNT) | \ - (1ULL << INT_INTCTRL_3) | \ - (1ULL << INT_INTCTRL_2) | \ - (1ULL << INT_INTCTRL_1) | \ - (1ULL << INT_INTCTRL_0) | \ - (1ULL << INT_BOOT_ACCESS) | \ - (1ULL << INT_WORLD_ACCESS) | \ - (1ULL << INT_I_ASID) | \ - (1ULL << INT_D_ASID) | \ - (1ULL << INT_DOUBLE_FAULT) | \ - 0) -#endif /* !__ASSEMBLER__ */ -#endif /* !__ARCH_INTERRUPTS_H__ */ diff --git a/arch/tile/include/uapi/arch/intreg.h b/arch/tile/include/uapi/arch/intreg.h deleted file mode 100644 index 5387fb645bb8..000000000000 --- a/arch/tile/include/uapi/arch/intreg.h +++ /dev/null @@ -1,71 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2017 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file - * - * Provide types and defines for the type that can hold a register, - * in the implementation namespace. - */ - -#ifndef __ARCH_INTREG_H__ -#define __ARCH_INTREG_H__ - -/* - * Get number of bits in a register. __INT_REG_BITS may be defined - * prior to including this header to force a particular bit width. - */ - -#ifndef __INT_REG_BITS -# if defined __tilegx__ -# define __INT_REG_BITS 64 -# elif defined __tilepro__ -# define __INT_REG_BITS 32 -# else -# error Unrecognized architecture -# endif -#endif - -#if __INT_REG_BITS == 64 - -# ifndef __ASSEMBLER__ -/** Unsigned type that can hold a register. */ -typedef unsigned long long __uint_reg_t; - -/** Signed type that can hold a register. */ -typedef long long __int_reg_t; -# endif - -/** String prefix to use for printf(). */ -# define __INT_REG_FMT "ll" - -#elif __INT_REG_BITS == 32 - -# ifndef __ASSEMBLER__ -/** Unsigned type that can hold a register. */ -typedef unsigned long __uint_reg_t; - -/** Signed type that can hold a register. */ -typedef long __int_reg_t; -# endif - -/** String prefix to use for printf(). */ -# define __INT_REG_FMT "l" - -#else -# error Unrecognized value of __INT_REG_BITS -#endif - -#endif /* !__ARCH_INTREG_H__ */ diff --git a/arch/tile/include/uapi/arch/opcode.h b/arch/tile/include/uapi/arch/opcode.h deleted file mode 100644 index a9ce5961a028..000000000000 --- a/arch/tile/include/uapi/arch/opcode.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#if defined(__tilepro__) -#include -#elif defined(__tilegx__) -#include -#else -#error Unexpected Tilera chip type -#endif diff --git a/arch/tile/include/uapi/arch/opcode_tilegx.h b/arch/tile/include/uapi/arch/opcode_tilegx.h deleted file mode 100644 index 948ea544567f..000000000000 --- a/arch/tile/include/uapi/arch/opcode_tilegx.h +++ /dev/null @@ -1,1407 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* TILE-Gx opcode information. - * - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * - * - * - * - */ - -#ifndef __ARCH_OPCODE_H__ -#define __ARCH_OPCODE_H__ - -#ifndef __ASSEMBLER__ - -typedef unsigned long long tilegx_bundle_bits; - -/* These are the bits that determine if a bundle is in the X encoding. */ -#define TILEGX_BUNDLE_MODE_MASK ((tilegx_bundle_bits)3 << 62) - -enum -{ - /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */ - TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE = 3, - - /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */ - TILEGX_NUM_PIPELINE_ENCODINGS = 5, - - /* Log base 2 of TILEGX_BUNDLE_SIZE_IN_BYTES. */ - TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES = 3, - - /* Instructions take this many bytes. */ - TILEGX_BUNDLE_SIZE_IN_BYTES = 1 << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES, - - /* Log base 2 of TILEGX_BUNDLE_ALIGNMENT_IN_BYTES. */ - TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3, - - /* Bundles should be aligned modulo this number of bytes. */ - TILEGX_BUNDLE_ALIGNMENT_IN_BYTES = - (1 << TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES), - - /* Number of registers (some are magic, such as network I/O). */ - TILEGX_NUM_REGISTERS = 64, -}; - -/* Make a few "tile_" variables to simplify common code between - architectures. */ - -typedef tilegx_bundle_bits tile_bundle_bits; -#define TILE_BUNDLE_SIZE_IN_BYTES TILEGX_BUNDLE_SIZE_IN_BYTES -#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEGX_BUNDLE_ALIGNMENT_IN_BYTES -#define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \ - TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES -#define TILE_BPT_BUNDLE TILEGX_BPT_BUNDLE - -/* 64-bit pattern for a { bpt ; nop } bundle. */ -#define TILEGX_BPT_BUNDLE 0x286a44ae51485000ULL - -static __inline unsigned int -get_BFEnd_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_BFOpcodeExtension_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 24)) & 0xf); -} - -static __inline unsigned int -get_BFStart_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3f); -} - -static __inline unsigned int -get_BrOff_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x0000003f) | - (((unsigned int)(n >> 37)) & 0x0001ffc0); -} - -static __inline unsigned int -get_BrType_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 54)) & 0x1f); -} - -static __inline unsigned int -get_Dest_Imm8_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x0000003f) | - (((unsigned int)(n >> 43)) & 0x000000c0); -} - -static __inline unsigned int -get_Dest_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3f); -} - -static __inline unsigned int -get_Dest_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x3f); -} - -static __inline unsigned int -get_Dest_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3f); -} - -static __inline unsigned int -get_Dest_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x3f); -} - -static __inline unsigned int -get_Imm16_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xffff); -} - -static __inline unsigned int -get_Imm16_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xffff); -} - -static __inline unsigned int -get_Imm8OpcodeExtension_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 20)) & 0xff); -} - -static __inline unsigned int -get_Imm8OpcodeExtension_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 51)) & 0xff); -} - -static __inline unsigned int -get_Imm8_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xff); -} - -static __inline unsigned int -get_Imm8_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xff); -} - -static __inline unsigned int -get_Imm8_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xff); -} - -static __inline unsigned int -get_Imm8_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xff); -} - -static __inline unsigned int -get_JumpOff_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x7ffffff); -} - -static __inline unsigned int -get_JumpOpcodeExtension_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 58)) & 0x1); -} - -static __inline unsigned int -get_MF_Imm14_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x3fff); -} - -static __inline unsigned int -get_MT_Imm14_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x0000003f) | - (((unsigned int)(n >> 37)) & 0x00003fc0); -} - -static __inline unsigned int -get_Mode(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 62)) & 0x3); -} - -static __inline unsigned int -get_Opcode_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 28)) & 0x7); -} - -static __inline unsigned int -get_Opcode_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 59)) & 0x7); -} - -static __inline unsigned int -get_Opcode_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 27)) & 0xf); -} - -static __inline unsigned int -get_Opcode_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 58)) & 0xf); -} - -static __inline unsigned int -get_Opcode_Y2(tilegx_bundle_bits n) -{ - return (((n >> 26)) & 0x00000001) | - (((unsigned int)(n >> 56)) & 0x00000002); -} - -static __inline unsigned int -get_RRROpcodeExtension_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3ff); -} - -static __inline unsigned int -get_RRROpcodeExtension_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x3ff); -} - -static __inline unsigned int -get_RRROpcodeExtension_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3); -} - -static __inline unsigned int -get_RRROpcodeExtension_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x3); -} - -static __inline unsigned int -get_ShAmt_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_ShAmt_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_ShAmt_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_ShAmt_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_ShiftOpcodeExtension_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3ff); -} - -static __inline unsigned int -get_ShiftOpcodeExtension_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x3ff); -} - -static __inline unsigned int -get_ShiftOpcodeExtension_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3); -} - -static __inline unsigned int -get_ShiftOpcodeExtension_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x3); -} - -static __inline unsigned int -get_SrcA_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 6)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 6)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y2(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 20)) & 0x3f); -} - -static __inline unsigned int -get_SrcBDest_Y2(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 51)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_UnaryOpcodeExtension_X0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_UnaryOpcodeExtension_X1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_UnaryOpcodeExtension_Y0(tilegx_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_UnaryOpcodeExtension_Y1(tilegx_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - - -static __inline int -sign_extend(int n, int num_bits) -{ - int shift = (int)(sizeof(int) * 8 - num_bits); - return (n << shift) >> shift; -} - - - -static __inline tilegx_bundle_bits -create_BFEnd_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_BFOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xf) << 24); -} - -static __inline tilegx_bundle_bits -create_BFStart_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 18); -} - -static __inline tilegx_bundle_bits -create_BrOff_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) | - (((tilegx_bundle_bits)(n & 0x0001ffc0)) << 37); -} - -static __inline tilegx_bundle_bits -create_BrType_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x1f)) << 54); -} - -static __inline tilegx_bundle_bits -create_Dest_Imm8_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) | - (((tilegx_bundle_bits)(n & 0x000000c0)) << 43); -} - -static __inline tilegx_bundle_bits -create_Dest_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 0); -} - -static __inline tilegx_bundle_bits -create_Dest_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 31); -} - -static __inline tilegx_bundle_bits -create_Dest_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 0); -} - -static __inline tilegx_bundle_bits -create_Dest_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 31); -} - -static __inline tilegx_bundle_bits -create_Imm16_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xffff) << 12); -} - -static __inline tilegx_bundle_bits -create_Imm16_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0xffff)) << 43); -} - -static __inline tilegx_bundle_bits -create_Imm8OpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 20); -} - -static __inline tilegx_bundle_bits -create_Imm8OpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0xff)) << 51); -} - -static __inline tilegx_bundle_bits -create_Imm8_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 12); -} - -static __inline tilegx_bundle_bits -create_Imm8_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0xff)) << 43); -} - -static __inline tilegx_bundle_bits -create_Imm8_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 12); -} - -static __inline tilegx_bundle_bits -create_Imm8_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0xff)) << 43); -} - -static __inline tilegx_bundle_bits -create_JumpOff_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x7ffffff)) << 31); -} - -static __inline tilegx_bundle_bits -create_JumpOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x1)) << 58); -} - -static __inline tilegx_bundle_bits -create_MF_Imm14_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3fff)) << 37); -} - -static __inline tilegx_bundle_bits -create_MT_Imm14_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x0000003f)) << 31) | - (((tilegx_bundle_bits)(n & 0x00003fc0)) << 37); -} - -static __inline tilegx_bundle_bits -create_Mode(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3)) << 62); -} - -static __inline tilegx_bundle_bits -create_Opcode_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x7) << 28); -} - -static __inline tilegx_bundle_bits -create_Opcode_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x7)) << 59); -} - -static __inline tilegx_bundle_bits -create_Opcode_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xf) << 27); -} - -static __inline tilegx_bundle_bits -create_Opcode_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0xf)) << 58); -} - -static __inline tilegx_bundle_bits -create_Opcode_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x00000001) << 26) | - (((tilegx_bundle_bits)(n & 0x00000002)) << 56); -} - -static __inline tilegx_bundle_bits -create_RRROpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3ff) << 18); -} - -static __inline tilegx_bundle_bits -create_RRROpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3ff)) << 49); -} - -static __inline tilegx_bundle_bits -create_RRROpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 18); -} - -static __inline tilegx_bundle_bits -create_RRROpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3)) << 49); -} - -static __inline tilegx_bundle_bits -create_ShAmt_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_ShAmt_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilegx_bundle_bits -create_ShAmt_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_ShAmt_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilegx_bundle_bits -create_ShiftOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3ff) << 18); -} - -static __inline tilegx_bundle_bits -create_ShiftOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3ff)) << 49); -} - -static __inline tilegx_bundle_bits -create_ShiftOpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 18); -} - -static __inline tilegx_bundle_bits -create_ShiftOpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3)) << 49); -} - -static __inline tilegx_bundle_bits -create_SrcA_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 6); -} - -static __inline tilegx_bundle_bits -create_SrcA_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 37); -} - -static __inline tilegx_bundle_bits -create_SrcA_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 6); -} - -static __inline tilegx_bundle_bits -create_SrcA_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 37); -} - -static __inline tilegx_bundle_bits -create_SrcA_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 20); -} - -static __inline tilegx_bundle_bits -create_SrcBDest_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 51); -} - -static __inline tilegx_bundle_bits -create_SrcB_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_SrcB_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilegx_bundle_bits -create_SrcB_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_SrcB_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilegx_bundle_bits -create_UnaryOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_UnaryOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilegx_bundle_bits -create_UnaryOpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilegx_bundle_bits -create_UnaryOpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilegx_bundle_bits)(n & 0x3f)) << 43); -} - - -enum -{ - ADDI_IMM8_OPCODE_X0 = 1, - ADDI_IMM8_OPCODE_X1 = 1, - ADDI_OPCODE_Y0 = 0, - ADDI_OPCODE_Y1 = 1, - ADDLI_OPCODE_X0 = 1, - ADDLI_OPCODE_X1 = 0, - ADDXI_IMM8_OPCODE_X0 = 2, - ADDXI_IMM8_OPCODE_X1 = 2, - ADDXI_OPCODE_Y0 = 1, - ADDXI_OPCODE_Y1 = 2, - ADDXLI_OPCODE_X0 = 2, - ADDXLI_OPCODE_X1 = 1, - ADDXSC_RRR_0_OPCODE_X0 = 1, - ADDXSC_RRR_0_OPCODE_X1 = 1, - ADDX_RRR_0_OPCODE_X0 = 2, - ADDX_RRR_0_OPCODE_X1 = 2, - ADDX_RRR_0_OPCODE_Y0 = 0, - ADDX_RRR_0_OPCODE_Y1 = 0, - ADD_RRR_0_OPCODE_X0 = 3, - ADD_RRR_0_OPCODE_X1 = 3, - ADD_RRR_0_OPCODE_Y0 = 1, - ADD_RRR_0_OPCODE_Y1 = 1, - ANDI_IMM8_OPCODE_X0 = 3, - ANDI_IMM8_OPCODE_X1 = 3, - ANDI_OPCODE_Y0 = 2, - ANDI_OPCODE_Y1 = 3, - AND_RRR_0_OPCODE_X0 = 4, - AND_RRR_0_OPCODE_X1 = 4, - AND_RRR_5_OPCODE_Y0 = 0, - AND_RRR_5_OPCODE_Y1 = 0, - BEQZT_BRANCH_OPCODE_X1 = 16, - BEQZ_BRANCH_OPCODE_X1 = 17, - BFEXTS_BF_OPCODE_X0 = 4, - BFEXTU_BF_OPCODE_X0 = 5, - BFINS_BF_OPCODE_X0 = 6, - BF_OPCODE_X0 = 3, - BGEZT_BRANCH_OPCODE_X1 = 18, - BGEZ_BRANCH_OPCODE_X1 = 19, - BGTZT_BRANCH_OPCODE_X1 = 20, - BGTZ_BRANCH_OPCODE_X1 = 21, - BLBCT_BRANCH_OPCODE_X1 = 22, - BLBC_BRANCH_OPCODE_X1 = 23, - BLBST_BRANCH_OPCODE_X1 = 24, - BLBS_BRANCH_OPCODE_X1 = 25, - BLEZT_BRANCH_OPCODE_X1 = 26, - BLEZ_BRANCH_OPCODE_X1 = 27, - BLTZT_BRANCH_OPCODE_X1 = 28, - BLTZ_BRANCH_OPCODE_X1 = 29, - BNEZT_BRANCH_OPCODE_X1 = 30, - BNEZ_BRANCH_OPCODE_X1 = 31, - BRANCH_OPCODE_X1 = 2, - CMOVEQZ_RRR_0_OPCODE_X0 = 5, - CMOVEQZ_RRR_4_OPCODE_Y0 = 0, - CMOVNEZ_RRR_0_OPCODE_X0 = 6, - CMOVNEZ_RRR_4_OPCODE_Y0 = 1, - CMPEQI_IMM8_OPCODE_X0 = 4, - CMPEQI_IMM8_OPCODE_X1 = 4, - CMPEQI_OPCODE_Y0 = 3, - CMPEQI_OPCODE_Y1 = 4, - CMPEQ_RRR_0_OPCODE_X0 = 7, - CMPEQ_RRR_0_OPCODE_X1 = 5, - CMPEQ_RRR_3_OPCODE_Y0 = 0, - CMPEQ_RRR_3_OPCODE_Y1 = 2, - CMPEXCH4_RRR_0_OPCODE_X1 = 6, - CMPEXCH_RRR_0_OPCODE_X1 = 7, - CMPLES_RRR_0_OPCODE_X0 = 8, - CMPLES_RRR_0_OPCODE_X1 = 8, - CMPLES_RRR_2_OPCODE_Y0 = 0, - CMPLES_RRR_2_OPCODE_Y1 = 0, - CMPLEU_RRR_0_OPCODE_X0 = 9, - CMPLEU_RRR_0_OPCODE_X1 = 9, - CMPLEU_RRR_2_OPCODE_Y0 = 1, - CMPLEU_RRR_2_OPCODE_Y1 = 1, - CMPLTSI_IMM8_OPCODE_X0 = 5, - CMPLTSI_IMM8_OPCODE_X1 = 5, - CMPLTSI_OPCODE_Y0 = 4, - CMPLTSI_OPCODE_Y1 = 5, - CMPLTS_RRR_0_OPCODE_X0 = 10, - CMPLTS_RRR_0_OPCODE_X1 = 10, - CMPLTS_RRR_2_OPCODE_Y0 = 2, - CMPLTS_RRR_2_OPCODE_Y1 = 2, - CMPLTUI_IMM8_OPCODE_X0 = 6, - CMPLTUI_IMM8_OPCODE_X1 = 6, - CMPLTU_RRR_0_OPCODE_X0 = 11, - CMPLTU_RRR_0_OPCODE_X1 = 11, - CMPLTU_RRR_2_OPCODE_Y0 = 3, - CMPLTU_RRR_2_OPCODE_Y1 = 3, - CMPNE_RRR_0_OPCODE_X0 = 12, - CMPNE_RRR_0_OPCODE_X1 = 12, - CMPNE_RRR_3_OPCODE_Y0 = 1, - CMPNE_RRR_3_OPCODE_Y1 = 3, - CMULAF_RRR_0_OPCODE_X0 = 13, - CMULA_RRR_0_OPCODE_X0 = 14, - CMULFR_RRR_0_OPCODE_X0 = 15, - CMULF_RRR_0_OPCODE_X0 = 16, - CMULHR_RRR_0_OPCODE_X0 = 17, - CMULH_RRR_0_OPCODE_X0 = 18, - CMUL_RRR_0_OPCODE_X0 = 19, - CNTLZ_UNARY_OPCODE_X0 = 1, - CNTLZ_UNARY_OPCODE_Y0 = 1, - CNTTZ_UNARY_OPCODE_X0 = 2, - CNTTZ_UNARY_OPCODE_Y0 = 2, - CRC32_32_RRR_0_OPCODE_X0 = 20, - CRC32_8_RRR_0_OPCODE_X0 = 21, - DBLALIGN2_RRR_0_OPCODE_X0 = 22, - DBLALIGN2_RRR_0_OPCODE_X1 = 13, - DBLALIGN4_RRR_0_OPCODE_X0 = 23, - DBLALIGN4_RRR_0_OPCODE_X1 = 14, - DBLALIGN6_RRR_0_OPCODE_X0 = 24, - DBLALIGN6_RRR_0_OPCODE_X1 = 15, - DBLALIGN_RRR_0_OPCODE_X0 = 25, - DRAIN_UNARY_OPCODE_X1 = 1, - DTLBPR_UNARY_OPCODE_X1 = 2, - EXCH4_RRR_0_OPCODE_X1 = 16, - EXCH_RRR_0_OPCODE_X1 = 17, - FDOUBLE_ADDSUB_RRR_0_OPCODE_X0 = 26, - FDOUBLE_ADD_FLAGS_RRR_0_OPCODE_X0 = 27, - FDOUBLE_MUL_FLAGS_RRR_0_OPCODE_X0 = 28, - FDOUBLE_PACK1_RRR_0_OPCODE_X0 = 29, - FDOUBLE_PACK2_RRR_0_OPCODE_X0 = 30, - FDOUBLE_SUB_FLAGS_RRR_0_OPCODE_X0 = 31, - FDOUBLE_UNPACK_MAX_RRR_0_OPCODE_X0 = 32, - FDOUBLE_UNPACK_MIN_RRR_0_OPCODE_X0 = 33, - FETCHADD4_RRR_0_OPCODE_X1 = 18, - FETCHADDGEZ4_RRR_0_OPCODE_X1 = 19, - FETCHADDGEZ_RRR_0_OPCODE_X1 = 20, - FETCHADD_RRR_0_OPCODE_X1 = 21, - FETCHAND4_RRR_0_OPCODE_X1 = 22, - FETCHAND_RRR_0_OPCODE_X1 = 23, - FETCHOR4_RRR_0_OPCODE_X1 = 24, - FETCHOR_RRR_0_OPCODE_X1 = 25, - FINV_UNARY_OPCODE_X1 = 3, - FLUSHWB_UNARY_OPCODE_X1 = 4, - FLUSH_UNARY_OPCODE_X1 = 5, - FNOP_UNARY_OPCODE_X0 = 3, - FNOP_UNARY_OPCODE_X1 = 6, - FNOP_UNARY_OPCODE_Y0 = 3, - FNOP_UNARY_OPCODE_Y1 = 8, - FSINGLE_ADD1_RRR_0_OPCODE_X0 = 34, - FSINGLE_ADDSUB2_RRR_0_OPCODE_X0 = 35, - FSINGLE_MUL1_RRR_0_OPCODE_X0 = 36, - FSINGLE_MUL2_RRR_0_OPCODE_X0 = 37, - FSINGLE_PACK1_UNARY_OPCODE_X0 = 4, - FSINGLE_PACK1_UNARY_OPCODE_Y0 = 4, - FSINGLE_PACK2_RRR_0_OPCODE_X0 = 38, - FSINGLE_SUB1_RRR_0_OPCODE_X0 = 39, - ICOH_UNARY_OPCODE_X1 = 7, - ILL_UNARY_OPCODE_X1 = 8, - ILL_UNARY_OPCODE_Y1 = 9, - IMM8_OPCODE_X0 = 4, - IMM8_OPCODE_X1 = 3, - INV_UNARY_OPCODE_X1 = 9, - IRET_UNARY_OPCODE_X1 = 10, - JALRP_UNARY_OPCODE_X1 = 11, - JALRP_UNARY_OPCODE_Y1 = 10, - JALR_UNARY_OPCODE_X1 = 12, - JALR_UNARY_OPCODE_Y1 = 11, - JAL_JUMP_OPCODE_X1 = 0, - JRP_UNARY_OPCODE_X1 = 13, - JRP_UNARY_OPCODE_Y1 = 12, - JR_UNARY_OPCODE_X1 = 14, - JR_UNARY_OPCODE_Y1 = 13, - JUMP_OPCODE_X1 = 4, - J_JUMP_OPCODE_X1 = 1, - LD1S_ADD_IMM8_OPCODE_X1 = 7, - LD1S_OPCODE_Y2 = 0, - LD1S_UNARY_OPCODE_X1 = 15, - LD1U_ADD_IMM8_OPCODE_X1 = 8, - LD1U_OPCODE_Y2 = 1, - LD1U_UNARY_OPCODE_X1 = 16, - LD2S_ADD_IMM8_OPCODE_X1 = 9, - LD2S_OPCODE_Y2 = 2, - LD2S_UNARY_OPCODE_X1 = 17, - LD2U_ADD_IMM8_OPCODE_X1 = 10, - LD2U_OPCODE_Y2 = 3, - LD2U_UNARY_OPCODE_X1 = 18, - LD4S_ADD_IMM8_OPCODE_X1 = 11, - LD4S_OPCODE_Y2 = 1, - LD4S_UNARY_OPCODE_X1 = 19, - LD4U_ADD_IMM8_OPCODE_X1 = 12, - LD4U_OPCODE_Y2 = 2, - LD4U_UNARY_OPCODE_X1 = 20, - LDNA_ADD_IMM8_OPCODE_X1 = 21, - LDNA_UNARY_OPCODE_X1 = 21, - LDNT1S_ADD_IMM8_OPCODE_X1 = 13, - LDNT1S_UNARY_OPCODE_X1 = 22, - LDNT1U_ADD_IMM8_OPCODE_X1 = 14, - LDNT1U_UNARY_OPCODE_X1 = 23, - LDNT2S_ADD_IMM8_OPCODE_X1 = 15, - LDNT2S_UNARY_OPCODE_X1 = 24, - LDNT2U_ADD_IMM8_OPCODE_X1 = 16, - LDNT2U_UNARY_OPCODE_X1 = 25, - LDNT4S_ADD_IMM8_OPCODE_X1 = 17, - LDNT4S_UNARY_OPCODE_X1 = 26, - LDNT4U_ADD_IMM8_OPCODE_X1 = 18, - LDNT4U_UNARY_OPCODE_X1 = 27, - LDNT_ADD_IMM8_OPCODE_X1 = 19, - LDNT_UNARY_OPCODE_X1 = 28, - LD_ADD_IMM8_OPCODE_X1 = 20, - LD_OPCODE_Y2 = 3, - LD_UNARY_OPCODE_X1 = 29, - LNK_UNARY_OPCODE_X1 = 30, - LNK_UNARY_OPCODE_Y1 = 14, - MFSPR_IMM8_OPCODE_X1 = 22, - MF_UNARY_OPCODE_X1 = 31, - MM_BF_OPCODE_X0 = 7, - MNZ_RRR_0_OPCODE_X0 = 40, - MNZ_RRR_0_OPCODE_X1 = 26, - MNZ_RRR_4_OPCODE_Y0 = 2, - MNZ_RRR_4_OPCODE_Y1 = 2, - MODE_OPCODE_YA2 = 1, - MODE_OPCODE_YB2 = 2, - MODE_OPCODE_YC2 = 3, - MTSPR_IMM8_OPCODE_X1 = 23, - MULAX_RRR_0_OPCODE_X0 = 41, - MULAX_RRR_3_OPCODE_Y0 = 2, - MULA_HS_HS_RRR_0_OPCODE_X0 = 42, - MULA_HS_HS_RRR_9_OPCODE_Y0 = 0, - MULA_HS_HU_RRR_0_OPCODE_X0 = 43, - MULA_HS_LS_RRR_0_OPCODE_X0 = 44, - MULA_HS_LU_RRR_0_OPCODE_X0 = 45, - MULA_HU_HU_RRR_0_OPCODE_X0 = 46, - MULA_HU_HU_RRR_9_OPCODE_Y0 = 1, - MULA_HU_LS_RRR_0_OPCODE_X0 = 47, - MULA_HU_LU_RRR_0_OPCODE_X0 = 48, - MULA_LS_LS_RRR_0_OPCODE_X0 = 49, - MULA_LS_LS_RRR_9_OPCODE_Y0 = 2, - MULA_LS_LU_RRR_0_OPCODE_X0 = 50, - MULA_LU_LU_RRR_0_OPCODE_X0 = 51, - MULA_LU_LU_RRR_9_OPCODE_Y0 = 3, - MULX_RRR_0_OPCODE_X0 = 52, - MULX_RRR_3_OPCODE_Y0 = 3, - MUL_HS_HS_RRR_0_OPCODE_X0 = 53, - MUL_HS_HS_RRR_8_OPCODE_Y0 = 0, - MUL_HS_HU_RRR_0_OPCODE_X0 = 54, - MUL_HS_LS_RRR_0_OPCODE_X0 = 55, - MUL_HS_LU_RRR_0_OPCODE_X0 = 56, - MUL_HU_HU_RRR_0_OPCODE_X0 = 57, - MUL_HU_HU_RRR_8_OPCODE_Y0 = 1, - MUL_HU_LS_RRR_0_OPCODE_X0 = 58, - MUL_HU_LU_RRR_0_OPCODE_X0 = 59, - MUL_LS_LS_RRR_0_OPCODE_X0 = 60, - MUL_LS_LS_RRR_8_OPCODE_Y0 = 2, - MUL_LS_LU_RRR_0_OPCODE_X0 = 61, - MUL_LU_LU_RRR_0_OPCODE_X0 = 62, - MUL_LU_LU_RRR_8_OPCODE_Y0 = 3, - MZ_RRR_0_OPCODE_X0 = 63, - MZ_RRR_0_OPCODE_X1 = 27, - MZ_RRR_4_OPCODE_Y0 = 3, - MZ_RRR_4_OPCODE_Y1 = 3, - NAP_UNARY_OPCODE_X1 = 32, - NOP_UNARY_OPCODE_X0 = 5, - NOP_UNARY_OPCODE_X1 = 33, - NOP_UNARY_OPCODE_Y0 = 5, - NOP_UNARY_OPCODE_Y1 = 15, - NOR_RRR_0_OPCODE_X0 = 64, - NOR_RRR_0_OPCODE_X1 = 28, - NOR_RRR_5_OPCODE_Y0 = 1, - NOR_RRR_5_OPCODE_Y1 = 1, - ORI_IMM8_OPCODE_X0 = 7, - ORI_IMM8_OPCODE_X1 = 24, - OR_RRR_0_OPCODE_X0 = 65, - OR_RRR_0_OPCODE_X1 = 29, - OR_RRR_5_OPCODE_Y0 = 2, - OR_RRR_5_OPCODE_Y1 = 2, - PCNT_UNARY_OPCODE_X0 = 6, - PCNT_UNARY_OPCODE_Y0 = 6, - REVBITS_UNARY_OPCODE_X0 = 7, - REVBITS_UNARY_OPCODE_Y0 = 7, - REVBYTES_UNARY_OPCODE_X0 = 8, - REVBYTES_UNARY_OPCODE_Y0 = 8, - ROTLI_SHIFT_OPCODE_X0 = 1, - ROTLI_SHIFT_OPCODE_X1 = 1, - ROTLI_SHIFT_OPCODE_Y0 = 0, - ROTLI_SHIFT_OPCODE_Y1 = 0, - ROTL_RRR_0_OPCODE_X0 = 66, - ROTL_RRR_0_OPCODE_X1 = 30, - ROTL_RRR_6_OPCODE_Y0 = 0, - ROTL_RRR_6_OPCODE_Y1 = 0, - RRR_0_OPCODE_X0 = 5, - RRR_0_OPCODE_X1 = 5, - RRR_0_OPCODE_Y0 = 5, - RRR_0_OPCODE_Y1 = 6, - RRR_1_OPCODE_Y0 = 6, - RRR_1_OPCODE_Y1 = 7, - RRR_2_OPCODE_Y0 = 7, - RRR_2_OPCODE_Y1 = 8, - RRR_3_OPCODE_Y0 = 8, - RRR_3_OPCODE_Y1 = 9, - RRR_4_OPCODE_Y0 = 9, - RRR_4_OPCODE_Y1 = 10, - RRR_5_OPCODE_Y0 = 10, - RRR_5_OPCODE_Y1 = 11, - RRR_6_OPCODE_Y0 = 11, - RRR_6_OPCODE_Y1 = 12, - RRR_7_OPCODE_Y0 = 12, - RRR_7_OPCODE_Y1 = 13, - RRR_8_OPCODE_Y0 = 13, - RRR_9_OPCODE_Y0 = 14, - SHIFT_OPCODE_X0 = 6, - SHIFT_OPCODE_X1 = 6, - SHIFT_OPCODE_Y0 = 15, - SHIFT_OPCODE_Y1 = 14, - SHL16INSLI_OPCODE_X0 = 7, - SHL16INSLI_OPCODE_X1 = 7, - SHL1ADDX_RRR_0_OPCODE_X0 = 67, - SHL1ADDX_RRR_0_OPCODE_X1 = 31, - SHL1ADDX_RRR_7_OPCODE_Y0 = 1, - SHL1ADDX_RRR_7_OPCODE_Y1 = 1, - SHL1ADD_RRR_0_OPCODE_X0 = 68, - SHL1ADD_RRR_0_OPCODE_X1 = 32, - SHL1ADD_RRR_1_OPCODE_Y0 = 0, - SHL1ADD_RRR_1_OPCODE_Y1 = 0, - SHL2ADDX_RRR_0_OPCODE_X0 = 69, - SHL2ADDX_RRR_0_OPCODE_X1 = 33, - SHL2ADDX_RRR_7_OPCODE_Y0 = 2, - SHL2ADDX_RRR_7_OPCODE_Y1 = 2, - SHL2ADD_RRR_0_OPCODE_X0 = 70, - SHL2ADD_RRR_0_OPCODE_X1 = 34, - SHL2ADD_RRR_1_OPCODE_Y0 = 1, - SHL2ADD_RRR_1_OPCODE_Y1 = 1, - SHL3ADDX_RRR_0_OPCODE_X0 = 71, - SHL3ADDX_RRR_0_OPCODE_X1 = 35, - SHL3ADDX_RRR_7_OPCODE_Y0 = 3, - SHL3ADDX_RRR_7_OPCODE_Y1 = 3, - SHL3ADD_RRR_0_OPCODE_X0 = 72, - SHL3ADD_RRR_0_OPCODE_X1 = 36, - SHL3ADD_RRR_1_OPCODE_Y0 = 2, - SHL3ADD_RRR_1_OPCODE_Y1 = 2, - SHLI_SHIFT_OPCODE_X0 = 2, - SHLI_SHIFT_OPCODE_X1 = 2, - SHLI_SHIFT_OPCODE_Y0 = 1, - SHLI_SHIFT_OPCODE_Y1 = 1, - SHLXI_SHIFT_OPCODE_X0 = 3, - SHLXI_SHIFT_OPCODE_X1 = 3, - SHLX_RRR_0_OPCODE_X0 = 73, - SHLX_RRR_0_OPCODE_X1 = 37, - SHL_RRR_0_OPCODE_X0 = 74, - SHL_RRR_0_OPCODE_X1 = 38, - SHL_RRR_6_OPCODE_Y0 = 1, - SHL_RRR_6_OPCODE_Y1 = 1, - SHRSI_SHIFT_OPCODE_X0 = 4, - SHRSI_SHIFT_OPCODE_X1 = 4, - SHRSI_SHIFT_OPCODE_Y0 = 2, - SHRSI_SHIFT_OPCODE_Y1 = 2, - SHRS_RRR_0_OPCODE_X0 = 75, - SHRS_RRR_0_OPCODE_X1 = 39, - SHRS_RRR_6_OPCODE_Y0 = 2, - SHRS_RRR_6_OPCODE_Y1 = 2, - SHRUI_SHIFT_OPCODE_X0 = 5, - SHRUI_SHIFT_OPCODE_X1 = 5, - SHRUI_SHIFT_OPCODE_Y0 = 3, - SHRUI_SHIFT_OPCODE_Y1 = 3, - SHRUXI_SHIFT_OPCODE_X0 = 6, - SHRUXI_SHIFT_OPCODE_X1 = 6, - SHRUX_RRR_0_OPCODE_X0 = 76, - SHRUX_RRR_0_OPCODE_X1 = 40, - SHRU_RRR_0_OPCODE_X0 = 77, - SHRU_RRR_0_OPCODE_X1 = 41, - SHRU_RRR_6_OPCODE_Y0 = 3, - SHRU_RRR_6_OPCODE_Y1 = 3, - SHUFFLEBYTES_RRR_0_OPCODE_X0 = 78, - ST1_ADD_IMM8_OPCODE_X1 = 25, - ST1_OPCODE_Y2 = 0, - ST1_RRR_0_OPCODE_X1 = 42, - ST2_ADD_IMM8_OPCODE_X1 = 26, - ST2_OPCODE_Y2 = 1, - ST2_RRR_0_OPCODE_X1 = 43, - ST4_ADD_IMM8_OPCODE_X1 = 27, - ST4_OPCODE_Y2 = 2, - ST4_RRR_0_OPCODE_X1 = 44, - STNT1_ADD_IMM8_OPCODE_X1 = 28, - STNT1_RRR_0_OPCODE_X1 = 45, - STNT2_ADD_IMM8_OPCODE_X1 = 29, - STNT2_RRR_0_OPCODE_X1 = 46, - STNT4_ADD_IMM8_OPCODE_X1 = 30, - STNT4_RRR_0_OPCODE_X1 = 47, - STNT_ADD_IMM8_OPCODE_X1 = 31, - STNT_RRR_0_OPCODE_X1 = 48, - ST_ADD_IMM8_OPCODE_X1 = 32, - ST_OPCODE_Y2 = 3, - ST_RRR_0_OPCODE_X1 = 49, - SUBXSC_RRR_0_OPCODE_X0 = 79, - SUBXSC_RRR_0_OPCODE_X1 = 50, - SUBX_RRR_0_OPCODE_X0 = 80, - SUBX_RRR_0_OPCODE_X1 = 51, - SUBX_RRR_0_OPCODE_Y0 = 2, - SUBX_RRR_0_OPCODE_Y1 = 2, - SUB_RRR_0_OPCODE_X0 = 81, - SUB_RRR_0_OPCODE_X1 = 52, - SUB_RRR_0_OPCODE_Y0 = 3, - SUB_RRR_0_OPCODE_Y1 = 3, - SWINT0_UNARY_OPCODE_X1 = 34, - SWINT1_UNARY_OPCODE_X1 = 35, - SWINT2_UNARY_OPCODE_X1 = 36, - SWINT3_UNARY_OPCODE_X1 = 37, - TBLIDXB0_UNARY_OPCODE_X0 = 9, - TBLIDXB0_UNARY_OPCODE_Y0 = 9, - TBLIDXB1_UNARY_OPCODE_X0 = 10, - TBLIDXB1_UNARY_OPCODE_Y0 = 10, - TBLIDXB2_UNARY_OPCODE_X0 = 11, - TBLIDXB2_UNARY_OPCODE_Y0 = 11, - TBLIDXB3_UNARY_OPCODE_X0 = 12, - TBLIDXB3_UNARY_OPCODE_Y0 = 12, - UNARY_RRR_0_OPCODE_X0 = 82, - UNARY_RRR_0_OPCODE_X1 = 53, - UNARY_RRR_1_OPCODE_Y0 = 3, - UNARY_RRR_1_OPCODE_Y1 = 3, - V1ADDI_IMM8_OPCODE_X0 = 8, - V1ADDI_IMM8_OPCODE_X1 = 33, - V1ADDUC_RRR_0_OPCODE_X0 = 83, - V1ADDUC_RRR_0_OPCODE_X1 = 54, - V1ADD_RRR_0_OPCODE_X0 = 84, - V1ADD_RRR_0_OPCODE_X1 = 55, - V1ADIFFU_RRR_0_OPCODE_X0 = 85, - V1AVGU_RRR_0_OPCODE_X0 = 86, - V1CMPEQI_IMM8_OPCODE_X0 = 9, - V1CMPEQI_IMM8_OPCODE_X1 = 34, - V1CMPEQ_RRR_0_OPCODE_X0 = 87, - V1CMPEQ_RRR_0_OPCODE_X1 = 56, - V1CMPLES_RRR_0_OPCODE_X0 = 88, - V1CMPLES_RRR_0_OPCODE_X1 = 57, - V1CMPLEU_RRR_0_OPCODE_X0 = 89, - V1CMPLEU_RRR_0_OPCODE_X1 = 58, - V1CMPLTSI_IMM8_OPCODE_X0 = 10, - V1CMPLTSI_IMM8_OPCODE_X1 = 35, - V1CMPLTS_RRR_0_OPCODE_X0 = 90, - V1CMPLTS_RRR_0_OPCODE_X1 = 59, - V1CMPLTUI_IMM8_OPCODE_X0 = 11, - V1CMPLTUI_IMM8_OPCODE_X1 = 36, - V1CMPLTU_RRR_0_OPCODE_X0 = 91, - V1CMPLTU_RRR_0_OPCODE_X1 = 60, - V1CMPNE_RRR_0_OPCODE_X0 = 92, - V1CMPNE_RRR_0_OPCODE_X1 = 61, - V1DDOTPUA_RRR_0_OPCODE_X0 = 161, - V1DDOTPUSA_RRR_0_OPCODE_X0 = 93, - V1DDOTPUS_RRR_0_OPCODE_X0 = 94, - V1DDOTPU_RRR_0_OPCODE_X0 = 162, - V1DOTPA_RRR_0_OPCODE_X0 = 95, - V1DOTPUA_RRR_0_OPCODE_X0 = 163, - V1DOTPUSA_RRR_0_OPCODE_X0 = 96, - V1DOTPUS_RRR_0_OPCODE_X0 = 97, - V1DOTPU_RRR_0_OPCODE_X0 = 164, - V1DOTP_RRR_0_OPCODE_X0 = 98, - V1INT_H_RRR_0_OPCODE_X0 = 99, - V1INT_H_RRR_0_OPCODE_X1 = 62, - V1INT_L_RRR_0_OPCODE_X0 = 100, - V1INT_L_RRR_0_OPCODE_X1 = 63, - V1MAXUI_IMM8_OPCODE_X0 = 12, - V1MAXUI_IMM8_OPCODE_X1 = 37, - V1MAXU_RRR_0_OPCODE_X0 = 101, - V1MAXU_RRR_0_OPCODE_X1 = 64, - V1MINUI_IMM8_OPCODE_X0 = 13, - V1MINUI_IMM8_OPCODE_X1 = 38, - V1MINU_RRR_0_OPCODE_X0 = 102, - V1MINU_RRR_0_OPCODE_X1 = 65, - V1MNZ_RRR_0_OPCODE_X0 = 103, - V1MNZ_RRR_0_OPCODE_X1 = 66, - V1MULTU_RRR_0_OPCODE_X0 = 104, - V1MULUS_RRR_0_OPCODE_X0 = 105, - V1MULU_RRR_0_OPCODE_X0 = 106, - V1MZ_RRR_0_OPCODE_X0 = 107, - V1MZ_RRR_0_OPCODE_X1 = 67, - V1SADAU_RRR_0_OPCODE_X0 = 108, - V1SADU_RRR_0_OPCODE_X0 = 109, - V1SHLI_SHIFT_OPCODE_X0 = 7, - V1SHLI_SHIFT_OPCODE_X1 = 7, - V1SHL_RRR_0_OPCODE_X0 = 110, - V1SHL_RRR_0_OPCODE_X1 = 68, - V1SHRSI_SHIFT_OPCODE_X0 = 8, - V1SHRSI_SHIFT_OPCODE_X1 = 8, - V1SHRS_RRR_0_OPCODE_X0 = 111, - V1SHRS_RRR_0_OPCODE_X1 = 69, - V1SHRUI_SHIFT_OPCODE_X0 = 9, - V1SHRUI_SHIFT_OPCODE_X1 = 9, - V1SHRU_RRR_0_OPCODE_X0 = 112, - V1SHRU_RRR_0_OPCODE_X1 = 70, - V1SUBUC_RRR_0_OPCODE_X0 = 113, - V1SUBUC_RRR_0_OPCODE_X1 = 71, - V1SUB_RRR_0_OPCODE_X0 = 114, - V1SUB_RRR_0_OPCODE_X1 = 72, - V2ADDI_IMM8_OPCODE_X0 = 14, - V2ADDI_IMM8_OPCODE_X1 = 39, - V2ADDSC_RRR_0_OPCODE_X0 = 115, - V2ADDSC_RRR_0_OPCODE_X1 = 73, - V2ADD_RRR_0_OPCODE_X0 = 116, - V2ADD_RRR_0_OPCODE_X1 = 74, - V2ADIFFS_RRR_0_OPCODE_X0 = 117, - V2AVGS_RRR_0_OPCODE_X0 = 118, - V2CMPEQI_IMM8_OPCODE_X0 = 15, - V2CMPEQI_IMM8_OPCODE_X1 = 40, - V2CMPEQ_RRR_0_OPCODE_X0 = 119, - V2CMPEQ_RRR_0_OPCODE_X1 = 75, - V2CMPLES_RRR_0_OPCODE_X0 = 120, - V2CMPLES_RRR_0_OPCODE_X1 = 76, - V2CMPLEU_RRR_0_OPCODE_X0 = 121, - V2CMPLEU_RRR_0_OPCODE_X1 = 77, - V2CMPLTSI_IMM8_OPCODE_X0 = 16, - V2CMPLTSI_IMM8_OPCODE_X1 = 41, - V2CMPLTS_RRR_0_OPCODE_X0 = 122, - V2CMPLTS_RRR_0_OPCODE_X1 = 78, - V2CMPLTUI_IMM8_OPCODE_X0 = 17, - V2CMPLTUI_IMM8_OPCODE_X1 = 42, - V2CMPLTU_RRR_0_OPCODE_X0 = 123, - V2CMPLTU_RRR_0_OPCODE_X1 = 79, - V2CMPNE_RRR_0_OPCODE_X0 = 124, - V2CMPNE_RRR_0_OPCODE_X1 = 80, - V2DOTPA_RRR_0_OPCODE_X0 = 125, - V2DOTP_RRR_0_OPCODE_X0 = 126, - V2INT_H_RRR_0_OPCODE_X0 = 127, - V2INT_H_RRR_0_OPCODE_X1 = 81, - V2INT_L_RRR_0_OPCODE_X0 = 128, - V2INT_L_RRR_0_OPCODE_X1 = 82, - V2MAXSI_IMM8_OPCODE_X0 = 18, - V2MAXSI_IMM8_OPCODE_X1 = 43, - V2MAXS_RRR_0_OPCODE_X0 = 129, - V2MAXS_RRR_0_OPCODE_X1 = 83, - V2MINSI_IMM8_OPCODE_X0 = 19, - V2MINSI_IMM8_OPCODE_X1 = 44, - V2MINS_RRR_0_OPCODE_X0 = 130, - V2MINS_RRR_0_OPCODE_X1 = 84, - V2MNZ_RRR_0_OPCODE_X0 = 131, - V2MNZ_RRR_0_OPCODE_X1 = 85, - V2MULFSC_RRR_0_OPCODE_X0 = 132, - V2MULS_RRR_0_OPCODE_X0 = 133, - V2MULTS_RRR_0_OPCODE_X0 = 134, - V2MZ_RRR_0_OPCODE_X0 = 135, - V2MZ_RRR_0_OPCODE_X1 = 86, - V2PACKH_RRR_0_OPCODE_X0 = 136, - V2PACKH_RRR_0_OPCODE_X1 = 87, - V2PACKL_RRR_0_OPCODE_X0 = 137, - V2PACKL_RRR_0_OPCODE_X1 = 88, - V2PACKUC_RRR_0_OPCODE_X0 = 138, - V2PACKUC_RRR_0_OPCODE_X1 = 89, - V2SADAS_RRR_0_OPCODE_X0 = 139, - V2SADAU_RRR_0_OPCODE_X0 = 140, - V2SADS_RRR_0_OPCODE_X0 = 141, - V2SADU_RRR_0_OPCODE_X0 = 142, - V2SHLI_SHIFT_OPCODE_X0 = 10, - V2SHLI_SHIFT_OPCODE_X1 = 10, - V2SHLSC_RRR_0_OPCODE_X0 = 143, - V2SHLSC_RRR_0_OPCODE_X1 = 90, - V2SHL_RRR_0_OPCODE_X0 = 144, - V2SHL_RRR_0_OPCODE_X1 = 91, - V2SHRSI_SHIFT_OPCODE_X0 = 11, - V2SHRSI_SHIFT_OPCODE_X1 = 11, - V2SHRS_RRR_0_OPCODE_X0 = 145, - V2SHRS_RRR_0_OPCODE_X1 = 92, - V2SHRUI_SHIFT_OPCODE_X0 = 12, - V2SHRUI_SHIFT_OPCODE_X1 = 12, - V2SHRU_RRR_0_OPCODE_X0 = 146, - V2SHRU_RRR_0_OPCODE_X1 = 93, - V2SUBSC_RRR_0_OPCODE_X0 = 147, - V2SUBSC_RRR_0_OPCODE_X1 = 94, - V2SUB_RRR_0_OPCODE_X0 = 148, - V2SUB_RRR_0_OPCODE_X1 = 95, - V4ADDSC_RRR_0_OPCODE_X0 = 149, - V4ADDSC_RRR_0_OPCODE_X1 = 96, - V4ADD_RRR_0_OPCODE_X0 = 150, - V4ADD_RRR_0_OPCODE_X1 = 97, - V4INT_H_RRR_0_OPCODE_X0 = 151, - V4INT_H_RRR_0_OPCODE_X1 = 98, - V4INT_L_RRR_0_OPCODE_X0 = 152, - V4INT_L_RRR_0_OPCODE_X1 = 99, - V4PACKSC_RRR_0_OPCODE_X0 = 153, - V4PACKSC_RRR_0_OPCODE_X1 = 100, - V4SHLSC_RRR_0_OPCODE_X0 = 154, - V4SHLSC_RRR_0_OPCODE_X1 = 101, - V4SHL_RRR_0_OPCODE_X0 = 155, - V4SHL_RRR_0_OPCODE_X1 = 102, - V4SHRS_RRR_0_OPCODE_X0 = 156, - V4SHRS_RRR_0_OPCODE_X1 = 103, - V4SHRU_RRR_0_OPCODE_X0 = 157, - V4SHRU_RRR_0_OPCODE_X1 = 104, - V4SUBSC_RRR_0_OPCODE_X0 = 158, - V4SUBSC_RRR_0_OPCODE_X1 = 105, - V4SUB_RRR_0_OPCODE_X0 = 159, - V4SUB_RRR_0_OPCODE_X1 = 106, - WH64_UNARY_OPCODE_X1 = 38, - XORI_IMM8_OPCODE_X0 = 20, - XORI_IMM8_OPCODE_X1 = 45, - XOR_RRR_0_OPCODE_X0 = 160, - XOR_RRR_0_OPCODE_X1 = 107, - XOR_RRR_5_OPCODE_Y0 = 3, - XOR_RRR_5_OPCODE_Y1 = 3 -}; - - -#endif /* __ASSEMBLER__ */ - -#endif /* __ARCH_OPCODE_H__ */ diff --git a/arch/tile/include/uapi/arch/opcode_tilepro.h b/arch/tile/include/uapi/arch/opcode_tilepro.h deleted file mode 100644 index 0d633688de63..000000000000 --- a/arch/tile/include/uapi/arch/opcode_tilepro.h +++ /dev/null @@ -1,1473 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* TILEPro opcode information. - * - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * - * - * - * - */ - -#ifndef __ARCH_OPCODE_H__ -#define __ARCH_OPCODE_H__ - -#ifndef __ASSEMBLER__ - -typedef unsigned long long tilepro_bundle_bits; - -/* This is the bit that determines if a bundle is in the Y encoding. */ -#define TILEPRO_BUNDLE_Y_ENCODING_MASK ((tilepro_bundle_bits)1 << 63) - -enum -{ - /* Maximum number of instructions in a bundle (2 for X, 3 for Y). */ - TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE = 3, - - /* How many different pipeline encodings are there? X0, X1, Y0, Y1, Y2. */ - TILEPRO_NUM_PIPELINE_ENCODINGS = 5, - - /* Log base 2 of TILEPRO_BUNDLE_SIZE_IN_BYTES. */ - TILEPRO_LOG2_BUNDLE_SIZE_IN_BYTES = 3, - - /* Instructions take this many bytes. */ - TILEPRO_BUNDLE_SIZE_IN_BYTES = 1 << TILEPRO_LOG2_BUNDLE_SIZE_IN_BYTES, - - /* Log base 2 of TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES. */ - TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES = 3, - - /* Bundles should be aligned modulo this number of bytes. */ - TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES = - (1 << TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES), - - /* Log base 2 of TILEPRO_SN_INSTRUCTION_SIZE_IN_BYTES. */ - TILEPRO_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES = 1, - - /* Static network instructions take this many bytes. */ - TILEPRO_SN_INSTRUCTION_SIZE_IN_BYTES = - (1 << TILEPRO_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES), - - /* Number of registers (some are magic, such as network I/O). */ - TILEPRO_NUM_REGISTERS = 64, - - /* Number of static network registers. */ - TILEPRO_NUM_SN_REGISTERS = 4 -}; - -/* Make a few "tile_" variables to simplify common code between - architectures. */ - -typedef tilepro_bundle_bits tile_bundle_bits; -#define TILE_BUNDLE_SIZE_IN_BYTES TILEPRO_BUNDLE_SIZE_IN_BYTES -#define TILE_BUNDLE_ALIGNMENT_IN_BYTES TILEPRO_BUNDLE_ALIGNMENT_IN_BYTES -#define TILE_LOG2_BUNDLE_ALIGNMENT_IN_BYTES \ - TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES -#define TILE_BPT_BUNDLE TILEPRO_BPT_BUNDLE - -/* 64-bit pattern for a { bpt ; nop } bundle. */ -#define TILEPRO_BPT_BUNDLE 0x400b3cae70166000ULL - -static __inline unsigned int -get_BrOff_SN(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3ff); -} - -static __inline unsigned int -get_BrOff_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x00007fff) | - (((unsigned int)(n >> 20)) & 0x00018000); -} - -static __inline unsigned int -get_BrType_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0xf); -} - -static __inline unsigned int -get_Dest_Imm8_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x0000003f) | - (((unsigned int)(n >> 43)) & 0x000000c0); -} - -static __inline unsigned int -get_Dest_SN(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 2)) & 0x3); -} - -static __inline unsigned int -get_Dest_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3f); -} - -static __inline unsigned int -get_Dest_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x3f); -} - -static __inline unsigned int -get_Dest_Y0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3f); -} - -static __inline unsigned int -get_Dest_Y1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x3f); -} - -static __inline unsigned int -get_Imm16_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xffff); -} - -static __inline unsigned int -get_Imm16_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xffff); -} - -static __inline unsigned int -get_Imm8_SN(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0xff); -} - -static __inline unsigned int -get_Imm8_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xff); -} - -static __inline unsigned int -get_Imm8_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xff); -} - -static __inline unsigned int -get_Imm8_Y0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0xff); -} - -static __inline unsigned int -get_Imm8_Y1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0xff); -} - -static __inline unsigned int -get_ImmOpcodeExtension_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 20)) & 0x7f); -} - -static __inline unsigned int -get_ImmOpcodeExtension_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 51)) & 0x7f); -} - -static __inline unsigned int -get_ImmRROpcodeExtension_SN(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 8)) & 0x3); -} - -static __inline unsigned int -get_JOffLong_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x00007fff) | - (((unsigned int)(n >> 20)) & 0x00018000) | - (((unsigned int)(n >> 14)) & 0x001e0000) | - (((unsigned int)(n >> 16)) & 0x07e00000) | - (((unsigned int)(n >> 31)) & 0x18000000); -} - -static __inline unsigned int -get_JOff_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x00007fff) | - (((unsigned int)(n >> 20)) & 0x00018000) | - (((unsigned int)(n >> 14)) & 0x001e0000) | - (((unsigned int)(n >> 16)) & 0x07e00000) | - (((unsigned int)(n >> 31)) & 0x08000000); -} - -static __inline unsigned int -get_MF_Imm15_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x00003fff) | - (((unsigned int)(n >> 44)) & 0x00004000); -} - -static __inline unsigned int -get_MMEnd_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x1f); -} - -static __inline unsigned int -get_MMEnd_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x1f); -} - -static __inline unsigned int -get_MMStart_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 23)) & 0x1f); -} - -static __inline unsigned int -get_MMStart_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 54)) & 0x1f); -} - -static __inline unsigned int -get_MT_Imm15_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 31)) & 0x0000003f) | - (((unsigned int)(n >> 37)) & 0x00003fc0) | - (((unsigned int)(n >> 44)) & 0x00004000); -} - -static __inline unsigned int -get_Mode(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 63)) & 0x1); -} - -static __inline unsigned int -get_NoRegOpcodeExtension_SN(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0xf); -} - -static __inline unsigned int -get_Opcode_SN(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 10)) & 0x3f); -} - -static __inline unsigned int -get_Opcode_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 28)) & 0x7); -} - -static __inline unsigned int -get_Opcode_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 59)) & 0xf); -} - -static __inline unsigned int -get_Opcode_Y0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 27)) & 0xf); -} - -static __inline unsigned int -get_Opcode_Y1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 59)) & 0xf); -} - -static __inline unsigned int -get_Opcode_Y2(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 56)) & 0x7); -} - -static __inline unsigned int -get_RROpcodeExtension_SN(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 4)) & 0xf); -} - -static __inline unsigned int -get_RRROpcodeExtension_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x1ff); -} - -static __inline unsigned int -get_RRROpcodeExtension_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x1ff); -} - -static __inline unsigned int -get_RRROpcodeExtension_Y0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 18)) & 0x3); -} - -static __inline unsigned int -get_RRROpcodeExtension_Y1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 49)) & 0x3); -} - -static __inline unsigned int -get_RouteOpcodeExtension_SN(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3ff); -} - -static __inline unsigned int -get_S_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 27)) & 0x1); -} - -static __inline unsigned int -get_S_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 58)) & 0x1); -} - -static __inline unsigned int -get_ShAmt_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x1f); -} - -static __inline unsigned int -get_ShAmt_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x1f); -} - -static __inline unsigned int -get_ShAmt_Y0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x1f); -} - -static __inline unsigned int -get_ShAmt_Y1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x1f); -} - -static __inline unsigned int -get_SrcA_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 6)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 6)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 37)) & 0x3f); -} - -static __inline unsigned int -get_SrcA_Y2(tilepro_bundle_bits n) -{ - return (((n >> 26)) & 0x00000001) | - (((unsigned int)(n >> 50)) & 0x0000003e); -} - -static __inline unsigned int -get_SrcBDest_Y2(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 20)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_Y0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x3f); -} - -static __inline unsigned int -get_SrcB_Y1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x3f); -} - -static __inline unsigned int -get_Src_SN(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 0)) & 0x3); -} - -static __inline unsigned int -get_UnOpcodeExtension_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x1f); -} - -static __inline unsigned int -get_UnOpcodeExtension_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x1f); -} - -static __inline unsigned int -get_UnOpcodeExtension_Y0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 12)) & 0x1f); -} - -static __inline unsigned int -get_UnOpcodeExtension_Y1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 43)) & 0x1f); -} - -static __inline unsigned int -get_UnShOpcodeExtension_X0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 17)) & 0x3ff); -} - -static __inline unsigned int -get_UnShOpcodeExtension_X1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 48)) & 0x3ff); -} - -static __inline unsigned int -get_UnShOpcodeExtension_Y0(tilepro_bundle_bits num) -{ - const unsigned int n = (unsigned int)num; - return (((n >> 17)) & 0x7); -} - -static __inline unsigned int -get_UnShOpcodeExtension_Y1(tilepro_bundle_bits n) -{ - return (((unsigned int)(n >> 48)) & 0x7); -} - - -static __inline int -sign_extend(int n, int num_bits) -{ - int shift = (int)(sizeof(int) * 8 - num_bits); - return (n << shift) >> shift; -} - - - -static __inline tilepro_bundle_bits -create_BrOff_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3ff) << 0); -} - -static __inline tilepro_bundle_bits -create_BrOff_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x00007fff)) << 43) | - (((tilepro_bundle_bits)(n & 0x00018000)) << 20); -} - -static __inline tilepro_bundle_bits -create_BrType_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0xf)) << 31); -} - -static __inline tilepro_bundle_bits -create_Dest_Imm8_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x0000003f)) << 31) | - (((tilepro_bundle_bits)(n & 0x000000c0)) << 43); -} - -static __inline tilepro_bundle_bits -create_Dest_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 2); -} - -static __inline tilepro_bundle_bits -create_Dest_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 0); -} - -static __inline tilepro_bundle_bits -create_Dest_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x3f)) << 31); -} - -static __inline tilepro_bundle_bits -create_Dest_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 0); -} - -static __inline tilepro_bundle_bits -create_Dest_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x3f)) << 31); -} - -static __inline tilepro_bundle_bits -create_Imm16_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xffff) << 12); -} - -static __inline tilepro_bundle_bits -create_Imm16_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0xffff)) << 43); -} - -static __inline tilepro_bundle_bits -create_Imm8_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 0); -} - -static __inline tilepro_bundle_bits -create_Imm8_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 12); -} - -static __inline tilepro_bundle_bits -create_Imm8_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0xff)) << 43); -} - -static __inline tilepro_bundle_bits -create_Imm8_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xff) << 12); -} - -static __inline tilepro_bundle_bits -create_Imm8_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0xff)) << 43); -} - -static __inline tilepro_bundle_bits -create_ImmOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x7f) << 20); -} - -static __inline tilepro_bundle_bits -create_ImmOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x7f)) << 51); -} - -static __inline tilepro_bundle_bits -create_ImmRROpcodeExtension_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 8); -} - -static __inline tilepro_bundle_bits -create_JOffLong_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x00007fff)) << 43) | - (((tilepro_bundle_bits)(n & 0x00018000)) << 20) | - (((tilepro_bundle_bits)(n & 0x001e0000)) << 14) | - (((tilepro_bundle_bits)(n & 0x07e00000)) << 16) | - (((tilepro_bundle_bits)(n & 0x18000000)) << 31); -} - -static __inline tilepro_bundle_bits -create_JOff_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x00007fff)) << 43) | - (((tilepro_bundle_bits)(n & 0x00018000)) << 20) | - (((tilepro_bundle_bits)(n & 0x001e0000)) << 14) | - (((tilepro_bundle_bits)(n & 0x07e00000)) << 16) | - (((tilepro_bundle_bits)(n & 0x08000000)) << 31); -} - -static __inline tilepro_bundle_bits -create_MF_Imm15_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x00003fff)) << 37) | - (((tilepro_bundle_bits)(n & 0x00004000)) << 44); -} - -static __inline tilepro_bundle_bits -create_MMEnd_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 18); -} - -static __inline tilepro_bundle_bits -create_MMEnd_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x1f)) << 49); -} - -static __inline tilepro_bundle_bits -create_MMStart_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 23); -} - -static __inline tilepro_bundle_bits -create_MMStart_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x1f)) << 54); -} - -static __inline tilepro_bundle_bits -create_MT_Imm15_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x0000003f)) << 31) | - (((tilepro_bundle_bits)(n & 0x00003fc0)) << 37) | - (((tilepro_bundle_bits)(n & 0x00004000)) << 44); -} - -static __inline tilepro_bundle_bits -create_Mode(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x1)) << 63); -} - -static __inline tilepro_bundle_bits -create_NoRegOpcodeExtension_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xf) << 0); -} - -static __inline tilepro_bundle_bits -create_Opcode_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 10); -} - -static __inline tilepro_bundle_bits -create_Opcode_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x7) << 28); -} - -static __inline tilepro_bundle_bits -create_Opcode_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0xf)) << 59); -} - -static __inline tilepro_bundle_bits -create_Opcode_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xf) << 27); -} - -static __inline tilepro_bundle_bits -create_Opcode_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0xf)) << 59); -} - -static __inline tilepro_bundle_bits -create_Opcode_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x7)) << 56); -} - -static __inline tilepro_bundle_bits -create_RROpcodeExtension_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0xf) << 4); -} - -static __inline tilepro_bundle_bits -create_RRROpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1ff) << 18); -} - -static __inline tilepro_bundle_bits -create_RRROpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x1ff)) << 49); -} - -static __inline tilepro_bundle_bits -create_RRROpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 18); -} - -static __inline tilepro_bundle_bits -create_RRROpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x3)) << 49); -} - -static __inline tilepro_bundle_bits -create_RouteOpcodeExtension_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3ff) << 0); -} - -static __inline tilepro_bundle_bits -create_S_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1) << 27); -} - -static __inline tilepro_bundle_bits -create_S_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x1)) << 58); -} - -static __inline tilepro_bundle_bits -create_ShAmt_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 12); -} - -static __inline tilepro_bundle_bits -create_ShAmt_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x1f)) << 43); -} - -static __inline tilepro_bundle_bits -create_ShAmt_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 12); -} - -static __inline tilepro_bundle_bits -create_ShAmt_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x1f)) << 43); -} - -static __inline tilepro_bundle_bits -create_SrcA_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 6); -} - -static __inline tilepro_bundle_bits -create_SrcA_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x3f)) << 37); -} - -static __inline tilepro_bundle_bits -create_SrcA_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 6); -} - -static __inline tilepro_bundle_bits -create_SrcA_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x3f)) << 37); -} - -static __inline tilepro_bundle_bits -create_SrcA_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x00000001) << 26) | - (((tilepro_bundle_bits)(n & 0x0000003e)) << 50); -} - -static __inline tilepro_bundle_bits -create_SrcBDest_Y2(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 20); -} - -static __inline tilepro_bundle_bits -create_SrcB_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilepro_bundle_bits -create_SrcB_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilepro_bundle_bits -create_SrcB_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3f) << 12); -} - -static __inline tilepro_bundle_bits -create_SrcB_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x3f)) << 43); -} - -static __inline tilepro_bundle_bits -create_Src_SN(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3) << 0); -} - -static __inline tilepro_bundle_bits -create_UnOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 12); -} - -static __inline tilepro_bundle_bits -create_UnOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x1f)) << 43); -} - -static __inline tilepro_bundle_bits -create_UnOpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x1f) << 12); -} - -static __inline tilepro_bundle_bits -create_UnOpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x1f)) << 43); -} - -static __inline tilepro_bundle_bits -create_UnShOpcodeExtension_X0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x3ff) << 17); -} - -static __inline tilepro_bundle_bits -create_UnShOpcodeExtension_X1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x3ff)) << 48); -} - -static __inline tilepro_bundle_bits -create_UnShOpcodeExtension_Y0(int num) -{ - const unsigned int n = (unsigned int)num; - return ((n & 0x7) << 17); -} - -static __inline tilepro_bundle_bits -create_UnShOpcodeExtension_Y1(int num) -{ - const unsigned int n = (unsigned int)num; - return (((tilepro_bundle_bits)(n & 0x7)) << 48); -} - - -enum -{ - ADDBS_U_SPECIAL_0_OPCODE_X0 = 98, - ADDBS_U_SPECIAL_0_OPCODE_X1 = 68, - ADDB_SPECIAL_0_OPCODE_X0 = 1, - ADDB_SPECIAL_0_OPCODE_X1 = 1, - ADDHS_SPECIAL_0_OPCODE_X0 = 99, - ADDHS_SPECIAL_0_OPCODE_X1 = 69, - ADDH_SPECIAL_0_OPCODE_X0 = 2, - ADDH_SPECIAL_0_OPCODE_X1 = 2, - ADDIB_IMM_0_OPCODE_X0 = 1, - ADDIB_IMM_0_OPCODE_X1 = 1, - ADDIH_IMM_0_OPCODE_X0 = 2, - ADDIH_IMM_0_OPCODE_X1 = 2, - ADDI_IMM_0_OPCODE_X0 = 3, - ADDI_IMM_0_OPCODE_X1 = 3, - ADDI_IMM_1_OPCODE_SN = 1, - ADDI_OPCODE_Y0 = 9, - ADDI_OPCODE_Y1 = 7, - ADDLIS_OPCODE_X0 = 1, - ADDLIS_OPCODE_X1 = 2, - ADDLI_OPCODE_X0 = 2, - ADDLI_OPCODE_X1 = 3, - ADDS_SPECIAL_0_OPCODE_X0 = 96, - ADDS_SPECIAL_0_OPCODE_X1 = 66, - ADD_SPECIAL_0_OPCODE_X0 = 3, - ADD_SPECIAL_0_OPCODE_X1 = 3, - ADD_SPECIAL_0_OPCODE_Y0 = 0, - ADD_SPECIAL_0_OPCODE_Y1 = 0, - ADIFFB_U_SPECIAL_0_OPCODE_X0 = 4, - ADIFFH_SPECIAL_0_OPCODE_X0 = 5, - ANDI_IMM_0_OPCODE_X0 = 1, - ANDI_IMM_0_OPCODE_X1 = 4, - ANDI_OPCODE_Y0 = 10, - ANDI_OPCODE_Y1 = 8, - AND_SPECIAL_0_OPCODE_X0 = 6, - AND_SPECIAL_0_OPCODE_X1 = 4, - AND_SPECIAL_2_OPCODE_Y0 = 0, - AND_SPECIAL_2_OPCODE_Y1 = 0, - AULI_OPCODE_X0 = 3, - AULI_OPCODE_X1 = 4, - AVGB_U_SPECIAL_0_OPCODE_X0 = 7, - AVGH_SPECIAL_0_OPCODE_X0 = 8, - BBNST_BRANCH_OPCODE_X1 = 15, - BBNS_BRANCH_OPCODE_X1 = 14, - BBNS_OPCODE_SN = 63, - BBST_BRANCH_OPCODE_X1 = 13, - BBS_BRANCH_OPCODE_X1 = 12, - BBS_OPCODE_SN = 62, - BGEZT_BRANCH_OPCODE_X1 = 7, - BGEZ_BRANCH_OPCODE_X1 = 6, - BGEZ_OPCODE_SN = 61, - BGZT_BRANCH_OPCODE_X1 = 5, - BGZ_BRANCH_OPCODE_X1 = 4, - BGZ_OPCODE_SN = 58, - BITX_UN_0_SHUN_0_OPCODE_X0 = 1, - BITX_UN_0_SHUN_0_OPCODE_Y0 = 1, - BLEZT_BRANCH_OPCODE_X1 = 11, - BLEZ_BRANCH_OPCODE_X1 = 10, - BLEZ_OPCODE_SN = 59, - BLZT_BRANCH_OPCODE_X1 = 9, - BLZ_BRANCH_OPCODE_X1 = 8, - BLZ_OPCODE_SN = 60, - BNZT_BRANCH_OPCODE_X1 = 3, - BNZ_BRANCH_OPCODE_X1 = 2, - BNZ_OPCODE_SN = 57, - BPT_NOREG_RR_IMM_0_OPCODE_SN = 1, - BRANCH_OPCODE_X1 = 5, - BYTEX_UN_0_SHUN_0_OPCODE_X0 = 2, - BYTEX_UN_0_SHUN_0_OPCODE_Y0 = 2, - BZT_BRANCH_OPCODE_X1 = 1, - BZ_BRANCH_OPCODE_X1 = 0, - BZ_OPCODE_SN = 56, - CLZ_UN_0_SHUN_0_OPCODE_X0 = 3, - CLZ_UN_0_SHUN_0_OPCODE_Y0 = 3, - CRC32_32_SPECIAL_0_OPCODE_X0 = 9, - CRC32_8_SPECIAL_0_OPCODE_X0 = 10, - CTZ_UN_0_SHUN_0_OPCODE_X0 = 4, - CTZ_UN_0_SHUN_0_OPCODE_Y0 = 4, - DRAIN_UN_0_SHUN_0_OPCODE_X1 = 1, - DTLBPR_UN_0_SHUN_0_OPCODE_X1 = 2, - DWORD_ALIGN_SPECIAL_0_OPCODE_X0 = 95, - FINV_UN_0_SHUN_0_OPCODE_X1 = 3, - FLUSH_UN_0_SHUN_0_OPCODE_X1 = 4, - FNOP_NOREG_RR_IMM_0_OPCODE_SN = 3, - FNOP_UN_0_SHUN_0_OPCODE_X0 = 5, - FNOP_UN_0_SHUN_0_OPCODE_X1 = 5, - FNOP_UN_0_SHUN_0_OPCODE_Y0 = 5, - FNOP_UN_0_SHUN_0_OPCODE_Y1 = 1, - HALT_NOREG_RR_IMM_0_OPCODE_SN = 0, - ICOH_UN_0_SHUN_0_OPCODE_X1 = 6, - ILL_UN_0_SHUN_0_OPCODE_X1 = 7, - ILL_UN_0_SHUN_0_OPCODE_Y1 = 2, - IMM_0_OPCODE_SN = 0, - IMM_0_OPCODE_X0 = 4, - IMM_0_OPCODE_X1 = 6, - IMM_1_OPCODE_SN = 1, - IMM_OPCODE_0_X0 = 5, - INTHB_SPECIAL_0_OPCODE_X0 = 11, - INTHB_SPECIAL_0_OPCODE_X1 = 5, - INTHH_SPECIAL_0_OPCODE_X0 = 12, - INTHH_SPECIAL_0_OPCODE_X1 = 6, - INTLB_SPECIAL_0_OPCODE_X0 = 13, - INTLB_SPECIAL_0_OPCODE_X1 = 7, - INTLH_SPECIAL_0_OPCODE_X0 = 14, - INTLH_SPECIAL_0_OPCODE_X1 = 8, - INV_UN_0_SHUN_0_OPCODE_X1 = 8, - IRET_UN_0_SHUN_0_OPCODE_X1 = 9, - JALB_OPCODE_X1 = 13, - JALF_OPCODE_X1 = 12, - JALRP_SPECIAL_0_OPCODE_X1 = 9, - JALRR_IMM_1_OPCODE_SN = 3, - JALR_RR_IMM_0_OPCODE_SN = 5, - JALR_SPECIAL_0_OPCODE_X1 = 10, - JB_OPCODE_X1 = 11, - JF_OPCODE_X1 = 10, - JRP_SPECIAL_0_OPCODE_X1 = 11, - JRR_IMM_1_OPCODE_SN = 2, - JR_RR_IMM_0_OPCODE_SN = 4, - JR_SPECIAL_0_OPCODE_X1 = 12, - LBADD_IMM_0_OPCODE_X1 = 22, - LBADD_U_IMM_0_OPCODE_X1 = 23, - LB_OPCODE_Y2 = 0, - LB_UN_0_SHUN_0_OPCODE_X1 = 10, - LB_U_OPCODE_Y2 = 1, - LB_U_UN_0_SHUN_0_OPCODE_X1 = 11, - LHADD_IMM_0_OPCODE_X1 = 24, - LHADD_U_IMM_0_OPCODE_X1 = 25, - LH_OPCODE_Y2 = 2, - LH_UN_0_SHUN_0_OPCODE_X1 = 12, - LH_U_OPCODE_Y2 = 3, - LH_U_UN_0_SHUN_0_OPCODE_X1 = 13, - LNK_SPECIAL_0_OPCODE_X1 = 13, - LWADD_IMM_0_OPCODE_X1 = 26, - LWADD_NA_IMM_0_OPCODE_X1 = 27, - LW_NA_UN_0_SHUN_0_OPCODE_X1 = 24, - LW_OPCODE_Y2 = 4, - LW_UN_0_SHUN_0_OPCODE_X1 = 14, - MAXB_U_SPECIAL_0_OPCODE_X0 = 15, - MAXB_U_SPECIAL_0_OPCODE_X1 = 14, - MAXH_SPECIAL_0_OPCODE_X0 = 16, - MAXH_SPECIAL_0_OPCODE_X1 = 15, - MAXIB_U_IMM_0_OPCODE_X0 = 4, - MAXIB_U_IMM_0_OPCODE_X1 = 5, - MAXIH_IMM_0_OPCODE_X0 = 5, - MAXIH_IMM_0_OPCODE_X1 = 6, - MFSPR_IMM_0_OPCODE_X1 = 7, - MF_UN_0_SHUN_0_OPCODE_X1 = 15, - MINB_U_SPECIAL_0_OPCODE_X0 = 17, - MINB_U_SPECIAL_0_OPCODE_X1 = 16, - MINH_SPECIAL_0_OPCODE_X0 = 18, - MINH_SPECIAL_0_OPCODE_X1 = 17, - MINIB_U_IMM_0_OPCODE_X0 = 6, - MINIB_U_IMM_0_OPCODE_X1 = 8, - MINIH_IMM_0_OPCODE_X0 = 7, - MINIH_IMM_0_OPCODE_X1 = 9, - MM_OPCODE_X0 = 6, - MM_OPCODE_X1 = 7, - MNZB_SPECIAL_0_OPCODE_X0 = 19, - MNZB_SPECIAL_0_OPCODE_X1 = 18, - MNZH_SPECIAL_0_OPCODE_X0 = 20, - MNZH_SPECIAL_0_OPCODE_X1 = 19, - MNZ_SPECIAL_0_OPCODE_X0 = 21, - MNZ_SPECIAL_0_OPCODE_X1 = 20, - MNZ_SPECIAL_1_OPCODE_Y0 = 0, - MNZ_SPECIAL_1_OPCODE_Y1 = 1, - MOVEI_IMM_1_OPCODE_SN = 0, - MOVE_RR_IMM_0_OPCODE_SN = 8, - MTSPR_IMM_0_OPCODE_X1 = 10, - MULHHA_SS_SPECIAL_0_OPCODE_X0 = 22, - MULHHA_SS_SPECIAL_7_OPCODE_Y0 = 0, - MULHHA_SU_SPECIAL_0_OPCODE_X0 = 23, - MULHHA_UU_SPECIAL_0_OPCODE_X0 = 24, - MULHHA_UU_SPECIAL_7_OPCODE_Y0 = 1, - MULHHSA_UU_SPECIAL_0_OPCODE_X0 = 25, - MULHH_SS_SPECIAL_0_OPCODE_X0 = 26, - MULHH_SS_SPECIAL_6_OPCODE_Y0 = 0, - MULHH_SU_SPECIAL_0_OPCODE_X0 = 27, - MULHH_UU_SPECIAL_0_OPCODE_X0 = 28, - MULHH_UU_SPECIAL_6_OPCODE_Y0 = 1, - MULHLA_SS_SPECIAL_0_OPCODE_X0 = 29, - MULHLA_SU_SPECIAL_0_OPCODE_X0 = 30, - MULHLA_US_SPECIAL_0_OPCODE_X0 = 31, - MULHLA_UU_SPECIAL_0_OPCODE_X0 = 32, - MULHLSA_UU_SPECIAL_0_OPCODE_X0 = 33, - MULHLSA_UU_SPECIAL_5_OPCODE_Y0 = 0, - MULHL_SS_SPECIAL_0_OPCODE_X0 = 34, - MULHL_SU_SPECIAL_0_OPCODE_X0 = 35, - MULHL_US_SPECIAL_0_OPCODE_X0 = 36, - MULHL_UU_SPECIAL_0_OPCODE_X0 = 37, - MULLLA_SS_SPECIAL_0_OPCODE_X0 = 38, - MULLLA_SS_SPECIAL_7_OPCODE_Y0 = 2, - MULLLA_SU_SPECIAL_0_OPCODE_X0 = 39, - MULLLA_UU_SPECIAL_0_OPCODE_X0 = 40, - MULLLA_UU_SPECIAL_7_OPCODE_Y0 = 3, - MULLLSA_UU_SPECIAL_0_OPCODE_X0 = 41, - MULLL_SS_SPECIAL_0_OPCODE_X0 = 42, - MULLL_SS_SPECIAL_6_OPCODE_Y0 = 2, - MULLL_SU_SPECIAL_0_OPCODE_X0 = 43, - MULLL_UU_SPECIAL_0_OPCODE_X0 = 44, - MULLL_UU_SPECIAL_6_OPCODE_Y0 = 3, - MVNZ_SPECIAL_0_OPCODE_X0 = 45, - MVNZ_SPECIAL_1_OPCODE_Y0 = 1, - MVZ_SPECIAL_0_OPCODE_X0 = 46, - MVZ_SPECIAL_1_OPCODE_Y0 = 2, - MZB_SPECIAL_0_OPCODE_X0 = 47, - MZB_SPECIAL_0_OPCODE_X1 = 21, - MZH_SPECIAL_0_OPCODE_X0 = 48, - MZH_SPECIAL_0_OPCODE_X1 = 22, - MZ_SPECIAL_0_OPCODE_X0 = 49, - MZ_SPECIAL_0_OPCODE_X1 = 23, - MZ_SPECIAL_1_OPCODE_Y0 = 3, - MZ_SPECIAL_1_OPCODE_Y1 = 2, - NAP_UN_0_SHUN_0_OPCODE_X1 = 16, - NOP_NOREG_RR_IMM_0_OPCODE_SN = 2, - NOP_UN_0_SHUN_0_OPCODE_X0 = 6, - NOP_UN_0_SHUN_0_OPCODE_X1 = 17, - NOP_UN_0_SHUN_0_OPCODE_Y0 = 6, - NOP_UN_0_SHUN_0_OPCODE_Y1 = 3, - NOREG_RR_IMM_0_OPCODE_SN = 0, - NOR_SPECIAL_0_OPCODE_X0 = 50, - NOR_SPECIAL_0_OPCODE_X1 = 24, - NOR_SPECIAL_2_OPCODE_Y0 = 1, - NOR_SPECIAL_2_OPCODE_Y1 = 1, - ORI_IMM_0_OPCODE_X0 = 8, - ORI_IMM_0_OPCODE_X1 = 11, - ORI_OPCODE_Y0 = 11, - ORI_OPCODE_Y1 = 9, - OR_SPECIAL_0_OPCODE_X0 = 51, - OR_SPECIAL_0_OPCODE_X1 = 25, - OR_SPECIAL_2_OPCODE_Y0 = 2, - OR_SPECIAL_2_OPCODE_Y1 = 2, - PACKBS_U_SPECIAL_0_OPCODE_X0 = 103, - PACKBS_U_SPECIAL_0_OPCODE_X1 = 73, - PACKHB_SPECIAL_0_OPCODE_X0 = 52, - PACKHB_SPECIAL_0_OPCODE_X1 = 26, - PACKHS_SPECIAL_0_OPCODE_X0 = 102, - PACKHS_SPECIAL_0_OPCODE_X1 = 72, - PACKLB_SPECIAL_0_OPCODE_X0 = 53, - PACKLB_SPECIAL_0_OPCODE_X1 = 27, - PCNT_UN_0_SHUN_0_OPCODE_X0 = 7, - PCNT_UN_0_SHUN_0_OPCODE_Y0 = 7, - RLI_SHUN_0_OPCODE_X0 = 1, - RLI_SHUN_0_OPCODE_X1 = 1, - RLI_SHUN_0_OPCODE_Y0 = 1, - RLI_SHUN_0_OPCODE_Y1 = 1, - RL_SPECIAL_0_OPCODE_X0 = 54, - RL_SPECIAL_0_OPCODE_X1 = 28, - RL_SPECIAL_3_OPCODE_Y0 = 0, - RL_SPECIAL_3_OPCODE_Y1 = 0, - RR_IMM_0_OPCODE_SN = 0, - S1A_SPECIAL_0_OPCODE_X0 = 55, - S1A_SPECIAL_0_OPCODE_X1 = 29, - S1A_SPECIAL_0_OPCODE_Y0 = 1, - S1A_SPECIAL_0_OPCODE_Y1 = 1, - S2A_SPECIAL_0_OPCODE_X0 = 56, - S2A_SPECIAL_0_OPCODE_X1 = 30, - S2A_SPECIAL_0_OPCODE_Y0 = 2, - S2A_SPECIAL_0_OPCODE_Y1 = 2, - S3A_SPECIAL_0_OPCODE_X0 = 57, - S3A_SPECIAL_0_OPCODE_X1 = 31, - S3A_SPECIAL_5_OPCODE_Y0 = 1, - S3A_SPECIAL_5_OPCODE_Y1 = 1, - SADAB_U_SPECIAL_0_OPCODE_X0 = 58, - SADAH_SPECIAL_0_OPCODE_X0 = 59, - SADAH_U_SPECIAL_0_OPCODE_X0 = 60, - SADB_U_SPECIAL_0_OPCODE_X0 = 61, - SADH_SPECIAL_0_OPCODE_X0 = 62, - SADH_U_SPECIAL_0_OPCODE_X0 = 63, - SBADD_IMM_0_OPCODE_X1 = 28, - SB_OPCODE_Y2 = 5, - SB_SPECIAL_0_OPCODE_X1 = 32, - SEQB_SPECIAL_0_OPCODE_X0 = 64, - SEQB_SPECIAL_0_OPCODE_X1 = 33, - SEQH_SPECIAL_0_OPCODE_X0 = 65, - SEQH_SPECIAL_0_OPCODE_X1 = 34, - SEQIB_IMM_0_OPCODE_X0 = 9, - SEQIB_IMM_0_OPCODE_X1 = 12, - SEQIH_IMM_0_OPCODE_X0 = 10, - SEQIH_IMM_0_OPCODE_X1 = 13, - SEQI_IMM_0_OPCODE_X0 = 11, - SEQI_IMM_0_OPCODE_X1 = 14, - SEQI_OPCODE_Y0 = 12, - SEQI_OPCODE_Y1 = 10, - SEQ_SPECIAL_0_OPCODE_X0 = 66, - SEQ_SPECIAL_0_OPCODE_X1 = 35, - SEQ_SPECIAL_5_OPCODE_Y0 = 2, - SEQ_SPECIAL_5_OPCODE_Y1 = 2, - SHADD_IMM_0_OPCODE_X1 = 29, - SHL8II_IMM_0_OPCODE_SN = 3, - SHLB_SPECIAL_0_OPCODE_X0 = 67, - SHLB_SPECIAL_0_OPCODE_X1 = 36, - SHLH_SPECIAL_0_OPCODE_X0 = 68, - SHLH_SPECIAL_0_OPCODE_X1 = 37, - SHLIB_SHUN_0_OPCODE_X0 = 2, - SHLIB_SHUN_0_OPCODE_X1 = 2, - SHLIH_SHUN_0_OPCODE_X0 = 3, - SHLIH_SHUN_0_OPCODE_X1 = 3, - SHLI_SHUN_0_OPCODE_X0 = 4, - SHLI_SHUN_0_OPCODE_X1 = 4, - SHLI_SHUN_0_OPCODE_Y0 = 2, - SHLI_SHUN_0_OPCODE_Y1 = 2, - SHL_SPECIAL_0_OPCODE_X0 = 69, - SHL_SPECIAL_0_OPCODE_X1 = 38, - SHL_SPECIAL_3_OPCODE_Y0 = 1, - SHL_SPECIAL_3_OPCODE_Y1 = 1, - SHR1_RR_IMM_0_OPCODE_SN = 9, - SHRB_SPECIAL_0_OPCODE_X0 = 70, - SHRB_SPECIAL_0_OPCODE_X1 = 39, - SHRH_SPECIAL_0_OPCODE_X0 = 71, - SHRH_SPECIAL_0_OPCODE_X1 = 40, - SHRIB_SHUN_0_OPCODE_X0 = 5, - SHRIB_SHUN_0_OPCODE_X1 = 5, - SHRIH_SHUN_0_OPCODE_X0 = 6, - SHRIH_SHUN_0_OPCODE_X1 = 6, - SHRI_SHUN_0_OPCODE_X0 = 7, - SHRI_SHUN_0_OPCODE_X1 = 7, - SHRI_SHUN_0_OPCODE_Y0 = 3, - SHRI_SHUN_0_OPCODE_Y1 = 3, - SHR_SPECIAL_0_OPCODE_X0 = 72, - SHR_SPECIAL_0_OPCODE_X1 = 41, - SHR_SPECIAL_3_OPCODE_Y0 = 2, - SHR_SPECIAL_3_OPCODE_Y1 = 2, - SHUN_0_OPCODE_X0 = 7, - SHUN_0_OPCODE_X1 = 8, - SHUN_0_OPCODE_Y0 = 13, - SHUN_0_OPCODE_Y1 = 11, - SH_OPCODE_Y2 = 6, - SH_SPECIAL_0_OPCODE_X1 = 42, - SLTB_SPECIAL_0_OPCODE_X0 = 73, - SLTB_SPECIAL_0_OPCODE_X1 = 43, - SLTB_U_SPECIAL_0_OPCODE_X0 = 74, - SLTB_U_SPECIAL_0_OPCODE_X1 = 44, - SLTEB_SPECIAL_0_OPCODE_X0 = 75, - SLTEB_SPECIAL_0_OPCODE_X1 = 45, - SLTEB_U_SPECIAL_0_OPCODE_X0 = 76, - SLTEB_U_SPECIAL_0_OPCODE_X1 = 46, - SLTEH_SPECIAL_0_OPCODE_X0 = 77, - SLTEH_SPECIAL_0_OPCODE_X1 = 47, - SLTEH_U_SPECIAL_0_OPCODE_X0 = 78, - SLTEH_U_SPECIAL_0_OPCODE_X1 = 48, - SLTE_SPECIAL_0_OPCODE_X0 = 79, - SLTE_SPECIAL_0_OPCODE_X1 = 49, - SLTE_SPECIAL_4_OPCODE_Y0 = 0, - SLTE_SPECIAL_4_OPCODE_Y1 = 0, - SLTE_U_SPECIAL_0_OPCODE_X0 = 80, - SLTE_U_SPECIAL_0_OPCODE_X1 = 50, - SLTE_U_SPECIAL_4_OPCODE_Y0 = 1, - SLTE_U_SPECIAL_4_OPCODE_Y1 = 1, - SLTH_SPECIAL_0_OPCODE_X0 = 81, - SLTH_SPECIAL_0_OPCODE_X1 = 51, - SLTH_U_SPECIAL_0_OPCODE_X0 = 82, - SLTH_U_SPECIAL_0_OPCODE_X1 = 52, - SLTIB_IMM_0_OPCODE_X0 = 12, - SLTIB_IMM_0_OPCODE_X1 = 15, - SLTIB_U_IMM_0_OPCODE_X0 = 13, - SLTIB_U_IMM_0_OPCODE_X1 = 16, - SLTIH_IMM_0_OPCODE_X0 = 14, - SLTIH_IMM_0_OPCODE_X1 = 17, - SLTIH_U_IMM_0_OPCODE_X0 = 15, - SLTIH_U_IMM_0_OPCODE_X1 = 18, - SLTI_IMM_0_OPCODE_X0 = 16, - SLTI_IMM_0_OPCODE_X1 = 19, - SLTI_OPCODE_Y0 = 14, - SLTI_OPCODE_Y1 = 12, - SLTI_U_IMM_0_OPCODE_X0 = 17, - SLTI_U_IMM_0_OPCODE_X1 = 20, - SLTI_U_OPCODE_Y0 = 15, - SLTI_U_OPCODE_Y1 = 13, - SLT_SPECIAL_0_OPCODE_X0 = 83, - SLT_SPECIAL_0_OPCODE_X1 = 53, - SLT_SPECIAL_4_OPCODE_Y0 = 2, - SLT_SPECIAL_4_OPCODE_Y1 = 2, - SLT_U_SPECIAL_0_OPCODE_X0 = 84, - SLT_U_SPECIAL_0_OPCODE_X1 = 54, - SLT_U_SPECIAL_4_OPCODE_Y0 = 3, - SLT_U_SPECIAL_4_OPCODE_Y1 = 3, - SNEB_SPECIAL_0_OPCODE_X0 = 85, - SNEB_SPECIAL_0_OPCODE_X1 = 55, - SNEH_SPECIAL_0_OPCODE_X0 = 86, - SNEH_SPECIAL_0_OPCODE_X1 = 56, - SNE_SPECIAL_0_OPCODE_X0 = 87, - SNE_SPECIAL_0_OPCODE_X1 = 57, - SNE_SPECIAL_5_OPCODE_Y0 = 3, - SNE_SPECIAL_5_OPCODE_Y1 = 3, - SPECIAL_0_OPCODE_X0 = 0, - SPECIAL_0_OPCODE_X1 = 1, - SPECIAL_0_OPCODE_Y0 = 1, - SPECIAL_0_OPCODE_Y1 = 1, - SPECIAL_1_OPCODE_Y0 = 2, - SPECIAL_1_OPCODE_Y1 = 2, - SPECIAL_2_OPCODE_Y0 = 3, - SPECIAL_2_OPCODE_Y1 = 3, - SPECIAL_3_OPCODE_Y0 = 4, - SPECIAL_3_OPCODE_Y1 = 4, - SPECIAL_4_OPCODE_Y0 = 5, - SPECIAL_4_OPCODE_Y1 = 5, - SPECIAL_5_OPCODE_Y0 = 6, - SPECIAL_5_OPCODE_Y1 = 6, - SPECIAL_6_OPCODE_Y0 = 7, - SPECIAL_7_OPCODE_Y0 = 8, - SRAB_SPECIAL_0_OPCODE_X0 = 88, - SRAB_SPECIAL_0_OPCODE_X1 = 58, - SRAH_SPECIAL_0_OPCODE_X0 = 89, - SRAH_SPECIAL_0_OPCODE_X1 = 59, - SRAIB_SHUN_0_OPCODE_X0 = 8, - SRAIB_SHUN_0_OPCODE_X1 = 8, - SRAIH_SHUN_0_OPCODE_X0 = 9, - SRAIH_SHUN_0_OPCODE_X1 = 9, - SRAI_SHUN_0_OPCODE_X0 = 10, - SRAI_SHUN_0_OPCODE_X1 = 10, - SRAI_SHUN_0_OPCODE_Y0 = 4, - SRAI_SHUN_0_OPCODE_Y1 = 4, - SRA_SPECIAL_0_OPCODE_X0 = 90, - SRA_SPECIAL_0_OPCODE_X1 = 60, - SRA_SPECIAL_3_OPCODE_Y0 = 3, - SRA_SPECIAL_3_OPCODE_Y1 = 3, - SUBBS_U_SPECIAL_0_OPCODE_X0 = 100, - SUBBS_U_SPECIAL_0_OPCODE_X1 = 70, - SUBB_SPECIAL_0_OPCODE_X0 = 91, - SUBB_SPECIAL_0_OPCODE_X1 = 61, - SUBHS_SPECIAL_0_OPCODE_X0 = 101, - SUBHS_SPECIAL_0_OPCODE_X1 = 71, - SUBH_SPECIAL_0_OPCODE_X0 = 92, - SUBH_SPECIAL_0_OPCODE_X1 = 62, - SUBS_SPECIAL_0_OPCODE_X0 = 97, - SUBS_SPECIAL_0_OPCODE_X1 = 67, - SUB_SPECIAL_0_OPCODE_X0 = 93, - SUB_SPECIAL_0_OPCODE_X1 = 63, - SUB_SPECIAL_0_OPCODE_Y0 = 3, - SUB_SPECIAL_0_OPCODE_Y1 = 3, - SWADD_IMM_0_OPCODE_X1 = 30, - SWINT0_UN_0_SHUN_0_OPCODE_X1 = 18, - SWINT1_UN_0_SHUN_0_OPCODE_X1 = 19, - SWINT2_UN_0_SHUN_0_OPCODE_X1 = 20, - SWINT3_UN_0_SHUN_0_OPCODE_X1 = 21, - SW_OPCODE_Y2 = 7, - SW_SPECIAL_0_OPCODE_X1 = 64, - TBLIDXB0_UN_0_SHUN_0_OPCODE_X0 = 8, - TBLIDXB0_UN_0_SHUN_0_OPCODE_Y0 = 8, - TBLIDXB1_UN_0_SHUN_0_OPCODE_X0 = 9, - TBLIDXB1_UN_0_SHUN_0_OPCODE_Y0 = 9, - TBLIDXB2_UN_0_SHUN_0_OPCODE_X0 = 10, - TBLIDXB2_UN_0_SHUN_0_OPCODE_Y0 = 10, - TBLIDXB3_UN_0_SHUN_0_OPCODE_X0 = 11, - TBLIDXB3_UN_0_SHUN_0_OPCODE_Y0 = 11, - TNS_UN_0_SHUN_0_OPCODE_X1 = 22, - UN_0_SHUN_0_OPCODE_X0 = 11, - UN_0_SHUN_0_OPCODE_X1 = 11, - UN_0_SHUN_0_OPCODE_Y0 = 5, - UN_0_SHUN_0_OPCODE_Y1 = 5, - WH64_UN_0_SHUN_0_OPCODE_X1 = 23, - XORI_IMM_0_OPCODE_X0 = 2, - XORI_IMM_0_OPCODE_X1 = 21, - XOR_SPECIAL_0_OPCODE_X0 = 94, - XOR_SPECIAL_0_OPCODE_X1 = 65, - XOR_SPECIAL_2_OPCODE_Y0 = 3, - XOR_SPECIAL_2_OPCODE_Y1 = 3 -}; - - -#endif /* __ASSEMBLER__ */ - -#endif /* __ARCH_OPCODE_H__ */ diff --git a/arch/tile/include/uapi/arch/sim.h b/arch/tile/include/uapi/arch/sim.h deleted file mode 100644 index c4183dcd2ea7..000000000000 --- a/arch/tile/include/uapi/arch/sim.h +++ /dev/null @@ -1,644 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file - * - * Provides an API for controlling the simulator at runtime. - */ - -/** - * @addtogroup arch_sim - * @{ - * - * An API for controlling the simulator at runtime. - * - * The simulator's behavior can be modified while it is running. - * For example, human-readable trace output can be enabled and disabled - * around code of interest. - * - * There are two ways to modify simulator behavior: - * programmatically, by calling various sim_* functions, and - * interactively, by entering commands like "sim set functional true" - * at the tile-monitor prompt. Typing "sim help" at that prompt provides - * a list of interactive commands. - * - * All interactive commands can also be executed programmatically by - * passing a string to the sim_command function. - */ - -#ifndef __ARCH_SIM_H__ -#define __ARCH_SIM_H__ - -#include -#include - -#ifndef __ASSEMBLER__ - -#include - - -/** - * Return true if the current program is running under a simulator, - * rather than on real hardware. If running on hardware, other "sim_xxx()" - * calls have no useful effect. - */ -static inline int -sim_is_simulator(void) -{ - return __insn_mfspr(SPR_SIM_CONTROL) != 0; -} - - -/** - * Checkpoint the simulator state to a checkpoint file. - * - * The checkpoint file name is either the default or the name specified - * on the command line with "--checkpoint-file". - */ -static __inline void -sim_checkpoint(void) -{ - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_CHECKPOINT); -} - - -/** - * Report whether or not various kinds of simulator tracing are enabled. - * - * @return The bitwise OR of these values: - * - * SIM_TRACE_CYCLES (--trace-cycles), - * SIM_TRACE_ROUTER (--trace-router), - * SIM_TRACE_REGISTER_WRITES (--trace-register-writes), - * SIM_TRACE_DISASM (--trace-disasm), - * SIM_TRACE_STALL_INFO (--trace-stall-info) - * SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller) - * SIM_TRACE_L2_CACHE (--trace-l2) - * SIM_TRACE_LINES (--trace-lines) - */ -static __inline unsigned int -sim_get_tracing(void) -{ - return __insn_mfspr(SPR_SIM_CONTROL) & SIM_TRACE_FLAG_MASK; -} - - -/** - * Turn on or off different kinds of simulator tracing. - * - * @param mask Either one of these special values: - * - * SIM_TRACE_NONE (turns off tracing), - * SIM_TRACE_ALL (turns on all possible tracing). - * - * or the bitwise OR of these values: - * - * SIM_TRACE_CYCLES (--trace-cycles), - * SIM_TRACE_ROUTER (--trace-router), - * SIM_TRACE_REGISTER_WRITES (--trace-register-writes), - * SIM_TRACE_DISASM (--trace-disasm), - * SIM_TRACE_STALL_INFO (--trace-stall-info) - * SIM_TRACE_MEMORY_CONTROLLER (--trace-memory-controller) - * SIM_TRACE_L2_CACHE (--trace-l2) - * SIM_TRACE_LINES (--trace-lines) - */ -static __inline void -sim_set_tracing(unsigned int mask) -{ - __insn_mtspr(SPR_SIM_CONTROL, SIM_TRACE_SPR_ARG(mask)); -} - - -/** - * Request dumping of different kinds of simulator state. - * - * @param mask Either this special value: - * - * SIM_DUMP_ALL (dump all known state) - * - * or the bitwise OR of these values: - * - * SIM_DUMP_REGS (the register file), - * SIM_DUMP_SPRS (the SPRs), - * SIM_DUMP_ITLB (the iTLB), - * SIM_DUMP_DTLB (the dTLB), - * SIM_DUMP_L1I (the L1 I-cache), - * SIM_DUMP_L1D (the L1 D-cache), - * SIM_DUMP_L2 (the L2 cache), - * SIM_DUMP_SNREGS (the switch register file), - * SIM_DUMP_SNITLB (the switch iTLB), - * SIM_DUMP_SNL1I (the switch L1 I-cache), - * SIM_DUMP_BACKTRACE (the current backtrace) - */ -static __inline void -sim_dump(unsigned int mask) -{ - __insn_mtspr(SPR_SIM_CONTROL, SIM_DUMP_SPR_ARG(mask)); -} - - -/** - * Print a string to the simulator stdout. - * - * @param str The string to be written. - */ -static __inline void -sim_print(const char* str) -{ - for ( ; *str != '\0'; str++) - { - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC | - (*str << _SIM_CONTROL_OPERATOR_BITS)); - } - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC | - (SIM_PUTC_FLUSH_BINARY << _SIM_CONTROL_OPERATOR_BITS)); -} - - -/** - * Print a string to the simulator stdout. - * - * @param str The string to be written (a newline is automatically added). - */ -static __inline void -sim_print_string(const char* str) -{ - for ( ; *str != '\0'; str++) - { - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC | - (*str << _SIM_CONTROL_OPERATOR_BITS)); - } - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PUTC | - (SIM_PUTC_FLUSH_STRING << _SIM_CONTROL_OPERATOR_BITS)); -} - - -/** - * Execute a simulator command string. - * - * Type 'sim help' at the tile-monitor prompt to learn what commands - * are available. Note the use of the tile-monitor "sim" command to - * pass commands to the simulator. - * - * The argument to sim_command() does not include the leading "sim" - * prefix used at the tile-monitor prompt; for example, you might call - * sim_command("trace disasm"). - */ -static __inline void -sim_command(const char* str) -{ - int c; - do - { - c = *str++; - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_COMMAND | - (c << _SIM_CONTROL_OPERATOR_BITS)); - } - while (c); -} - - - -#ifndef __DOXYGEN__ - -/** - * The underlying implementation of "_sim_syscall()". - * - * We use extra "and" instructions to ensure that all the values - * we are passing to the simulator are actually valid in the registers - * (i.e. returned from memory) prior to the SIM_CONTROL spr. - */ -static __inline long _sim_syscall0(int val) -{ - long result; - __asm__ __volatile__ ("mtspr SIM_CONTROL, r0" - : "=R00" (result) : "R00" (val)); - return result; -} - -static __inline long _sim_syscall1(int val, long arg1) -{ - long result; - __asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }" - : "=R00" (result) : "R00" (val), "R01" (arg1)); - return result; -} - -static __inline long _sim_syscall2(int val, long arg1, long arg2) -{ - long result; - __asm__ __volatile__ ("{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }" - : "=R00" (result) - : "R00" (val), "R01" (arg1), "R02" (arg2)); - return result; -} - -/* Note that _sim_syscall3() and higher are technically at risk of - receiving an interrupt right before the mtspr bundle, in which case - the register values for arguments 3 and up may still be in flight - to the core from a stack frame reload. */ - -static __inline long _sim_syscall3(int val, long arg1, long arg2, long arg3) -{ - long result; - __asm__ __volatile__ ("{ and zero, r3, r3 };" - "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }" - : "=R00" (result) - : "R00" (val), "R01" (arg1), "R02" (arg2), - "R03" (arg3)); - return result; -} - -static __inline long _sim_syscall4(int val, long arg1, long arg2, long arg3, - long arg4) -{ - long result; - __asm__ __volatile__ ("{ and zero, r3, r4 };" - "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }" - : "=R00" (result) - : "R00" (val), "R01" (arg1), "R02" (arg2), - "R03" (arg3), "R04" (arg4)); - return result; -} - -static __inline long _sim_syscall5(int val, long arg1, long arg2, long arg3, - long arg4, long arg5) -{ - long result; - __asm__ __volatile__ ("{ and zero, r3, r4; and zero, r5, r5 };" - "{ and zero, r1, r2; mtspr SIM_CONTROL, r0 }" - : "=R00" (result) - : "R00" (val), "R01" (arg1), "R02" (arg2), - "R03" (arg3), "R04" (arg4), "R05" (arg5)); - return result; -} - -/** - * Make a special syscall to the simulator itself, if running under - * simulation. This is used as the implementation of other functions - * and should not be used outside this file. - * - * @param syscall_num The simulator syscall number. - * @param nr The number of additional arguments provided. - * - * @return Varies by syscall. - */ -#define _sim_syscall(syscall_num, nr, args...) \ - _sim_syscall##nr( \ - ((syscall_num) << _SIM_CONTROL_OPERATOR_BITS) | SIM_CONTROL_SYSCALL, \ - ##args) - - -/* Values for the "access_mask" parameters below. */ -#define SIM_WATCHPOINT_READ 1 -#define SIM_WATCHPOINT_WRITE 2 -#define SIM_WATCHPOINT_EXECUTE 4 - - -static __inline int -sim_add_watchpoint(unsigned int process_id, - unsigned long address, - unsigned long size, - unsigned int access_mask, - unsigned long user_data) -{ - return _sim_syscall(SIM_SYSCALL_ADD_WATCHPOINT, 5, process_id, - address, size, access_mask, user_data); -} - - -static __inline int -sim_remove_watchpoint(unsigned int process_id, - unsigned long address, - unsigned long size, - unsigned int access_mask, - unsigned long user_data) -{ - return _sim_syscall(SIM_SYSCALL_REMOVE_WATCHPOINT, 5, process_id, - address, size, access_mask, user_data); -} - - -/** - * Return value from sim_query_watchpoint. - */ -struct SimQueryWatchpointStatus -{ - /** - * 0 if a watchpoint fired, 1 if no watchpoint fired, or -1 for - * error (meaning a bad process_id). - */ - int syscall_status; - - /** - * The address of the watchpoint that fired (this is the address - * passed to sim_add_watchpoint, not an address within that range - * that actually triggered the watchpoint). - */ - unsigned long address; - - /** The arbitrary user_data installed by sim_add_watchpoint. */ - unsigned long user_data; -}; - - -static __inline struct SimQueryWatchpointStatus -sim_query_watchpoint(unsigned int process_id) -{ - struct SimQueryWatchpointStatus status; - long val = SIM_CONTROL_SYSCALL | - (SIM_SYSCALL_QUERY_WATCHPOINT << _SIM_CONTROL_OPERATOR_BITS); - __asm__ __volatile__ ("{ and zero, r1, r1; mtspr SIM_CONTROL, r0 }" - : "=R00" (status.syscall_status), - "=R01" (status.address), - "=R02" (status.user_data) - : "R00" (val), "R01" (process_id)); - return status; -} - - -/* On the simulator, confirm lines have been evicted everywhere. */ -static __inline void -sim_validate_lines_evicted(unsigned long long pa, unsigned long length) -{ -#ifdef __LP64__ - _sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 2, pa, length); -#else - _sim_syscall(SIM_SYSCALL_VALIDATE_LINES_EVICTED, 4, - 0 /* dummy */, (long)(pa), (long)(pa >> 32), length); -#endif -} - - -/* Return the current CPU speed in cycles per second. */ -static __inline long -sim_query_cpu_speed(void) -{ - return _sim_syscall(SIM_SYSCALL_QUERY_CPU_SPEED, 0); -} - -#endif /* !__DOXYGEN__ */ - - - - -/** - * Modify the shaping parameters of a shim. - * - * @param shim The shim to modify. One of: - * SIM_CONTROL_SHAPING_GBE_0 - * SIM_CONTROL_SHAPING_GBE_1 - * SIM_CONTROL_SHAPING_GBE_2 - * SIM_CONTROL_SHAPING_GBE_3 - * SIM_CONTROL_SHAPING_XGBE_0 - * SIM_CONTROL_SHAPING_XGBE_1 - * - * @param type The type of shaping. This should be the same type of - * shaping that is already in place on the shim. One of: - * SIM_CONTROL_SHAPING_MULTIPLIER - * SIM_CONTROL_SHAPING_PPS - * SIM_CONTROL_SHAPING_BPS - * - * @param units The magnitude of the rate. One of: - * SIM_CONTROL_SHAPING_UNITS_SINGLE - * SIM_CONTROL_SHAPING_UNITS_KILO - * SIM_CONTROL_SHAPING_UNITS_MEGA - * SIM_CONTROL_SHAPING_UNITS_GIGA - * - * @param rate The rate to which to change it. This must fit in - * SIM_CONTROL_SHAPING_RATE_BITS bits or a warning is issued and - * the shaping is not changed. - * - * @return 0 if no problems were detected in the arguments to sim_set_shaping - * or 1 if problems were detected (for example, rate does not fit in 17 bits). - */ -static __inline int -sim_set_shaping(unsigned shim, - unsigned type, - unsigned units, - unsigned rate) -{ - if ((rate & ~((1 << SIM_CONTROL_SHAPING_RATE_BITS) - 1)) != 0) - return 1; - - __insn_mtspr(SPR_SIM_CONTROL, SIM_SHAPING_SPR_ARG(shim, type, units, rate)); - return 0; -} - -#ifdef __tilegx__ - -/** Enable a set of mPIPE links. Pass a -1 link_mask to enable all links. */ -static __inline void -sim_enable_mpipe_links(unsigned mpipe, unsigned long link_mask) -{ - __insn_mtspr(SPR_SIM_CONTROL, - (SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE | - (mpipe << 8) | (1 << 16) | ((uint_reg_t)link_mask << 32))); -} - -/** Disable a set of mPIPE links. Pass a -1 link_mask to disable all links. */ -static __inline void -sim_disable_mpipe_links(unsigned mpipe, unsigned long link_mask) -{ - __insn_mtspr(SPR_SIM_CONTROL, - (SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE | - (mpipe << 8) | (0 << 16) | ((uint_reg_t)link_mask << 32))); -} - -#endif /* __tilegx__ */ - - -/* - * An API for changing "functional" mode. - */ - -#ifndef __DOXYGEN__ - -#define sim_enable_functional() \ - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_ENABLE_FUNCTIONAL) - -#define sim_disable_functional() \ - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_DISABLE_FUNCTIONAL) - -#endif /* __DOXYGEN__ */ - - -/* - * Profiler support. - */ - -/** - * Turn profiling on for the current task. - * - * Note that this has no effect if run in an environment without - * profiling support (thus, the proper flags to the simulator must - * be supplied). - */ -static __inline void -sim_profiler_enable(void) -{ - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_ENABLE); -} - - -/** Turn profiling off for the current task. */ -static __inline void -sim_profiler_disable(void) -{ - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_DISABLE); -} - - -/** - * Turn profiling on or off for the current task. - * - * @param enabled If true, turns on profiling. If false, turns it off. - * - * Note that this has no effect if run in an environment without - * profiling support (thus, the proper flags to the simulator must - * be supplied). - */ -static __inline void -sim_profiler_set_enabled(int enabled) -{ - int val = - enabled ? SIM_CONTROL_PROFILER_ENABLE : SIM_CONTROL_PROFILER_DISABLE; - __insn_mtspr(SPR_SIM_CONTROL, val); -} - - -/** - * Return true if and only if profiling is currently enabled - * for the current task. - * - * This returns false even if sim_profiler_enable() was called - * if the current execution environment does not support profiling. - */ -static __inline int -sim_profiler_is_enabled(void) -{ - return ((__insn_mfspr(SPR_SIM_CONTROL) & SIM_PROFILER_ENABLED_MASK) != 0); -} - - -/** - * Reset profiling counters to zero for the current task. - * - * Resetting can be done while profiling is enabled. It does not affect - * the chip-wide profiling counters. - */ -static __inline void -sim_profiler_clear(void) -{ - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_PROFILER_CLEAR); -} - - -/** - * Enable specified chip-level profiling counters. - * - * Does not affect the per-task profiling counters. - * - * @param mask Either this special value: - * - * SIM_CHIP_ALL (enables all chip-level components). - * - * or the bitwise OR of these values: - * - * SIM_CHIP_MEMCTL (enable all memory controllers) - * SIM_CHIP_XAUI (enable all XAUI controllers) - * SIM_CHIP_MPIPE (enable all MPIPE controllers) - */ -static __inline void -sim_profiler_chip_enable(unsigned int mask) -{ - __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask)); -} - - -/** - * Disable specified chip-level profiling counters. - * - * Does not affect the per-task profiling counters. - * - * @param mask Either this special value: - * - * SIM_CHIP_ALL (disables all chip-level components). - * - * or the bitwise OR of these values: - * - * SIM_CHIP_MEMCTL (disable all memory controllers) - * SIM_CHIP_XAUI (disable all XAUI controllers) - * SIM_CHIP_MPIPE (disable all MPIPE controllers) - */ -static __inline void -sim_profiler_chip_disable(unsigned int mask) -{ - __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask)); -} - - -/** - * Reset specified chip-level profiling counters to zero. - * - * Does not affect the per-task profiling counters. - * - * @param mask Either this special value: - * - * SIM_CHIP_ALL (clears all chip-level components). - * - * or the bitwise OR of these values: - * - * SIM_CHIP_MEMCTL (clear all memory controllers) - * SIM_CHIP_XAUI (clear all XAUI controllers) - * SIM_CHIP_MPIPE (clear all MPIPE controllers) - */ -static __inline void -sim_profiler_chip_clear(unsigned int mask) -{ - __insn_mtspr(SPR_SIM_CONTROL, SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask)); -} - - -/* - * Event support. - */ - -#ifndef __DOXYGEN__ - -static __inline void -sim_event_begin(unsigned int x) -{ -#if defined(__tile__) && !defined(__NO_EVENT_SPR__) - __insn_mtspr(SPR_EVENT_BEGIN, x); -#endif -} - -static __inline void -sim_event_end(unsigned int x) -{ -#if defined(__tile__) && !defined(__NO_EVENT_SPR__) - __insn_mtspr(SPR_EVENT_END, x); -#endif -} - -#endif /* !__DOXYGEN__ */ - -#endif /* !__ASSEMBLER__ */ - -#endif /* !__ARCH_SIM_H__ */ - -/** @} */ diff --git a/arch/tile/include/uapi/arch/sim_def.h b/arch/tile/include/uapi/arch/sim_def.h deleted file mode 100644 index f74f9943770d..000000000000 --- a/arch/tile/include/uapi/arch/sim_def.h +++ /dev/null @@ -1,506 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/** - * @file - * - * Some low-level simulator definitions. - */ - -#ifndef __ARCH_SIM_DEF_H__ -#define __ARCH_SIM_DEF_H__ - - -/** - * Internal: the low bits of the SIM_CONTROL_* SPR values specify - * the operation to perform, and the remaining bits are - * an operation-specific parameter (often unused). - */ -#define _SIM_CONTROL_OPERATOR_BITS 8 - - -/* - * Values which can be written to SPR_SIM_CONTROL. - */ - -/** If written to SPR_SIM_CONTROL, stops profiling. */ -#define SIM_CONTROL_PROFILER_DISABLE 0 - -/** If written to SPR_SIM_CONTROL, starts profiling. */ -#define SIM_CONTROL_PROFILER_ENABLE 1 - -/** If written to SPR_SIM_CONTROL, clears profiling counters. */ -#define SIM_CONTROL_PROFILER_CLEAR 2 - -/** If written to SPR_SIM_CONTROL, checkpoints the simulator. */ -#define SIM_CONTROL_CHECKPOINT 3 - -/** - * If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8), - * sets the tracing mask to the given mask. See "sim_set_tracing()". - */ -#define SIM_CONTROL_SET_TRACING 4 - -/** - * If written to SPR_SIM_CONTROL, combined with a mask (shifted by 8), - * dumps the requested items of machine state to the log. - */ -#define SIM_CONTROL_DUMP 5 - -/** If written to SPR_SIM_CONTROL, clears chip-level profiling counters. */ -#define SIM_CONTROL_PROFILER_CHIP_CLEAR 6 - -/** If written to SPR_SIM_CONTROL, disables chip-level profiling. */ -#define SIM_CONTROL_PROFILER_CHIP_DISABLE 7 - -/** If written to SPR_SIM_CONTROL, enables chip-level profiling. */ -#define SIM_CONTROL_PROFILER_CHIP_ENABLE 8 - -/** If written to SPR_SIM_CONTROL, enables chip-level functional mode */ -#define SIM_CONTROL_ENABLE_FUNCTIONAL 9 - -/** If written to SPR_SIM_CONTROL, disables chip-level functional mode. */ -#define SIM_CONTROL_DISABLE_FUNCTIONAL 10 - -/** - * If written to SPR_SIM_CONTROL, enables chip-level functional mode. - * All tiles must perform this write for functional mode to be enabled. - * Ignored in naked boot mode unless --functional is specified. - * WARNING: Only the hypervisor startup code should use this! - */ -#define SIM_CONTROL_ENABLE_FUNCTIONAL_BARRIER 11 - -/** - * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8), - * writes a string directly to the simulator output. Written to once for - * each character in the string, plus a final NUL. Instead of NUL, - * you can also use "SIM_PUTC_FLUSH_STRING" or "SIM_PUTC_FLUSH_BINARY". - */ -/* ISSUE: Document the meaning of "newline", and the handling of NUL. */ -#define SIM_CONTROL_PUTC 12 - -/** - * If written to SPR_SIM_CONTROL, clears the --grind-coherence state for - * this core. This is intended to be used before a loop that will - * invalidate the cache by loading new data and evicting all current data. - * Generally speaking, this API should only be used by system code. - */ -#define SIM_CONTROL_GRINDER_CLEAR 13 - -/** If written to SPR_SIM_CONTROL, shuts down the simulator. */ -#define SIM_CONTROL_SHUTDOWN 14 - -/** - * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8), - * indicates that a fork syscall just created the given process. - */ -#define SIM_CONTROL_OS_FORK 15 - -/** - * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8), - * indicates that an exit syscall was just executed by the given process. - */ -#define SIM_CONTROL_OS_EXIT 16 - -/** - * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8), - * indicates that the OS just switched to the given process. - */ -#define SIM_CONTROL_OS_SWITCH 17 - -/** - * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8), - * indicates that an exec syscall was just executed. Written to once for - * each character in the executable name, plus a final NUL. - */ -#define SIM_CONTROL_OS_EXEC 18 - -/** - * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8), - * indicates that an interpreter (PT_INTERP) was loaded. Written to once - * for each character in "ADDR:PATH", plus a final NUL, where "ADDR" is a - * hex load address starting with "0x", and "PATH" is the executable name. - */ -#define SIM_CONTROL_OS_INTERP 19 - -/** - * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8), - * indicates that a dll was loaded. Written to once for each character - * in "ADDR:PATH", plus a final NUL, where "ADDR" is a hexadecimal load - * address starting with "0x", and "PATH" is the executable name. - */ -#define SIM_CONTROL_DLOPEN 20 - -/** - * If written to SPR_SIM_CONTROL, combined with a character (shifted by 8), - * indicates that a dll was unloaded. Written to once for each character - * in "ADDR", plus a final NUL, where "ADDR" is a hexadecimal load - * address starting with "0x". - */ -#define SIM_CONTROL_DLCLOSE 21 - -/** - * If written to SPR_SIM_CONTROL, combined with a flag (shifted by 8), - * indicates whether to allow data reads to remotely-cached - * dirty cache lines to be cached locally without grinder warnings or - * assertions (used by Linux kernel fast memcpy). - */ -#define SIM_CONTROL_ALLOW_MULTIPLE_CACHING 22 - -/** If written to SPR_SIM_CONTROL, enables memory tracing. */ -#define SIM_CONTROL_ENABLE_MEM_LOGGING 23 - -/** If written to SPR_SIM_CONTROL, disables memory tracing. */ -#define SIM_CONTROL_DISABLE_MEM_LOGGING 24 - -/** - * If written to SPR_SIM_CONTROL, changes the shaping parameters of one of - * the gbe or xgbe shims. Must specify the shim id, the type, the units, and - * the rate, as defined in SIM_SHAPING_SPR_ARG. - */ -#define SIM_CONTROL_SHAPING 25 - -/** - * If written to SPR_SIM_CONTROL, combined with character (shifted by 8), - * requests that a simulator command be executed. Written to once for each - * character in the command, plus a final NUL. - */ -#define SIM_CONTROL_COMMAND 26 - -/** - * If written to SPR_SIM_CONTROL, indicates that the simulated system - * is panicking, to allow debugging via --debug-on-panic. - */ -#define SIM_CONTROL_PANIC 27 - -/** - * If written to SPR_SIM_CONTROL, triggers a simulator syscall. - * See "sim_syscall()" for more info. - */ -#define SIM_CONTROL_SYSCALL 32 - -/** - * If written to SPR_SIM_CONTROL, combined with a pid (shifted by 8), - * provides the pid that subsequent SIM_CONTROL_OS_FORK writes should - * use as the pid, rather than the default previous SIM_CONTROL_OS_SWITCH. - */ -#define SIM_CONTROL_OS_FORK_PARENT 33 - -/** - * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number - * (shifted by 8), clears the pending magic data section. The cleared - * pending magic data section and any subsequently appended magic bytes - * will only take effect when the classifier blast programmer is run. - */ -#define SIM_CONTROL_CLEAR_MPIPE_MAGIC_BYTES 34 - -/** - * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number - * (shifted by 8) and a byte of data (shifted by 16), appends that byte - * to the shim's pending magic data section. The pending magic data - * section takes effect when the classifier blast programmer is run. - */ -#define SIM_CONTROL_APPEND_MPIPE_MAGIC_BYTE 35 - -/** - * If written to SPR_SIM_CONTROL, combined with a mPIPE shim number - * (shifted by 8), an enable=1/disable=0 bit (shifted by 16), and a - * mask of links (shifted by 32), enable or disable the corresponding - * mPIPE links. - */ -#define SIM_CONTROL_ENABLE_MPIPE_LINK_MAGIC_BYTE 36 - - -/* - * Syscall numbers for use with "sim_syscall()". - */ - -/** Syscall number for sim_add_watchpoint(). */ -#define SIM_SYSCALL_ADD_WATCHPOINT 2 - -/** Syscall number for sim_remove_watchpoint(). */ -#define SIM_SYSCALL_REMOVE_WATCHPOINT 3 - -/** Syscall number for sim_query_watchpoint(). */ -#define SIM_SYSCALL_QUERY_WATCHPOINT 4 - -/** - * Syscall number that asserts that the cache lines whose 64-bit PA - * is passed as the second argument to sim_syscall(), and over a - * range passed as the third argument, are no longer in cache. - * The simulator raises an error if this is not the case. - */ -#define SIM_SYSCALL_VALIDATE_LINES_EVICTED 5 - -/** Syscall number for sim_query_cpu_speed(). */ -#define SIM_SYSCALL_QUERY_CPU_SPEED 6 - - -/* - * Bit masks which can be shifted by 8, combined with - * SIM_CONTROL_SET_TRACING, and written to SPR_SIM_CONTROL. - */ - -/** - * @addtogroup arch_sim - * @{ - */ - -/** Enable --trace-cycle when passed to simulator_set_tracing(). */ -#define SIM_TRACE_CYCLES 0x01 - -/** Enable --trace-router when passed to simulator_set_tracing(). */ -#define SIM_TRACE_ROUTER 0x02 - -/** Enable --trace-register-writes when passed to simulator_set_tracing(). */ -#define SIM_TRACE_REGISTER_WRITES 0x04 - -/** Enable --trace-disasm when passed to simulator_set_tracing(). */ -#define SIM_TRACE_DISASM 0x08 - -/** Enable --trace-stall-info when passed to simulator_set_tracing(). */ -#define SIM_TRACE_STALL_INFO 0x10 - -/** Enable --trace-memory-controller when passed to simulator_set_tracing(). */ -#define SIM_TRACE_MEMORY_CONTROLLER 0x20 - -/** Enable --trace-l2 when passed to simulator_set_tracing(). */ -#define SIM_TRACE_L2_CACHE 0x40 - -/** Enable --trace-lines when passed to simulator_set_tracing(). */ -#define SIM_TRACE_LINES 0x80 - -/** Turn off all tracing when passed to simulator_set_tracing(). */ -#define SIM_TRACE_NONE 0 - -/** Turn on all tracing when passed to simulator_set_tracing(). */ -#define SIM_TRACE_ALL (-1) - -/** @} */ - -/** Computes the value to write to SPR_SIM_CONTROL to set tracing flags. */ -#define SIM_TRACE_SPR_ARG(mask) \ - (SIM_CONTROL_SET_TRACING | ((mask) << _SIM_CONTROL_OPERATOR_BITS)) - - -/* - * Bit masks which can be shifted by 8, combined with - * SIM_CONTROL_DUMP, and written to SPR_SIM_CONTROL. - */ - -/** - * @addtogroup arch_sim - * @{ - */ - -/** Dump the general-purpose registers. */ -#define SIM_DUMP_REGS 0x001 - -/** Dump the SPRs. */ -#define SIM_DUMP_SPRS 0x002 - -/** Dump the ITLB. */ -#define SIM_DUMP_ITLB 0x004 - -/** Dump the DTLB. */ -#define SIM_DUMP_DTLB 0x008 - -/** Dump the L1 I-cache. */ -#define SIM_DUMP_L1I 0x010 - -/** Dump the L1 D-cache. */ -#define SIM_DUMP_L1D 0x020 - -/** Dump the L2 cache. */ -#define SIM_DUMP_L2 0x040 - -/** Dump the switch registers. */ -#define SIM_DUMP_SNREGS 0x080 - -/** Dump the switch ITLB. */ -#define SIM_DUMP_SNITLB 0x100 - -/** Dump the switch L1 I-cache. */ -#define SIM_DUMP_SNL1I 0x200 - -/** Dump the current backtrace. */ -#define SIM_DUMP_BACKTRACE 0x400 - -/** Only dump valid lines in caches. */ -#define SIM_DUMP_VALID_LINES 0x800 - -/** Dump everything that is dumpable. */ -#define SIM_DUMP_ALL (-1 & ~SIM_DUMP_VALID_LINES) - -/** @} */ - -/** Computes the value to write to SPR_SIM_CONTROL to dump machine state. */ -#define SIM_DUMP_SPR_ARG(mask) \ - (SIM_CONTROL_DUMP | ((mask) << _SIM_CONTROL_OPERATOR_BITS)) - - -/* - * Bit masks which can be shifted by 8, combined with - * SIM_CONTROL_PROFILER_CHIP_xxx, and written to SPR_SIM_CONTROL. - */ - -/** - * @addtogroup arch_sim - * @{ - */ - -/** Use with SIM_PROFILER_CHIP_xxx to control the memory controllers. */ -#define SIM_CHIP_MEMCTL 0x001 - -/** Use with SIM_PROFILER_CHIP_xxx to control the XAUI interface. */ -#define SIM_CHIP_XAUI 0x002 - -/** Use with SIM_PROFILER_CHIP_xxx to control the PCIe interface. */ -#define SIM_CHIP_PCIE 0x004 - -/** Use with SIM_PROFILER_CHIP_xxx to control the MPIPE interface. */ -#define SIM_CHIP_MPIPE 0x008 - -/** Use with SIM_PROFILER_CHIP_xxx to control the TRIO interface. */ -#define SIM_CHIP_TRIO 0x010 - -/** Reference all chip devices. */ -#define SIM_CHIP_ALL (-1) - -/** @} */ - -/** Computes the value to write to SPR_SIM_CONTROL to clear chip statistics. */ -#define SIM_PROFILER_CHIP_CLEAR_SPR_ARG(mask) \ - (SIM_CONTROL_PROFILER_CHIP_CLEAR | ((mask) << _SIM_CONTROL_OPERATOR_BITS)) - -/** Computes the value to write to SPR_SIM_CONTROL to disable chip statistics.*/ -#define SIM_PROFILER_CHIP_DISABLE_SPR_ARG(mask) \ - (SIM_CONTROL_PROFILER_CHIP_DISABLE | ((mask) << _SIM_CONTROL_OPERATOR_BITS)) - -/** Computes the value to write to SPR_SIM_CONTROL to enable chip statistics. */ -#define SIM_PROFILER_CHIP_ENABLE_SPR_ARG(mask) \ - (SIM_CONTROL_PROFILER_CHIP_ENABLE | ((mask) << _SIM_CONTROL_OPERATOR_BITS)) - - - -/* Shim bitrate controls. */ - -/** The number of bits used to store the shim id. */ -#define SIM_CONTROL_SHAPING_SHIM_ID_BITS 3 - -/** - * @addtogroup arch_sim - * @{ - */ - -/** Change the gbe 0 bitrate. */ -#define SIM_CONTROL_SHAPING_GBE_0 0x0 - -/** Change the gbe 1 bitrate. */ -#define SIM_CONTROL_SHAPING_GBE_1 0x1 - -/** Change the gbe 2 bitrate. */ -#define SIM_CONTROL_SHAPING_GBE_2 0x2 - -/** Change the gbe 3 bitrate. */ -#define SIM_CONTROL_SHAPING_GBE_3 0x3 - -/** Change the xgbe 0 bitrate. */ -#define SIM_CONTROL_SHAPING_XGBE_0 0x4 - -/** Change the xgbe 1 bitrate. */ -#define SIM_CONTROL_SHAPING_XGBE_1 0x5 - -/** The type of shaping to do. */ -#define SIM_CONTROL_SHAPING_TYPE_BITS 2 - -/** Control the multiplier. */ -#define SIM_CONTROL_SHAPING_MULTIPLIER 0 - -/** Control the PPS. */ -#define SIM_CONTROL_SHAPING_PPS 1 - -/** Control the BPS. */ -#define SIM_CONTROL_SHAPING_BPS 2 - -/** The number of bits for the units for the shaping parameter. */ -#define SIM_CONTROL_SHAPING_UNITS_BITS 2 - -/** Provide a number in single units. */ -#define SIM_CONTROL_SHAPING_UNITS_SINGLE 0 - -/** Provide a number in kilo units. */ -#define SIM_CONTROL_SHAPING_UNITS_KILO 1 - -/** Provide a number in mega units. */ -#define SIM_CONTROL_SHAPING_UNITS_MEGA 2 - -/** Provide a number in giga units. */ -#define SIM_CONTROL_SHAPING_UNITS_GIGA 3 - -/** @} */ - -/** How many bits are available for the rate. */ -#define SIM_CONTROL_SHAPING_RATE_BITS \ - (32 - (_SIM_CONTROL_OPERATOR_BITS + \ - SIM_CONTROL_SHAPING_SHIM_ID_BITS + \ - SIM_CONTROL_SHAPING_TYPE_BITS + \ - SIM_CONTROL_SHAPING_UNITS_BITS)) - -/** Computes the value to write to SPR_SIM_CONTROL to change a bitrate. */ -#define SIM_SHAPING_SPR_ARG(shim, type, units, rate) \ - (SIM_CONTROL_SHAPING | \ - ((shim) | \ - ((type) << (SIM_CONTROL_SHAPING_SHIM_ID_BITS)) | \ - ((units) << (SIM_CONTROL_SHAPING_SHIM_ID_BITS + \ - SIM_CONTROL_SHAPING_TYPE_BITS)) | \ - ((rate) << (SIM_CONTROL_SHAPING_SHIM_ID_BITS + \ - SIM_CONTROL_SHAPING_TYPE_BITS + \ - SIM_CONTROL_SHAPING_UNITS_BITS))) << _SIM_CONTROL_OPERATOR_BITS) - - -/* - * Values returned when reading SPR_SIM_CONTROL. - * ISSUE: These names should share a longer common prefix. - */ - -/** - * When reading SPR_SIM_CONTROL, the mask of simulator tracing bits - * (SIM_TRACE_xxx values). - */ -#define SIM_TRACE_FLAG_MASK 0xFFFF - -/** When reading SPR_SIM_CONTROL, the mask for whether profiling is enabled. */ -#define SIM_PROFILER_ENABLED_MASK 0x10000 - - -/* - * Special arguments for "SIM_CONTROL_PUTC". - */ - -/** - * Flag value for forcing a PUTC string-flush, including - * coordinate/cycle prefix and newline. - */ -#define SIM_PUTC_FLUSH_STRING 0x100 - -/** - * Flag value for forcing a PUTC binary-data-flush, which skips the - * prefix and does not append a newline. - */ -#define SIM_PUTC_FLUSH_BINARY 0x101 - - -#endif /* __ARCH_SIM_DEF_H__ */ diff --git a/arch/tile/include/uapi/arch/spr_def.h b/arch/tile/include/uapi/arch/spr_def.h deleted file mode 100644 index 743428615cda..000000000000 --- a/arch/tile/include/uapi/arch/spr_def.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _UAPI__ARCH_SPR_DEF_H__ -#define _UAPI__ARCH_SPR_DEF_H__ - -/* Include the proper base SPR definition file. */ -#ifdef __tilegx__ -#include -#else -#include -#endif - - -#endif /* _UAPI__ARCH_SPR_DEF_H__ */ diff --git a/arch/tile/include/uapi/arch/spr_def_32.h b/arch/tile/include/uapi/arch/spr_def_32.h deleted file mode 100644 index 64122d6160e1..000000000000 --- a/arch/tile/include/uapi/arch/spr_def_32.h +++ /dev/null @@ -1,256 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef __DOXYGEN__ - -#ifndef __ARCH_SPR_DEF_32_H__ -#define __ARCH_SPR_DEF_32_H__ - -#define SPR_AUX_PERF_COUNT_0 0x6005 -#define SPR_AUX_PERF_COUNT_1 0x6006 -#define SPR_AUX_PERF_COUNT_CTL 0x6007 -#define SPR_AUX_PERF_COUNT_STS 0x6008 -#define SPR_CYCLE_HIGH 0x4e06 -#define SPR_CYCLE_LOW 0x4e07 -#define SPR_DMA_BYTE 0x3900 -#define SPR_DMA_CHUNK_SIZE 0x3901 -#define SPR_DMA_CTR 0x3902 -#define SPR_DMA_CTR__REQUEST_MASK 0x1 -#define SPR_DMA_CTR__SUSPEND_MASK 0x2 -#define SPR_DMA_DST_ADDR 0x3903 -#define SPR_DMA_DST_CHUNK_ADDR 0x3904 -#define SPR_DMA_SRC_ADDR 0x3905 -#define SPR_DMA_SRC_CHUNK_ADDR 0x3906 -#define SPR_DMA_STATUS__DONE_MASK 0x1 -#define SPR_DMA_STATUS__BUSY_MASK 0x2 -#define SPR_DMA_STATUS__RUNNING_MASK 0x10 -#define SPR_DMA_STRIDE 0x3907 -#define SPR_DMA_USER_STATUS 0x3908 -#define SPR_DONE 0x4e08 -#define SPR_EVENT_BEGIN 0x4e0d -#define SPR_EVENT_END 0x4e0e -#define SPR_EX_CONTEXT_0_0 0x4a05 -#define SPR_EX_CONTEXT_0_1 0x4a06 -#define SPR_EX_CONTEXT_0_1__PL_SHIFT 0 -#define SPR_EX_CONTEXT_0_1__PL_RMASK 0x3 -#define SPR_EX_CONTEXT_0_1__PL_MASK 0x3 -#define SPR_EX_CONTEXT_0_1__ICS_SHIFT 2 -#define SPR_EX_CONTEXT_0_1__ICS_RMASK 0x1 -#define SPR_EX_CONTEXT_0_1__ICS_MASK 0x4 -#define SPR_EX_CONTEXT_1_0 0x4805 -#define SPR_EX_CONTEXT_1_1 0x4806 -#define SPR_EX_CONTEXT_1_1__PL_SHIFT 0 -#define SPR_EX_CONTEXT_1_1__PL_RMASK 0x3 -#define SPR_EX_CONTEXT_1_1__PL_MASK 0x3 -#define SPR_EX_CONTEXT_1_1__ICS_SHIFT 2 -#define SPR_EX_CONTEXT_1_1__ICS_RMASK 0x1 -#define SPR_EX_CONTEXT_1_1__ICS_MASK 0x4 -#define SPR_EX_CONTEXT_2_0 0x4605 -#define SPR_EX_CONTEXT_2_1 0x4606 -#define SPR_EX_CONTEXT_2_1__PL_SHIFT 0 -#define SPR_EX_CONTEXT_2_1__PL_RMASK 0x3 -#define SPR_EX_CONTEXT_2_1__PL_MASK 0x3 -#define SPR_EX_CONTEXT_2_1__ICS_SHIFT 2 -#define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1 -#define SPR_EX_CONTEXT_2_1__ICS_MASK 0x4 -#define SPR_FAIL 0x4e09 -#define SPR_IDN_AVAIL_EN 0x3e05 -#define SPR_IDN_CA_DATA 0x0b00 -#define SPR_IDN_DATA_AVAIL 0x0b03 -#define SPR_IDN_DEADLOCK_TIMEOUT 0x3406 -#define SPR_IDN_DEMUX_CA_COUNT 0x0a05 -#define SPR_IDN_DEMUX_COUNT_0 0x0a06 -#define SPR_IDN_DEMUX_COUNT_1 0x0a07 -#define SPR_IDN_DEMUX_CTL 0x0a08 -#define SPR_IDN_DEMUX_QUEUE_SEL 0x0a0a -#define SPR_IDN_DEMUX_STATUS 0x0a0b -#define SPR_IDN_DEMUX_WRITE_FIFO 0x0a0c -#define SPR_IDN_DIRECTION_PROTECT 0x2e05 -#define SPR_IDN_PENDING 0x0a0e -#define SPR_IDN_REFILL_EN 0x0e05 -#define SPR_IDN_SP_FIFO_DATA 0x0a0f -#define SPR_IDN_SP_FIFO_SEL 0x0a10 -#define SPR_IDN_SP_FREEZE 0x0a11 -#define SPR_IDN_SP_FREEZE__SP_FRZ_MASK 0x1 -#define SPR_IDN_SP_FREEZE__DEMUX_FRZ_MASK 0x2 -#define SPR_IDN_SP_FREEZE__NON_DEST_EXT_MASK 0x4 -#define SPR_IDN_SP_STATE 0x0a12 -#define SPR_IDN_TAG_0 0x0a13 -#define SPR_IDN_TAG_1 0x0a14 -#define SPR_IDN_TAG_VALID 0x0a15 -#define SPR_IDN_TILE_COORD 0x0a16 -#define SPR_INTCTRL_0_STATUS 0x4a07 -#define SPR_INTCTRL_1_STATUS 0x4807 -#define SPR_INTCTRL_2_STATUS 0x4607 -#define SPR_INTERRUPT_CRITICAL_SECTION 0x4e0a -#define SPR_INTERRUPT_MASK_0_0 0x4a08 -#define SPR_INTERRUPT_MASK_0_1 0x4a09 -#define SPR_INTERRUPT_MASK_1_0 0x4809 -#define SPR_INTERRUPT_MASK_1_1 0x480a -#define SPR_INTERRUPT_MASK_2_0 0x4608 -#define SPR_INTERRUPT_MASK_2_1 0x4609 -#define SPR_INTERRUPT_MASK_RESET_0_0 0x4a0a -#define SPR_INTERRUPT_MASK_RESET_0_1 0x4a0b -#define SPR_INTERRUPT_MASK_RESET_1_0 0x480b -#define SPR_INTERRUPT_MASK_RESET_1_1 0x480c -#define SPR_INTERRUPT_MASK_RESET_2_0 0x460a -#define SPR_INTERRUPT_MASK_RESET_2_1 0x460b -#define SPR_INTERRUPT_MASK_SET_0_0 0x4a0c -#define SPR_INTERRUPT_MASK_SET_0_1 0x4a0d -#define SPR_INTERRUPT_MASK_SET_1_0 0x480d -#define SPR_INTERRUPT_MASK_SET_1_1 0x480e -#define SPR_INTERRUPT_MASK_SET_2_0 0x460c -#define SPR_INTERRUPT_MASK_SET_2_1 0x460d -#define SPR_MPL_AUX_PERF_COUNT_SET_0 0x6000 -#define SPR_MPL_AUX_PERF_COUNT_SET_1 0x6001 -#define SPR_MPL_AUX_PERF_COUNT_SET_2 0x6002 -#define SPR_MPL_DMA_CPL_SET_0 0x5800 -#define SPR_MPL_DMA_CPL_SET_1 0x5801 -#define SPR_MPL_DMA_CPL_SET_2 0x5802 -#define SPR_MPL_DMA_NOTIFY_SET_0 0x3800 -#define SPR_MPL_DMA_NOTIFY_SET_1 0x3801 -#define SPR_MPL_DMA_NOTIFY_SET_2 0x3802 -#define SPR_MPL_IDN_ACCESS_SET_0 0x0a00 -#define SPR_MPL_IDN_ACCESS_SET_1 0x0a01 -#define SPR_MPL_IDN_ACCESS_SET_2 0x0a02 -#define SPR_MPL_IDN_AVAIL_SET_0 0x3e00 -#define SPR_MPL_IDN_AVAIL_SET_1 0x3e01 -#define SPR_MPL_IDN_AVAIL_SET_2 0x3e02 -#define SPR_MPL_IDN_CA_SET_0 0x3a00 -#define SPR_MPL_IDN_CA_SET_1 0x3a01 -#define SPR_MPL_IDN_CA_SET_2 0x3a02 -#define SPR_MPL_IDN_COMPLETE_SET_0 0x1200 -#define SPR_MPL_IDN_COMPLETE_SET_1 0x1201 -#define SPR_MPL_IDN_COMPLETE_SET_2 0x1202 -#define SPR_MPL_IDN_FIREWALL_SET_0 0x2e00 -#define SPR_MPL_IDN_FIREWALL_SET_1 0x2e01 -#define SPR_MPL_IDN_FIREWALL_SET_2 0x2e02 -#define SPR_MPL_IDN_REFILL_SET_0 0x0e00 -#define SPR_MPL_IDN_REFILL_SET_1 0x0e01 -#define SPR_MPL_IDN_REFILL_SET_2 0x0e02 -#define SPR_MPL_IDN_TIMER_SET_0 0x3400 -#define SPR_MPL_IDN_TIMER_SET_1 0x3401 -#define SPR_MPL_IDN_TIMER_SET_2 0x3402 -#define SPR_MPL_INTCTRL_0_SET_0 0x4a00 -#define SPR_MPL_INTCTRL_0_SET_1 0x4a01 -#define SPR_MPL_INTCTRL_0_SET_2 0x4a02 -#define SPR_MPL_INTCTRL_1_SET_0 0x4800 -#define SPR_MPL_INTCTRL_1_SET_1 0x4801 -#define SPR_MPL_INTCTRL_1_SET_2 0x4802 -#define SPR_MPL_INTCTRL_2_SET_0 0x4600 -#define SPR_MPL_INTCTRL_2_SET_1 0x4601 -#define SPR_MPL_INTCTRL_2_SET_2 0x4602 -#define SPR_MPL_PERF_COUNT_SET_0 0x4200 -#define SPR_MPL_PERF_COUNT_SET_1 0x4201 -#define SPR_MPL_PERF_COUNT_SET_2 0x4202 -#define SPR_MPL_SN_ACCESS_SET_0 0x0800 -#define SPR_MPL_SN_ACCESS_SET_1 0x0801 -#define SPR_MPL_SN_ACCESS_SET_2 0x0802 -#define SPR_MPL_SN_CPL_SET_0 0x5a00 -#define SPR_MPL_SN_CPL_SET_1 0x5a01 -#define SPR_MPL_SN_CPL_SET_2 0x5a02 -#define SPR_MPL_SN_FIREWALL_SET_0 0x2c00 -#define SPR_MPL_SN_FIREWALL_SET_1 0x2c01 -#define SPR_MPL_SN_FIREWALL_SET_2 0x2c02 -#define SPR_MPL_SN_NOTIFY_SET_0 0x2a00 -#define SPR_MPL_SN_NOTIFY_SET_1 0x2a01 -#define SPR_MPL_SN_NOTIFY_SET_2 0x2a02 -#define SPR_MPL_UDN_ACCESS_SET_0 0x0c00 -#define SPR_MPL_UDN_ACCESS_SET_1 0x0c01 -#define SPR_MPL_UDN_ACCESS_SET_2 0x0c02 -#define SPR_MPL_UDN_AVAIL_SET_0 0x4000 -#define SPR_MPL_UDN_AVAIL_SET_1 0x4001 -#define SPR_MPL_UDN_AVAIL_SET_2 0x4002 -#define SPR_MPL_UDN_CA_SET_0 0x3c00 -#define SPR_MPL_UDN_CA_SET_1 0x3c01 -#define SPR_MPL_UDN_CA_SET_2 0x3c02 -#define SPR_MPL_UDN_COMPLETE_SET_0 0x1400 -#define SPR_MPL_UDN_COMPLETE_SET_1 0x1401 -#define SPR_MPL_UDN_COMPLETE_SET_2 0x1402 -#define SPR_MPL_UDN_FIREWALL_SET_0 0x3000 -#define SPR_MPL_UDN_FIREWALL_SET_1 0x3001 -#define SPR_MPL_UDN_FIREWALL_SET_2 0x3002 -#define SPR_MPL_UDN_REFILL_SET_0 0x1000 -#define SPR_MPL_UDN_REFILL_SET_1 0x1001 -#define SPR_MPL_UDN_REFILL_SET_2 0x1002 -#define SPR_MPL_UDN_TIMER_SET_0 0x3600 -#define SPR_MPL_UDN_TIMER_SET_1 0x3601 -#define SPR_MPL_UDN_TIMER_SET_2 0x3602 -#define SPR_MPL_WORLD_ACCESS_SET_0 0x4e00 -#define SPR_MPL_WORLD_ACCESS_SET_1 0x4e01 -#define SPR_MPL_WORLD_ACCESS_SET_2 0x4e02 -#define SPR_PASS 0x4e0b -#define SPR_PERF_COUNT_0 0x4205 -#define SPR_PERF_COUNT_1 0x4206 -#define SPR_PERF_COUNT_CTL 0x4207 -#define SPR_PERF_COUNT_DN_CTL 0x4210 -#define SPR_PERF_COUNT_STS 0x4208 -#define SPR_PROC_STATUS 0x4f00 -#define SPR_SIM_CONTROL 0x4e0c -#define SPR_SNCTL 0x0805 -#define SPR_SNCTL__FRZFABRIC_MASK 0x1 -#define SPR_SNSTATIC 0x080c -#define SPR_SYSTEM_SAVE_0_0 0x4b00 -#define SPR_SYSTEM_SAVE_0_1 0x4b01 -#define SPR_SYSTEM_SAVE_0_2 0x4b02 -#define SPR_SYSTEM_SAVE_0_3 0x4b03 -#define SPR_SYSTEM_SAVE_1_0 0x4900 -#define SPR_SYSTEM_SAVE_1_1 0x4901 -#define SPR_SYSTEM_SAVE_1_2 0x4902 -#define SPR_SYSTEM_SAVE_1_3 0x4903 -#define SPR_SYSTEM_SAVE_2_0 0x4700 -#define SPR_SYSTEM_SAVE_2_1 0x4701 -#define SPR_SYSTEM_SAVE_2_2 0x4702 -#define SPR_SYSTEM_SAVE_2_3 0x4703 -#define SPR_TILE_COORD 0x4c17 -#define SPR_TILE_RTF_HWM 0x4e10 -#define SPR_TILE_TIMER_CONTROL 0x3205 -#define SPR_TILE_WRITE_PENDING 0x4e0f -#define SPR_UDN_AVAIL_EN 0x4005 -#define SPR_UDN_CA_DATA 0x0d00 -#define SPR_UDN_DATA_AVAIL 0x0d03 -#define SPR_UDN_DEADLOCK_TIMEOUT 0x3606 -#define SPR_UDN_DEMUX_CA_COUNT 0x0c05 -#define SPR_UDN_DEMUX_COUNT_0 0x0c06 -#define SPR_UDN_DEMUX_COUNT_1 0x0c07 -#define SPR_UDN_DEMUX_COUNT_2 0x0c08 -#define SPR_UDN_DEMUX_COUNT_3 0x0c09 -#define SPR_UDN_DEMUX_CTL 0x0c0a -#define SPR_UDN_DEMUX_QUEUE_SEL 0x0c0c -#define SPR_UDN_DEMUX_STATUS 0x0c0d -#define SPR_UDN_DEMUX_WRITE_FIFO 0x0c0e -#define SPR_UDN_DIRECTION_PROTECT 0x3005 -#define SPR_UDN_PENDING 0x0c10 -#define SPR_UDN_REFILL_EN 0x1005 -#define SPR_UDN_SP_FIFO_DATA 0x0c11 -#define SPR_UDN_SP_FIFO_SEL 0x0c12 -#define SPR_UDN_SP_FREEZE 0x0c13 -#define SPR_UDN_SP_FREEZE__SP_FRZ_MASK 0x1 -#define SPR_UDN_SP_FREEZE__DEMUX_FRZ_MASK 0x2 -#define SPR_UDN_SP_FREEZE__NON_DEST_EXT_MASK 0x4 -#define SPR_UDN_SP_STATE 0x0c14 -#define SPR_UDN_TAG_0 0x0c15 -#define SPR_UDN_TAG_1 0x0c16 -#define SPR_UDN_TAG_2 0x0c17 -#define SPR_UDN_TAG_3 0x0c18 -#define SPR_UDN_TAG_VALID 0x0c19 -#define SPR_UDN_TILE_COORD 0x0c1a -#define SPR_WATCH_CTL 0x4209 -#define SPR_WATCH_MASK 0x420a -#define SPR_WATCH_VAL 0x420b - -#endif /* !defined(__ARCH_SPR_DEF_32_H__) */ - -#endif /* !defined(__DOXYGEN__) */ diff --git a/arch/tile/include/uapi/arch/spr_def_64.h b/arch/tile/include/uapi/arch/spr_def_64.h deleted file mode 100644 index d183cbb31aa7..000000000000 --- a/arch/tile/include/uapi/arch/spr_def_64.h +++ /dev/null @@ -1,217 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef __DOXYGEN__ - -#ifndef __ARCH_SPR_DEF_64_H__ -#define __ARCH_SPR_DEF_64_H__ - -#define SPR_AUX_PERF_COUNT_0 0x2105 -#define SPR_AUX_PERF_COUNT_1 0x2106 -#define SPR_AUX_PERF_COUNT_CTL 0x2107 -#define SPR_AUX_PERF_COUNT_STS 0x2108 -#define SPR_CMPEXCH_VALUE 0x2780 -#define SPR_CYCLE 0x2781 -#define SPR_DONE 0x2705 -#define SPR_DSTREAM_PF 0x2706 -#define SPR_EVENT_BEGIN 0x2782 -#define SPR_EVENT_END 0x2783 -#define SPR_EX_CONTEXT_0_0 0x2580 -#define SPR_EX_CONTEXT_0_1 0x2581 -#define SPR_EX_CONTEXT_0_1__PL_SHIFT 0 -#define SPR_EX_CONTEXT_0_1__PL_RMASK 0x3 -#define SPR_EX_CONTEXT_0_1__PL_MASK 0x3 -#define SPR_EX_CONTEXT_0_1__ICS_SHIFT 2 -#define SPR_EX_CONTEXT_0_1__ICS_RMASK 0x1 -#define SPR_EX_CONTEXT_0_1__ICS_MASK 0x4 -#define SPR_EX_CONTEXT_1_0 0x2480 -#define SPR_EX_CONTEXT_1_1 0x2481 -#define SPR_EX_CONTEXT_1_1__PL_SHIFT 0 -#define SPR_EX_CONTEXT_1_1__PL_RMASK 0x3 -#define SPR_EX_CONTEXT_1_1__PL_MASK 0x3 -#define SPR_EX_CONTEXT_1_1__ICS_SHIFT 2 -#define SPR_EX_CONTEXT_1_1__ICS_RMASK 0x1 -#define SPR_EX_CONTEXT_1_1__ICS_MASK 0x4 -#define SPR_EX_CONTEXT_2_0 0x2380 -#define SPR_EX_CONTEXT_2_1 0x2381 -#define SPR_EX_CONTEXT_2_1__PL_SHIFT 0 -#define SPR_EX_CONTEXT_2_1__PL_RMASK 0x3 -#define SPR_EX_CONTEXT_2_1__PL_MASK 0x3 -#define SPR_EX_CONTEXT_2_1__ICS_SHIFT 2 -#define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1 -#define SPR_EX_CONTEXT_2_1__ICS_MASK 0x4 -#define SPR_FAIL 0x2707 -#define SPR_IDN_AVAIL_EN 0x1a05 -#define SPR_IDN_DATA_AVAIL 0x0a80 -#define SPR_IDN_DEADLOCK_TIMEOUT 0x1806 -#define SPR_IDN_DEMUX_COUNT_0 0x0a05 -#define SPR_IDN_DEMUX_COUNT_1 0x0a06 -#define SPR_IDN_DIRECTION_PROTECT 0x1405 -#define SPR_IDN_PENDING 0x0a08 -#define SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK 0x1 -#define SPR_INTCTRL_0_STATUS 0x2505 -#define SPR_INTCTRL_1_STATUS 0x2405 -#define SPR_INTCTRL_2_STATUS 0x2305 -#define SPR_INTERRUPT_CRITICAL_SECTION 0x2708 -#define SPR_INTERRUPT_MASK_0 0x2506 -#define SPR_INTERRUPT_MASK_1 0x2406 -#define SPR_INTERRUPT_MASK_2 0x2306 -#define SPR_INTERRUPT_MASK_RESET_0 0x2507 -#define SPR_INTERRUPT_MASK_RESET_1 0x2407 -#define SPR_INTERRUPT_MASK_RESET_2 0x2307 -#define SPR_INTERRUPT_MASK_SET_0 0x2508 -#define SPR_INTERRUPT_MASK_SET_1 0x2408 -#define SPR_INTERRUPT_MASK_SET_2 0x2308 -#define SPR_INTERRUPT_VECTOR_BASE_0 0x2509 -#define SPR_INTERRUPT_VECTOR_BASE_1 0x2409 -#define SPR_INTERRUPT_VECTOR_BASE_2 0x2309 -#define SPR_INTERRUPT_VECTOR_BASE_3 0x2209 -#define SPR_IPI_EVENT_0 0x1f05 -#define SPR_IPI_EVENT_1 0x1e05 -#define SPR_IPI_EVENT_2 0x1d05 -#define SPR_IPI_EVENT_RESET_0 0x1f06 -#define SPR_IPI_EVENT_RESET_1 0x1e06 -#define SPR_IPI_EVENT_RESET_2 0x1d06 -#define SPR_IPI_EVENT_SET_0 0x1f07 -#define SPR_IPI_EVENT_SET_1 0x1e07 -#define SPR_IPI_EVENT_SET_2 0x1d07 -#define SPR_IPI_MASK_0 0x1f08 -#define SPR_IPI_MASK_1 0x1e08 -#define SPR_IPI_MASK_2 0x1d08 -#define SPR_IPI_MASK_RESET_0 0x1f09 -#define SPR_IPI_MASK_RESET_1 0x1e09 -#define SPR_IPI_MASK_RESET_2 0x1d09 -#define SPR_IPI_MASK_SET_0 0x1f0a -#define SPR_IPI_MASK_SET_1 0x1e0a -#define SPR_IPI_MASK_SET_2 0x1d0a -#define SPR_MPL_AUX_PERF_COUNT_SET_0 0x2100 -#define SPR_MPL_AUX_PERF_COUNT_SET_1 0x2101 -#define SPR_MPL_AUX_PERF_COUNT_SET_2 0x2102 -#define SPR_MPL_AUX_TILE_TIMER_SET_0 0x1700 -#define SPR_MPL_AUX_TILE_TIMER_SET_1 0x1701 -#define SPR_MPL_AUX_TILE_TIMER_SET_2 0x1702 -#define SPR_MPL_IDN_ACCESS_SET_0 0x0a00 -#define SPR_MPL_IDN_ACCESS_SET_1 0x0a01 -#define SPR_MPL_IDN_ACCESS_SET_2 0x0a02 -#define SPR_MPL_IDN_AVAIL_SET_0 0x1a00 -#define SPR_MPL_IDN_AVAIL_SET_1 0x1a01 -#define SPR_MPL_IDN_AVAIL_SET_2 0x1a02 -#define SPR_MPL_IDN_COMPLETE_SET_0 0x0500 -#define SPR_MPL_IDN_COMPLETE_SET_1 0x0501 -#define SPR_MPL_IDN_COMPLETE_SET_2 0x0502 -#define SPR_MPL_IDN_FIREWALL_SET_0 0x1400 -#define SPR_MPL_IDN_FIREWALL_SET_1 0x1401 -#define SPR_MPL_IDN_FIREWALL_SET_2 0x1402 -#define SPR_MPL_IDN_TIMER_SET_0 0x1800 -#define SPR_MPL_IDN_TIMER_SET_1 0x1801 -#define SPR_MPL_IDN_TIMER_SET_2 0x1802 -#define SPR_MPL_INTCTRL_0_SET_0 0x2500 -#define SPR_MPL_INTCTRL_0_SET_1 0x2501 -#define SPR_MPL_INTCTRL_0_SET_2 0x2502 -#define SPR_MPL_INTCTRL_1_SET_0 0x2400 -#define SPR_MPL_INTCTRL_1_SET_1 0x2401 -#define SPR_MPL_INTCTRL_1_SET_2 0x2402 -#define SPR_MPL_INTCTRL_2_SET_0 0x2300 -#define SPR_MPL_INTCTRL_2_SET_1 0x2301 -#define SPR_MPL_INTCTRL_2_SET_2 0x2302 -#define SPR_MPL_IPI_0 0x1f04 -#define SPR_MPL_IPI_0_SET_0 0x1f00 -#define SPR_MPL_IPI_0_SET_1 0x1f01 -#define SPR_MPL_IPI_0_SET_2 0x1f02 -#define SPR_MPL_IPI_1 0x1e04 -#define SPR_MPL_IPI_1_SET_0 0x1e00 -#define SPR_MPL_IPI_1_SET_1 0x1e01 -#define SPR_MPL_IPI_1_SET_2 0x1e02 -#define SPR_MPL_IPI_2 0x1d04 -#define SPR_MPL_IPI_2_SET_0 0x1d00 -#define SPR_MPL_IPI_2_SET_1 0x1d01 -#define SPR_MPL_IPI_2_SET_2 0x1d02 -#define SPR_MPL_PERF_COUNT_SET_0 0x2000 -#define SPR_MPL_PERF_COUNT_SET_1 0x2001 -#define SPR_MPL_PERF_COUNT_SET_2 0x2002 -#define SPR_MPL_UDN_ACCESS_SET_0 0x0b00 -#define SPR_MPL_UDN_ACCESS_SET_1 0x0b01 -#define SPR_MPL_UDN_ACCESS_SET_2 0x0b02 -#define SPR_MPL_UDN_AVAIL_SET_0 0x1b00 -#define SPR_MPL_UDN_AVAIL_SET_1 0x1b01 -#define SPR_MPL_UDN_AVAIL_SET_2 0x1b02 -#define SPR_MPL_UDN_COMPLETE_SET_0 0x0600 -#define SPR_MPL_UDN_COMPLETE_SET_1 0x0601 -#define SPR_MPL_UDN_COMPLETE_SET_2 0x0602 -#define SPR_MPL_UDN_FIREWALL_SET_0 0x1500 -#define SPR_MPL_UDN_FIREWALL_SET_1 0x1501 -#define SPR_MPL_UDN_FIREWALL_SET_2 0x1502 -#define SPR_MPL_UDN_TIMER_SET_0 0x1900 -#define SPR_MPL_UDN_TIMER_SET_1 0x1901 -#define SPR_MPL_UDN_TIMER_SET_2 0x1902 -#define SPR_MPL_WORLD_ACCESS_SET_0 0x2700 -#define SPR_MPL_WORLD_ACCESS_SET_1 0x2701 -#define SPR_MPL_WORLD_ACCESS_SET_2 0x2702 -#define SPR_PASS 0x2709 -#define SPR_PERF_COUNT_0 0x2005 -#define SPR_PERF_COUNT_1 0x2006 -#define SPR_PERF_COUNT_CTL 0x2007 -#define SPR_PERF_COUNT_DN_CTL 0x2008 -#define SPR_PERF_COUNT_STS 0x2009 -#define SPR_PROC_STATUS 0x2784 -#define SPR_SIM_CONTROL 0x2785 -#define SPR_SINGLE_STEP_CONTROL_0 0x0405 -#define SPR_SINGLE_STEP_CONTROL_0__CANCELED_MASK 0x1 -#define SPR_SINGLE_STEP_CONTROL_0__INHIBIT_MASK 0x2 -#define SPR_SINGLE_STEP_CONTROL_1 0x0305 -#define SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK 0x1 -#define SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK 0x2 -#define SPR_SINGLE_STEP_CONTROL_2 0x0205 -#define SPR_SINGLE_STEP_CONTROL_2__CANCELED_MASK 0x1 -#define SPR_SINGLE_STEP_CONTROL_2__INHIBIT_MASK 0x2 -#define SPR_SINGLE_STEP_EN_0_0 0x250a -#define SPR_SINGLE_STEP_EN_0_1 0x240a -#define SPR_SINGLE_STEP_EN_0_2 0x230a -#define SPR_SINGLE_STEP_EN_1_0 0x250b -#define SPR_SINGLE_STEP_EN_1_1 0x240b -#define SPR_SINGLE_STEP_EN_1_2 0x230b -#define SPR_SINGLE_STEP_EN_2_0 0x250c -#define SPR_SINGLE_STEP_EN_2_1 0x240c -#define SPR_SINGLE_STEP_EN_2_2 0x230c -#define SPR_SYSTEM_SAVE_0_0 0x2582 -#define SPR_SYSTEM_SAVE_0_1 0x2583 -#define SPR_SYSTEM_SAVE_0_2 0x2584 -#define SPR_SYSTEM_SAVE_0_3 0x2585 -#define SPR_SYSTEM_SAVE_1_0 0x2482 -#define SPR_SYSTEM_SAVE_1_1 0x2483 -#define SPR_SYSTEM_SAVE_1_2 0x2484 -#define SPR_SYSTEM_SAVE_1_3 0x2485 -#define SPR_SYSTEM_SAVE_2_0 0x2382 -#define SPR_SYSTEM_SAVE_2_1 0x2383 -#define SPR_SYSTEM_SAVE_2_2 0x2384 -#define SPR_SYSTEM_SAVE_2_3 0x2385 -#define SPR_TILE_COORD 0x270b -#define SPR_TILE_RTF_HWM 0x270c -#define SPR_TILE_TIMER_CONTROL 0x1605 -#define SPR_UDN_AVAIL_EN 0x1b05 -#define SPR_UDN_DATA_AVAIL 0x0b80 -#define SPR_UDN_DEADLOCK_TIMEOUT 0x1906 -#define SPR_UDN_DEMUX_COUNT_0 0x0b05 -#define SPR_UDN_DEMUX_COUNT_1 0x0b06 -#define SPR_UDN_DEMUX_COUNT_2 0x0b07 -#define SPR_UDN_DEMUX_COUNT_3 0x0b08 -#define SPR_UDN_DIRECTION_PROTECT 0x1505 -#define SPR_UDN_PENDING 0x0b0a -#define SPR_WATCH_MASK 0x200a -#define SPR_WATCH_VAL 0x200b - -#endif /* !defined(__ARCH_SPR_DEF_64_H__) */ - -#endif /* !defined(__DOXYGEN__) */ diff --git a/arch/tile/include/uapi/asm/Kbuild b/arch/tile/include/uapi/asm/Kbuild deleted file mode 100644 index cc439612bcd5..000000000000 --- a/arch/tile/include/uapi/asm/Kbuild +++ /dev/null @@ -1,24 +0,0 @@ -# UAPI Header export list -include include/uapi/asm-generic/Kbuild.asm - -generic-y += bpf_perf_event.h -generic-y += errno.h -generic-y += fcntl.h -generic-y += ioctl.h -generic-y += ioctls.h -generic-y += ipcbuf.h -generic-y += msgbuf.h -generic-y += param.h -generic-y += poll.h -generic-y += posix_types.h -generic-y += resource.h -generic-y += sembuf.h -generic-y += shmbuf.h -generic-y += shmparam.h -generic-y += socket.h -generic-y += sockios.h -generic-y += statfs.h -generic-y += termbits.h -generic-y += termios.h -generic-y += types.h -generic-y += ucontext.h diff --git a/arch/tile/include/uapi/asm/auxvec.h b/arch/tile/include/uapi/asm/auxvec.h deleted file mode 100644 index 922383ce8f4f..000000000000 --- a/arch/tile/include/uapi/asm/auxvec.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_AUXVEC_H -#define _ASM_TILE_AUXVEC_H - -/* The vDSO location. */ -#define AT_SYSINFO_EHDR 33 - -#define AT_VECTOR_SIZE_ARCH 1 /* entries in ARCH_DLINFO */ - -#endif /* _ASM_TILE_AUXVEC_H */ diff --git a/arch/tile/include/uapi/asm/bitsperlong.h b/arch/tile/include/uapi/asm/bitsperlong.h deleted file mode 100644 index 57cca78c0fbb..000000000000 --- a/arch/tile/include/uapi/asm/bitsperlong.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_BITSPERLONG_H -#define _ASM_TILE_BITSPERLONG_H - -#ifdef __LP64__ -# define __BITS_PER_LONG 64 -#else -# define __BITS_PER_LONG 32 -#endif - -#include - -#endif /* _ASM_TILE_BITSPERLONG_H */ diff --git a/arch/tile/include/uapi/asm/byteorder.h b/arch/tile/include/uapi/asm/byteorder.h deleted file mode 100644 index d508e61c1e56..000000000000 --- a/arch/tile/include/uapi/asm/byteorder.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#if defined (__BIG_ENDIAN__) -#include -#else -#include -#endif diff --git a/arch/tile/include/uapi/asm/cachectl.h b/arch/tile/include/uapi/asm/cachectl.h deleted file mode 100644 index ed8bac28a1b9..000000000000 --- a/arch/tile/include/uapi/asm/cachectl.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_CACHECTL_H -#define _ASM_TILE_CACHECTL_H - -/* - * Options for cacheflush system call. - * - * The ICACHE flush is performed on all cores currently running the - * current process's address space. The intent is for user - * applications to be able to modify code, invoke the system call, - * then allow arbitrary other threads in the same address space to see - * the newly-modified code. Passing a length of CHIP_L1I_CACHE_SIZE() - * or more invalidates the entire icache on all cores in the address - * spaces. (Note: currently this option invalidates the entire icache - * regardless of the requested address and length, but we may choose - * to honor the arguments at some point.) - * - * Flush and invalidation of memory can normally be performed with the - * __insn_flush() and __insn_finv() instructions from userspace. - * The DCACHE option to the system call allows userspace - * to flush the entire L1+L2 data cache from the core. In this case, - * the address and length arguments are not used. The DCACHE flush is - * restricted to the current core, not all cores in the address space. - */ -#define ICACHE (1<<0) /* invalidate L1 instruction cache */ -#define DCACHE (1<<1) /* flush and invalidate data cache */ -#define BCACHE (ICACHE|DCACHE) /* flush both caches */ - -#endif /* _ASM_TILE_CACHECTL_H */ diff --git a/arch/tile/include/uapi/asm/hardwall.h b/arch/tile/include/uapi/asm/hardwall.h deleted file mode 100644 index f02e9132ae71..000000000000 --- a/arch/tile/include/uapi/asm/hardwall.h +++ /dev/null @@ -1,52 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Provide methods for access control of per-cpu resources like - * UDN, IDN, or IPI. - */ - -#ifndef _UAPI_ASM_TILE_HARDWALL_H -#define _UAPI_ASM_TILE_HARDWALL_H - -#include -#include - -#define HARDWALL_IOCTL_BASE 0xa2 - -/* - * The HARDWALL_CREATE() ioctl is a macro with a "size" argument. - * The resulting ioctl value is passed to the kernel in conjunction - * with a pointer to a standard kernel bitmask of cpus. - * For network resources (UDN or IDN) the bitmask must physically - * represent a rectangular configuration on the chip. - * The "size" is the number of bytes of cpu mask data. - */ -#define _HARDWALL_CREATE 1 -#define HARDWALL_CREATE(size) \ - _IOC(_IOC_READ, HARDWALL_IOCTL_BASE, _HARDWALL_CREATE, (size)) - -#define _HARDWALL_ACTIVATE 2 -#define HARDWALL_ACTIVATE \ - _IO(HARDWALL_IOCTL_BASE, _HARDWALL_ACTIVATE) - -#define _HARDWALL_DEACTIVATE 3 -#define HARDWALL_DEACTIVATE \ - _IO(HARDWALL_IOCTL_BASE, _HARDWALL_DEACTIVATE) - -#define _HARDWALL_GET_ID 4 -#define HARDWALL_GET_ID \ - _IO(HARDWALL_IOCTL_BASE, _HARDWALL_GET_ID) - - -#endif /* _UAPI_ASM_TILE_HARDWALL_H */ diff --git a/arch/tile/include/uapi/asm/kvm_para.h b/arch/tile/include/uapi/asm/kvm_para.h deleted file mode 100644 index baacc4996d18..000000000000 --- a/arch/tile/include/uapi/asm/kvm_para.h +++ /dev/null @@ -1,2 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#include diff --git a/arch/tile/include/uapi/asm/mman.h b/arch/tile/include/uapi/asm/mman.h deleted file mode 100644 index 9b7add95926b..000000000000 --- a/arch/tile/include/uapi/asm/mman.h +++ /dev/null @@ -1,43 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_MMAN_H -#define _ASM_TILE_MMAN_H - -#include -#include - -/* Standard Linux flags */ - -#define MAP_POPULATE 0x0040 /* populate (prefault) pagetables */ -#define MAP_NONBLOCK 0x0080 /* do not block on IO */ -#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ -#define MAP_STACK MAP_GROWSDOWN /* provide convenience alias */ -#define MAP_LOCKED 0x0200 /* pages are locked */ -#define MAP_NORESERVE 0x0400 /* don't check for reservations */ -#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ -#define MAP_HUGETLB 0x4000 /* create a huge page mapping */ - - -/* - * Flags for mlockall - */ -#define MCL_CURRENT 1 /* lock all current mappings */ -#define MCL_FUTURE 2 /* lock all future mappings */ -#define MCL_ONFAULT 4 /* lock all pages that are faulted in */ - - -#endif /* _ASM_TILE_MMAN_H */ diff --git a/arch/tile/include/uapi/asm/ptrace.h b/arch/tile/include/uapi/asm/ptrace.h deleted file mode 100644 index 667ed742f4dd..000000000000 --- a/arch/tile/include/uapi/asm/ptrace.h +++ /dev/null @@ -1,99 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _UAPI_ASM_TILE_PTRACE_H -#define _UAPI_ASM_TILE_PTRACE_H - -#include -#include - -/* These must match struct pt_regs, below. */ -#if CHIP_WORD_SIZE() == 32 -#define PTREGS_OFFSET_REG(n) ((n)*4) -#else -#define PTREGS_OFFSET_REG(n) ((n)*8) -#endif -#define PTREGS_OFFSET_BASE 0 -#define PTREGS_OFFSET_TP PTREGS_OFFSET_REG(53) -#define PTREGS_OFFSET_SP PTREGS_OFFSET_REG(54) -#define PTREGS_OFFSET_LR PTREGS_OFFSET_REG(55) -#define PTREGS_NR_GPRS 56 -#define PTREGS_OFFSET_PC PTREGS_OFFSET_REG(56) -#define PTREGS_OFFSET_EX1 PTREGS_OFFSET_REG(57) -#define PTREGS_OFFSET_FAULTNUM PTREGS_OFFSET_REG(58) -#define PTREGS_OFFSET_ORIG_R0 PTREGS_OFFSET_REG(59) -#define PTREGS_OFFSET_FLAGS PTREGS_OFFSET_REG(60) -#if CHIP_HAS_CMPEXCH() -#define PTREGS_OFFSET_CMPEXCH PTREGS_OFFSET_REG(61) -#endif -#define PTREGS_SIZE PTREGS_OFFSET_REG(64) - - -#ifndef __ASSEMBLY__ - -#ifndef __KERNEL__ -/* Provide appropriate length type to userspace regardless of -m32/-m64. */ -typedef uint_reg_t pt_reg_t; -#endif - -/* - * This struct defines the way the registers are stored on the stack during a - * system call or exception. "struct sigcontext" has the same shape. - */ -struct pt_regs { - union { - /* Saved main processor registers; 56..63 are special. */ - pt_reg_t regs[56]; - struct { - pt_reg_t __regs[53]; - pt_reg_t tp; /* aliases regs[TREG_TP] */ - pt_reg_t sp; /* aliases regs[TREG_SP] */ - pt_reg_t lr; /* aliases regs[TREG_LR] */ - }; - }; - - /* Saved special registers. */ - pt_reg_t pc; /* stored in EX_CONTEXT_K_0 */ - pt_reg_t ex1; /* stored in EX_CONTEXT_K_1 (PL and ICS bit) */ - pt_reg_t faultnum; /* fault number (INT_SWINT_1 for syscall) */ - pt_reg_t orig_r0; /* r0 at syscall entry, else zero */ - pt_reg_t flags; /* flags (see below) */ -#if !CHIP_HAS_CMPEXCH() - pt_reg_t pad[3]; -#else - pt_reg_t cmpexch; /* value of CMPEXCH_VALUE SPR at interrupt */ - pt_reg_t pad[2]; -#endif -}; - -#endif /* __ASSEMBLY__ */ - -#define PTRACE_GETREGS 12 -#define PTRACE_SETREGS 13 -#define PTRACE_GETFPREGS 14 -#define PTRACE_SETFPREGS 15 - -/* Support TILE-specific ptrace options, with events starting at 16. */ -#define PTRACE_EVENT_MIGRATE 16 -#define PTRACE_O_TRACEMIGRATE (1 << PTRACE_EVENT_MIGRATE) - -/* - * Flag bits in pt_regs.flags that are part of the ptrace API. - * We start our numbering higher up to avoid confusion with the - * non-ABI kernel-internal values that use the low 16 bits. - */ -#define PT_FLAGS_COMPAT 0x10000 /* process is an -m32 compat process */ - -#endif /* _UAPI_ASM_TILE_PTRACE_H */ diff --git a/arch/tile/include/uapi/asm/setup.h b/arch/tile/include/uapi/asm/setup.h deleted file mode 100644 index 6d1dfdddad6c..000000000000 --- a/arch/tile/include/uapi/asm/setup.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _UAPI_ASM_TILE_SETUP_H -#define _UAPI_ASM_TILE_SETUP_H - -#define COMMAND_LINE_SIZE 2048 - - -#endif /* _UAPI_ASM_TILE_SETUP_H */ diff --git a/arch/tile/include/uapi/asm/sigcontext.h b/arch/tile/include/uapi/asm/sigcontext.h deleted file mode 100644 index 4003d5cc9202..000000000000 --- a/arch/tile/include/uapi/asm/sigcontext.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_SIGCONTEXT_H -#define _ASM_TILE_SIGCONTEXT_H - -/* Don't pollute the namespace since includes this file. */ -#define __need_int_reg_t -#include - -/* - * struct sigcontext has the same shape as struct pt_regs, - * but is simplified since we know the fault is from userspace. - */ -struct sigcontext { - __extension__ union { - /* General-purpose registers. */ - __uint_reg_t gregs[56]; - __extension__ struct { - __uint_reg_t __gregs[53]; - __uint_reg_t tp; /* Aliases gregs[TREG_TP]. */ - __uint_reg_t sp; /* Aliases gregs[TREG_SP]. */ - __uint_reg_t lr; /* Aliases gregs[TREG_LR]. */ - }; - }; - __uint_reg_t pc; /* Program counter. */ - __uint_reg_t ics; /* In Interrupt Critical Section? */ - __uint_reg_t faultnum; /* Fault number. */ - __uint_reg_t pad[5]; -}; - -#endif /* _ASM_TILE_SIGCONTEXT_H */ diff --git a/arch/tile/include/uapi/asm/siginfo.h b/arch/tile/include/uapi/asm/siginfo.h deleted file mode 100644 index a812fcbf4267..000000000000 --- a/arch/tile/include/uapi/asm/siginfo.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_SIGINFO_H -#define _ASM_TILE_SIGINFO_H - -#define __ARCH_SI_TRAPNO - -#ifdef __LP64__ -# define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) -#endif - -#include - -#endif /* _ASM_TILE_SIGINFO_H */ diff --git a/arch/tile/include/uapi/asm/signal.h b/arch/tile/include/uapi/asm/signal.h deleted file mode 100644 index 7b3c814e00f0..000000000000 --- a/arch/tile/include/uapi/asm/signal.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _UAPI_ASM_TILE_SIGNAL_H -#define _UAPI_ASM_TILE_SIGNAL_H - -/* Do not notify a ptracer when this signal is handled. */ -#define SA_NOPTRACE 0x02000000u - -/* Used in earlier Tilera releases, so keeping for binary compatibility. */ -#define SA_RESTORER 0x04000000u - -#include - - -#endif /* _UAPI_ASM_TILE_SIGNAL_H */ diff --git a/arch/tile/include/uapi/asm/stat.h b/arch/tile/include/uapi/asm/stat.h deleted file mode 100644 index ea03de7d67aa..000000000000 --- a/arch/tile/include/uapi/asm/stat.h +++ /dev/null @@ -1,5 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#if defined(__KERNEL__) && defined(CONFIG_COMPAT) -#define __ARCH_WANT_STAT64 /* Used for compat_sys_stat64() etc. */ -#endif -#include diff --git a/arch/tile/include/uapi/asm/swab.h b/arch/tile/include/uapi/asm/swab.h deleted file mode 100644 index 36952353a31d..000000000000 --- a/arch/tile/include/uapi/asm/swab.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_SWAB_H -#define _ASM_TILE_SWAB_H - -/* Tile gcc is always >= 4.3.0, so we use __builtin_bswap. */ -#define __arch_swab32(x) __builtin_bswap32(x) -#define __arch_swab64(x) __builtin_bswap64(x) -#define __arch_swab16(x) (__builtin_bswap32(x) >> 16) - -#endif /* _ASM_TILE_SWAB_H */ diff --git a/arch/tile/include/uapi/asm/unistd.h b/arch/tile/include/uapi/asm/unistd.h deleted file mode 100644 index 1a169ec92ef8..000000000000 --- a/arch/tile/include/uapi/asm/unistd.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#define __ARCH_WANT_RENAMEAT -#if !defined(__LP64__) || defined(__SYSCALL_COMPAT) -/* Use the flavor of this syscall that matches the 32-bit API better. */ -#define __ARCH_WANT_SYNC_FILE_RANGE2 -#endif - -/* Use the standard ABI for syscalls. */ -#include - -#define NR_syscalls __NR_syscalls - -/* Additional Tilera-specific syscalls. */ -#define __NR_cacheflush (__NR_arch_specific_syscall + 1) -__SYSCALL(__NR_cacheflush, sys_cacheflush) - -#ifndef __tilegx__ -/* "Fast" syscalls provide atomic support for 32-bit chips. */ -#define __NR_FAST_cmpxchg -1 -#define __NR_FAST_atomic_update -2 -#define __NR_FAST_cmpxchg64 -3 -#define __NR_cmpxchg_badaddr (__NR_arch_specific_syscall + 0) -__SYSCALL(__NR_cmpxchg_badaddr, sys_cmpxchg_badaddr) -#endif diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile deleted file mode 100644 index 3e43d78731a8..000000000000 --- a/arch/tile/kernel/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for the Linux/TILE kernel. -# - -extra-y := vmlinux.lds head_$(BITS).o -obj-y := backtrace.o entry.o hvglue.o irq.o messaging.o \ - pci-dma.o proc.o process.o ptrace.o reboot.o \ - setup.o signal.o single_step.o stack.o sys.o \ - sysfs.o time.o traps.o unaligned.o vdso.o \ - intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o - -ifdef CONFIG_FUNCTION_TRACER -CFLAGS_REMOVE_ftrace.o = -pg -CFLAGS_REMOVE_early_printk.o = -pg -endif - -obj-$(CONFIG_HARDWALL) += hardwall.o -obj-$(CONFIG_COMPAT) += compat.o compat_signal.o -obj-$(CONFIG_SMP) += smpboot.o smp.o tlb.o -obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel_$(BITS).o -ifdef CONFIG_TILEGX -obj-$(CONFIG_PCI) += pci_gx.o -else -obj-$(CONFIG_PCI) += pci.o -endif -obj-$(CONFIG_PERF_EVENTS) += perf_event.o -obj-$(CONFIG_USE_PMC) += pmc.o -obj-$(CONFIG_TILE_USB) += usb.o -obj-$(CONFIG_TILE_HVGLUE_TRACE) += hvglue_trace.o -obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o mcount_64.o -obj-$(CONFIG_KPROBES) += kprobes.o -obj-$(CONFIG_KGDB) += kgdb.o -obj-$(CONFIG_JUMP_LABEL) += jump_label.o - -obj-y += vdso/ diff --git a/arch/tile/kernel/asm-offsets.c b/arch/tile/kernel/asm-offsets.c deleted file mode 100644 index 375e7c321eef..000000000000 --- a/arch/tile/kernel/asm-offsets.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Generates definitions from c-type structures used by assembly sources. - */ - -/* Check for compatible compiler early in the build. */ -#ifdef CONFIG_TILEGX -# ifndef __tilegx__ -# error Can only build TILE-Gx configurations with tilegx compiler -# endif -# ifndef __LP64__ -# error Must not specify -m32 when building the TILE-Gx kernel -# endif -#else -# ifdef __tilegx__ -# error Can not build TILEPro configurations with tilegx compiler -# endif -#endif - -#include -#include -#include -#include -#include -#include - -void foo(void) -{ - DEFINE(SINGLESTEP_STATE_BUFFER_OFFSET, - offsetof(struct single_step_state, buffer)); - DEFINE(SINGLESTEP_STATE_FLAGS_OFFSET, - offsetof(struct single_step_state, flags)); - DEFINE(SINGLESTEP_STATE_ORIG_PC_OFFSET, - offsetof(struct single_step_state, orig_pc)); - DEFINE(SINGLESTEP_STATE_NEXT_PC_OFFSET, - offsetof(struct single_step_state, next_pc)); - DEFINE(SINGLESTEP_STATE_BRANCH_NEXT_PC_OFFSET, - offsetof(struct single_step_state, branch_next_pc)); - DEFINE(SINGLESTEP_STATE_UPDATE_VALUE_OFFSET, - offsetof(struct single_step_state, update_value)); - - DEFINE(THREAD_INFO_TASK_OFFSET, - offsetof(struct thread_info, task)); - DEFINE(THREAD_INFO_FLAGS_OFFSET, - offsetof(struct thread_info, flags)); - DEFINE(THREAD_INFO_STATUS_OFFSET, - offsetof(struct thread_info, status)); - DEFINE(THREAD_INFO_HOMECACHE_CPU_OFFSET, - offsetof(struct thread_info, homecache_cpu)); - DEFINE(THREAD_INFO_PREEMPT_COUNT_OFFSET, - offsetof(struct thread_info, preempt_count)); - DEFINE(THREAD_INFO_STEP_STATE_OFFSET, - offsetof(struct thread_info, step_state)); -#ifdef __tilegx__ - DEFINE(THREAD_INFO_UNALIGN_JIT_BASE_OFFSET, - offsetof(struct thread_info, unalign_jit_base)); - DEFINE(THREAD_INFO_UNALIGN_JIT_TMP_OFFSET, - offsetof(struct thread_info, unalign_jit_tmp)); -#endif - - DEFINE(TASK_STRUCT_THREAD_KSP_OFFSET, - offsetof(struct task_struct, thread.ksp)); - DEFINE(TASK_STRUCT_THREAD_PC_OFFSET, - offsetof(struct task_struct, thread.pc)); - - DEFINE(HV_TOPOLOGY_WIDTH_OFFSET, - offsetof(HV_Topology, width)); - DEFINE(HV_TOPOLOGY_HEIGHT_OFFSET, - offsetof(HV_Topology, height)); - - DEFINE(IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET, - offsetof(irq_cpustat_t, irq_syscall_count)); -} diff --git a/arch/tile/kernel/backtrace.c b/arch/tile/kernel/backtrace.c deleted file mode 100644 index f8b74ca83b92..000000000000 --- a/arch/tile/kernel/backtrace.c +++ /dev/null @@ -1,683 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include - -#ifdef __tilegx__ -#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE -#define tile_decoded_instruction tilegx_decoded_instruction -#define tile_mnemonic tilegx_mnemonic -#define parse_insn_tile parse_insn_tilegx -#define TILE_OPC_IRET TILEGX_OPC_IRET -#define TILE_OPC_ADDI TILEGX_OPC_ADDI -#define TILE_OPC_ADDLI TILEGX_OPC_ADDLI -#define TILE_OPC_INFO TILEGX_OPC_INFO -#define TILE_OPC_INFOL TILEGX_OPC_INFOL -#define TILE_OPC_JRP TILEGX_OPC_JRP -#define TILE_OPC_MOVE TILEGX_OPC_MOVE -#define OPCODE_STORE TILEGX_OPC_ST -typedef long long bt_int_reg_t; -#else -#define TILE_MAX_INSTRUCTIONS_PER_BUNDLE TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE -#define tile_decoded_instruction tilepro_decoded_instruction -#define tile_mnemonic tilepro_mnemonic -#define parse_insn_tile parse_insn_tilepro -#define TILE_OPC_IRET TILEPRO_OPC_IRET -#define TILE_OPC_ADDI TILEPRO_OPC_ADDI -#define TILE_OPC_ADDLI TILEPRO_OPC_ADDLI -#define TILE_OPC_INFO TILEPRO_OPC_INFO -#define TILE_OPC_INFOL TILEPRO_OPC_INFOL -#define TILE_OPC_JRP TILEPRO_OPC_JRP -#define TILE_OPC_MOVE TILEPRO_OPC_MOVE -#define OPCODE_STORE TILEPRO_OPC_SW -typedef int bt_int_reg_t; -#endif - -/* A decoded bundle used for backtracer analysis. */ -struct BacktraceBundle { - tile_bundle_bits bits; - int num_insns; - struct tile_decoded_instruction - insns[TILE_MAX_INSTRUCTIONS_PER_BUNDLE]; -}; - - -/* Locates an instruction inside the given bundle that - * has the specified mnemonic, and whose first 'num_operands_to_match' - * operands exactly match those in 'operand_values'. - */ -static const struct tile_decoded_instruction *find_matching_insn( - const struct BacktraceBundle *bundle, - tile_mnemonic mnemonic, - const int *operand_values, - int num_operands_to_match) -{ - int i, j; - bool match; - - for (i = 0; i < bundle->num_insns; i++) { - const struct tile_decoded_instruction *insn = - &bundle->insns[i]; - - if (insn->opcode->mnemonic != mnemonic) - continue; - - match = true; - for (j = 0; j < num_operands_to_match; j++) { - if (operand_values[j] != insn->operand_values[j]) { - match = false; - break; - } - } - - if (match) - return insn; - } - - return NULL; -} - -/* Does this bundle contain an 'iret' instruction? */ -static inline bool bt_has_iret(const struct BacktraceBundle *bundle) -{ - return find_matching_insn(bundle, TILE_OPC_IRET, NULL, 0) != NULL; -} - -/* Does this bundle contain an 'addi sp, sp, OFFSET' or - * 'addli sp, sp, OFFSET' instruction, and if so, what is OFFSET? - */ -static bool bt_has_addi_sp(const struct BacktraceBundle *bundle, int *adjust) -{ - static const int vals[2] = { TREG_SP, TREG_SP }; - - const struct tile_decoded_instruction *insn = - find_matching_insn(bundle, TILE_OPC_ADDI, vals, 2); - if (insn == NULL) - insn = find_matching_insn(bundle, TILE_OPC_ADDLI, vals, 2); -#ifdef __tilegx__ - if (insn == NULL) - insn = find_matching_insn(bundle, TILEGX_OPC_ADDXLI, vals, 2); - if (insn == NULL) - insn = find_matching_insn(bundle, TILEGX_OPC_ADDXI, vals, 2); -#endif - if (insn == NULL) - return false; - - *adjust = insn->operand_values[2]; - return true; -} - -/* Does this bundle contain any 'info OP' or 'infol OP' - * instruction, and if so, what are their OP? Note that OP is interpreted - * as an unsigned value by this code since that's what the caller wants. - * Returns the number of info ops found. - */ -static int bt_get_info_ops(const struct BacktraceBundle *bundle, - int operands[MAX_INFO_OPS_PER_BUNDLE]) -{ - int num_ops = 0; - int i; - - for (i = 0; i < bundle->num_insns; i++) { - const struct tile_decoded_instruction *insn = - &bundle->insns[i]; - - if (insn->opcode->mnemonic == TILE_OPC_INFO || - insn->opcode->mnemonic == TILE_OPC_INFOL) { - operands[num_ops++] = insn->operand_values[0]; - } - } - - return num_ops; -} - -/* Does this bundle contain a jrp instruction, and if so, to which - * register is it jumping? - */ -static bool bt_has_jrp(const struct BacktraceBundle *bundle, int *target_reg) -{ - const struct tile_decoded_instruction *insn = - find_matching_insn(bundle, TILE_OPC_JRP, NULL, 0); - if (insn == NULL) - return false; - - *target_reg = insn->operand_values[0]; - return true; -} - -/* Does this bundle modify the specified register in any way? */ -static bool bt_modifies_reg(const struct BacktraceBundle *bundle, int reg) -{ - int i, j; - for (i = 0; i < bundle->num_insns; i++) { - const struct tile_decoded_instruction *insn = - &bundle->insns[i]; - - if (insn->opcode->implicitly_written_register == reg) - return true; - - for (j = 0; j < insn->opcode->num_operands; j++) - if (insn->operands[j]->is_dest_reg && - insn->operand_values[j] == reg) - return true; - } - - return false; -} - -/* Does this bundle modify sp? */ -static inline bool bt_modifies_sp(const struct BacktraceBundle *bundle) -{ - return bt_modifies_reg(bundle, TREG_SP); -} - -/* Does this bundle modify lr? */ -static inline bool bt_modifies_lr(const struct BacktraceBundle *bundle) -{ - return bt_modifies_reg(bundle, TREG_LR); -} - -/* Does this bundle contain the instruction 'move fp, sp'? */ -static inline bool bt_has_move_r52_sp(const struct BacktraceBundle *bundle) -{ - static const int vals[2] = { 52, TREG_SP }; - return find_matching_insn(bundle, TILE_OPC_MOVE, vals, 2) != NULL; -} - -/* Does this bundle contain a store of lr to sp? */ -static inline bool bt_has_sw_sp_lr(const struct BacktraceBundle *bundle) -{ - static const int vals[2] = { TREG_SP, TREG_LR }; - return find_matching_insn(bundle, OPCODE_STORE, vals, 2) != NULL; -} - -#ifdef __tilegx__ -/* Track moveli values placed into registers. */ -static inline void bt_update_moveli(const struct BacktraceBundle *bundle, - int moveli_args[]) -{ - int i; - for (i = 0; i < bundle->num_insns; i++) { - const struct tile_decoded_instruction *insn = - &bundle->insns[i]; - - if (insn->opcode->mnemonic == TILEGX_OPC_MOVELI) { - int reg = insn->operand_values[0]; - moveli_args[reg] = insn->operand_values[1]; - } - } -} - -/* Does this bundle contain an 'add sp, sp, reg' instruction - * from a register that we saw a moveli into, and if so, what - * is the value in the register? - */ -static bool bt_has_add_sp(const struct BacktraceBundle *bundle, int *adjust, - int moveli_args[]) -{ - static const int vals[2] = { TREG_SP, TREG_SP }; - - const struct tile_decoded_instruction *insn = - find_matching_insn(bundle, TILEGX_OPC_ADDX, vals, 2); - if (insn) { - int reg = insn->operand_values[2]; - if (moveli_args[reg]) { - *adjust = moveli_args[reg]; - return true; - } - } - return false; -} -#endif - -/* Locates the caller's PC and SP for a program starting at the - * given address. - */ -static void find_caller_pc_and_caller_sp(CallerLocation *location, - const unsigned long start_pc, - BacktraceMemoryReader read_memory_func, - void *read_memory_func_extra) -{ - /* Have we explicitly decided what the sp is, - * rather than just the default? - */ - bool sp_determined = false; - - /* Has any bundle seen so far modified lr? */ - bool lr_modified = false; - - /* Have we seen a move from sp to fp? */ - bool sp_moved_to_r52 = false; - - /* Have we seen a terminating bundle? */ - bool seen_terminating_bundle = false; - - /* Cut down on round-trip reading overhead by reading several - * bundles at a time. - */ - tile_bundle_bits prefetched_bundles[32]; - int num_bundles_prefetched = 0; - int next_bundle = 0; - unsigned long pc; - -#ifdef __tilegx__ - /* Naively try to track moveli values to support addx for -m32. */ - int moveli_args[TILEGX_NUM_REGISTERS] = { 0 }; -#endif - - /* Default to assuming that the caller's sp is the current sp. - * This is necessary to handle the case where we start backtracing - * right at the end of the epilog. - */ - location->sp_location = SP_LOC_OFFSET; - location->sp_offset = 0; - - /* Default to having no idea where the caller PC is. */ - location->pc_location = PC_LOC_UNKNOWN; - - /* Don't even try if the PC is not aligned. */ - if (start_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0) - return; - - for (pc = start_pc;; pc += sizeof(tile_bundle_bits)) { - - struct BacktraceBundle bundle; - int num_info_ops, info_operands[MAX_INFO_OPS_PER_BUNDLE]; - int one_ago, jrp_reg; - bool has_jrp; - - if (next_bundle >= num_bundles_prefetched) { - /* Prefetch some bytes, but don't cross a page - * boundary since that might cause a read failure we - * don't care about if we only need the first few - * bytes. Note: we don't care what the actual page - * size is; using the minimum possible page size will - * prevent any problems. - */ - unsigned int bytes_to_prefetch = 4096 - (pc & 4095); - if (bytes_to_prefetch > sizeof prefetched_bundles) - bytes_to_prefetch = sizeof prefetched_bundles; - - if (!read_memory_func(prefetched_bundles, pc, - bytes_to_prefetch, - read_memory_func_extra)) { - if (pc == start_pc) { - /* The program probably called a bad - * address, such as a NULL pointer. - * So treat this as if we are at the - * start of the function prolog so the - * backtrace will show how we got here. - */ - location->pc_location = PC_LOC_IN_LR; - return; - } - - /* Unreadable address. Give up. */ - break; - } - - next_bundle = 0; - num_bundles_prefetched = - bytes_to_prefetch / sizeof(tile_bundle_bits); - } - - /* - * Decode the next bundle. - * TILE always stores instruction bundles in little-endian - * mode, even when the chip is running in big-endian mode. - */ - bundle.bits = le64_to_cpu(prefetched_bundles[next_bundle++]); - bundle.num_insns = - parse_insn_tile(bundle.bits, pc, bundle.insns); - num_info_ops = bt_get_info_ops(&bundle, info_operands); - - /* First look at any one_ago info ops if they are interesting, - * since they should shadow any non-one-ago info ops. - */ - for (one_ago = (pc != start_pc) ? 1 : 0; - one_ago >= 0; one_ago--) { - int i; - for (i = 0; i < num_info_ops; i++) { - int info_operand = info_operands[i]; - if (info_operand < CALLER_UNKNOWN_BASE) { - /* Weird; reserved value, ignore it. */ - continue; - } - - /* Skip info ops which are not in the - * "one_ago" mode we want right now. - */ - if (((info_operand & ONE_BUNDLE_AGO_FLAG) != 0) - != (one_ago != 0)) - continue; - - /* Clear the flag to make later checking - * easier. */ - info_operand &= ~ONE_BUNDLE_AGO_FLAG; - - /* Default to looking at PC_IN_LR_FLAG. */ - if (info_operand & PC_IN_LR_FLAG) - location->pc_location = - PC_LOC_IN_LR; - else - location->pc_location = - PC_LOC_ON_STACK; - - switch (info_operand) { - case CALLER_UNKNOWN_BASE: - location->pc_location = PC_LOC_UNKNOWN; - location->sp_location = SP_LOC_UNKNOWN; - return; - - case CALLER_SP_IN_R52_BASE: - case CALLER_SP_IN_R52_BASE | PC_IN_LR_FLAG: - location->sp_location = SP_LOC_IN_R52; - return; - - default: - { - const unsigned int val = info_operand - - CALLER_SP_OFFSET_BASE; - const unsigned int sp_offset = - (val >> NUM_INFO_OP_FLAGS) * 8; - if (sp_offset < 32768) { - /* This is a properly encoded - * SP offset. */ - location->sp_location = - SP_LOC_OFFSET; - location->sp_offset = - sp_offset; - return; - } else { - /* This looked like an SP - * offset, but it's outside - * the legal range, so this - * must be an unrecognized - * info operand. Ignore it. - */ - } - } - break; - } - } - } - - if (seen_terminating_bundle) { - /* We saw a terminating bundle during the previous - * iteration, so we were only looking for an info op. - */ - break; - } - - if (bundle.bits == 0) { - /* Wacky terminating bundle. Stop looping, and hope - * we've already seen enough to find the caller. - */ - break; - } - - /* - * Try to determine caller's SP. - */ - - if (!sp_determined) { - int adjust; - if (bt_has_addi_sp(&bundle, &adjust) -#ifdef __tilegx__ - || bt_has_add_sp(&bundle, &adjust, moveli_args) -#endif - ) { - location->sp_location = SP_LOC_OFFSET; - - if (adjust <= 0) { - /* We are in prolog about to adjust - * SP. */ - location->sp_offset = 0; - } else { - /* We are in epilog restoring SP. */ - location->sp_offset = adjust; - } - - sp_determined = true; - } else { - if (bt_has_move_r52_sp(&bundle)) { - /* Maybe in prolog, creating an - * alloca-style frame. But maybe in - * the middle of a fixed-size frame - * clobbering r52 with SP. - */ - sp_moved_to_r52 = true; - } - - if (bt_modifies_sp(&bundle)) { - if (sp_moved_to_r52) { - /* We saw SP get saved into - * r52 earlier (or now), which - * must have been in the - * prolog, so we now know that - * SP is still holding the - * caller's sp value. - */ - location->sp_location = - SP_LOC_OFFSET; - location->sp_offset = 0; - } else { - /* Someone must have saved - * aside the caller's SP value - * into r52, so r52 holds the - * current value. - */ - location->sp_location = - SP_LOC_IN_R52; - } - sp_determined = true; - } - } - -#ifdef __tilegx__ - /* Track moveli arguments for -m32 mode. */ - bt_update_moveli(&bundle, moveli_args); -#endif - } - - if (bt_has_iret(&bundle)) { - /* This is a terminating bundle. */ - seen_terminating_bundle = true; - continue; - } - - /* - * Try to determine caller's PC. - */ - - jrp_reg = -1; - has_jrp = bt_has_jrp(&bundle, &jrp_reg); - if (has_jrp) - seen_terminating_bundle = true; - - if (location->pc_location == PC_LOC_UNKNOWN) { - if (has_jrp) { - if (jrp_reg == TREG_LR && !lr_modified) { - /* Looks like a leaf function, or else - * lr is already restored. */ - location->pc_location = - PC_LOC_IN_LR; - } else { - location->pc_location = - PC_LOC_ON_STACK; - } - } else if (bt_has_sw_sp_lr(&bundle)) { - /* In prolog, spilling initial lr to stack. */ - location->pc_location = PC_LOC_IN_LR; - } else if (bt_modifies_lr(&bundle)) { - lr_modified = true; - } - } - } -} - -/* Initializes a backtracer to start from the given location. - * - * If the frame pointer cannot be determined it is set to -1. - * - * state: The state to be filled in. - * read_memory_func: A callback that reads memory. - * read_memory_func_extra: An arbitrary argument to read_memory_func. - * pc: The current PC. - * lr: The current value of the 'lr' register. - * sp: The current value of the 'sp' register. - * r52: The current value of the 'r52' register. - */ -void backtrace_init(BacktraceIterator *state, - BacktraceMemoryReader read_memory_func, - void *read_memory_func_extra, - unsigned long pc, unsigned long lr, - unsigned long sp, unsigned long r52) -{ - CallerLocation location; - unsigned long fp, initial_frame_caller_pc; - - /* Find out where we are in the initial frame. */ - find_caller_pc_and_caller_sp(&location, pc, - read_memory_func, read_memory_func_extra); - - switch (location.sp_location) { - case SP_LOC_UNKNOWN: - /* Give up. */ - fp = -1; - break; - - case SP_LOC_IN_R52: - fp = r52; - break; - - case SP_LOC_OFFSET: - fp = sp + location.sp_offset; - break; - - default: - /* Give up. */ - fp = -1; - break; - } - - /* If the frame pointer is not aligned to the basic word size - * something terrible happened and we should mark it as invalid. - */ - if (fp % sizeof(bt_int_reg_t) != 0) - fp = -1; - - /* -1 means "don't know initial_frame_caller_pc". */ - initial_frame_caller_pc = -1; - - switch (location.pc_location) { - case PC_LOC_UNKNOWN: - /* Give up. */ - fp = -1; - break; - - case PC_LOC_IN_LR: - if (lr == 0 || lr % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0) { - /* Give up. */ - fp = -1; - } else { - initial_frame_caller_pc = lr; - } - break; - - case PC_LOC_ON_STACK: - /* Leave initial_frame_caller_pc as -1, - * meaning check the stack. - */ - break; - - default: - /* Give up. */ - fp = -1; - break; - } - - state->pc = pc; - state->sp = sp; - state->fp = fp; - state->initial_frame_caller_pc = initial_frame_caller_pc; - state->read_memory_func = read_memory_func; - state->read_memory_func_extra = read_memory_func_extra; -} - -/* Handle the case where the register holds more bits than the VA. */ -static bool valid_addr_reg(bt_int_reg_t reg) -{ - return ((unsigned long)reg == reg); -} - -/* Advances the backtracing state to the calling frame, returning - * true iff successful. - */ -bool backtrace_next(BacktraceIterator *state) -{ - unsigned long next_fp, next_pc; - bt_int_reg_t next_frame[2]; - - if (state->fp == -1) { - /* No parent frame. */ - return false; - } - - /* Try to read the frame linkage data chaining to the next function. */ - if (!state->read_memory_func(&next_frame, state->fp, sizeof next_frame, - state->read_memory_func_extra)) { - return false; - } - - next_fp = next_frame[1]; - if (!valid_addr_reg(next_frame[1]) || - next_fp % sizeof(bt_int_reg_t) != 0) { - /* Caller's frame pointer is suspect, so give up. */ - return false; - } - - if (state->initial_frame_caller_pc != -1) { - /* We must be in the initial stack frame and already know the - * caller PC. - */ - next_pc = state->initial_frame_caller_pc; - - /* Force reading stack next time, in case we were in the - * initial frame. We don't do this above just to paranoidly - * avoid changing the struct at all when we return false. - */ - state->initial_frame_caller_pc = -1; - } else { - /* Get the caller PC from the frame linkage area. */ - next_pc = next_frame[0]; - if (!valid_addr_reg(next_frame[0]) || next_pc == 0 || - next_pc % TILE_BUNDLE_ALIGNMENT_IN_BYTES != 0) { - /* The PC is suspect, so give up. */ - return false; - } - } - - /* Update state to become the caller's stack frame. */ - state->pc = next_pc; - state->sp = state->fp; - state->fp = next_fp; - - return true; -} diff --git a/arch/tile/kernel/compat.c b/arch/tile/kernel/compat.c deleted file mode 100644 index bdaf71d31a4a..000000000000 --- a/arch/tile/kernel/compat.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* Adjust unistd.h to provide 32-bit numbers and functions. */ -#define __SYSCALL_COMPAT - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Syscalls that take 64-bit numbers traditionally take them in 32-bit - * "high" and "low" value parts on 32-bit architectures. - * In principle, one could imagine passing some register arguments as - * fully 64-bit on TILE-Gx in 32-bit mode, but it seems easier to - * adopt the usual convention. - */ - -#ifdef __BIG_ENDIAN -#define SYSCALL_PAIR(name) u32, name ## _hi, u32, name ## _lo -#else -#define SYSCALL_PAIR(name) u32, name ## _lo, u32, name ## _hi -#endif - -COMPAT_SYSCALL_DEFINE4(truncate64, char __user *, filename, u32, dummy, - SYSCALL_PAIR(length)) -{ - return sys_truncate(filename, ((loff_t)length_hi << 32) | length_lo); -} - -COMPAT_SYSCALL_DEFINE4(ftruncate64, unsigned int, fd, u32, dummy, - SYSCALL_PAIR(length)) -{ - return sys_ftruncate(fd, ((loff_t)length_hi << 32) | length_lo); -} - -COMPAT_SYSCALL_DEFINE6(pread64, unsigned int, fd, char __user *, ubuf, - size_t, count, u32, dummy, SYSCALL_PAIR(offset)) -{ - return sys_pread64(fd, ubuf, count, - ((loff_t)offset_hi << 32) | offset_lo); -} - -COMPAT_SYSCALL_DEFINE6(pwrite64, unsigned int, fd, char __user *, ubuf, - size_t, count, u32, dummy, SYSCALL_PAIR(offset)) -{ - return sys_pwrite64(fd, ubuf, count, - ((loff_t)offset_hi << 32) | offset_lo); -} - -COMPAT_SYSCALL_DEFINE6(sync_file_range2, int, fd, unsigned int, flags, - SYSCALL_PAIR(offset), SYSCALL_PAIR(nbytes)) -{ - return sys_sync_file_range(fd, ((loff_t)offset_hi << 32) | offset_lo, - ((loff_t)nbytes_hi << 32) | nbytes_lo, - flags); -} - -COMPAT_SYSCALL_DEFINE6(fallocate, int, fd, int, mode, - SYSCALL_PAIR(offset), SYSCALL_PAIR(len)) -{ - return sys_fallocate(fd, mode, ((loff_t)offset_hi << 32) | offset_lo, - ((loff_t)len_hi << 32) | len_lo); -} - -/* - * Avoid bug in generic sys_llseek() that specifies offset_high and - * offset_low as "unsigned long", thus making it possible to pass - * a sign-extended high 32 bits in offset_low. - * Note that we do not use SYSCALL_PAIR here since glibc passes the - * high and low parts explicitly in that order. - */ -COMPAT_SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned int, offset_high, - unsigned int, offset_low, loff_t __user *, result, - unsigned int, origin) -{ - return sys_llseek(fd, offset_high, offset_low, result, origin); -} - -/* Provide the compat syscall number to call mapping. */ -#undef __SYSCALL -#define __SYSCALL(nr, call) [nr] = (call), - -/* See comments in sys.c */ -#define compat_sys_fadvise64_64 sys32_fadvise64_64 -#define compat_sys_readahead sys32_readahead -#define sys_llseek compat_sys_llseek - -/* Call the assembly trampolines where necessary. */ -#define compat_sys_rt_sigreturn _compat_sys_rt_sigreturn -#define sys_clone _sys_clone - -/* - * Note that we can't include here since the header - * guard will defeat us; checks for __SYSCALL as well. - */ -void *compat_sys_call_table[__NR_syscalls] = { - [0 ... __NR_syscalls-1] = sys_ni_syscall, -#include -}; diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c deleted file mode 100644 index a703bd0e0488..000000000000 --- a/arch/tile/kernel/compat_signal.c +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct compat_ucontext { - compat_ulong_t uc_flags; - compat_uptr_t uc_link; - struct compat_sigaltstack uc_stack; - struct sigcontext uc_mcontext; - sigset_t uc_sigmask; /* mask last for extensibility */ -}; - -struct compat_rt_sigframe { - unsigned char save_area[C_ABI_SAVE_AREA_SIZE]; /* caller save area */ - struct compat_siginfo info; - struct compat_ucontext uc; -}; - -/* The assembly shim for this function arranges to ignore the return value. */ -long compat_sys_rt_sigreturn(void) -{ - struct pt_regs *regs = current_pt_regs(); - struct compat_rt_sigframe __user *frame = - (struct compat_rt_sigframe __user *) compat_ptr(regs->sp); - sigset_t set; - - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - set_current_blocked(&set); - - if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) - goto badframe; - - if (compat_restore_altstack(&frame->uc.uc_stack)) - goto badframe; - - return 0; - -badframe: - signal_fault("bad sigreturn frame", regs, frame, 0); - return 0; -} - -/* - * Determine which stack to use.. - */ -static inline void __user *compat_get_sigframe(struct k_sigaction *ka, - struct pt_regs *regs, - size_t frame_size) -{ - unsigned long sp; - - /* Default to using normal stack */ - sp = (unsigned long)compat_ptr(regs->sp); - - /* - * If we are on the alternate signal stack and would overflow - * it, don't. Return an always-bogus address instead so we - * will die with SIGSEGV. - */ - if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) - return (void __user __force *)-1UL; - - /* This is the X/Open sanctioned signal stack switching. */ - if (ka->sa.sa_flags & SA_ONSTACK) { - if (sas_ss_flags(sp) == 0) - sp = current->sas_ss_sp + current->sas_ss_size; - } - - sp -= frame_size; - /* - * Align the stack pointer according to the TILE ABI, - * i.e. so that on function entry (sp & 15) == 0. - */ - sp &= -16UL; - return (void __user *) sp; -} - -int compat_setup_rt_frame(struct ksignal *ksig, sigset_t *set, - struct pt_regs *regs) -{ - unsigned long restorer; - struct compat_rt_sigframe __user *frame; - int err = 0, sig = ksig->sig; - - frame = compat_get_sigframe(&ksig->ka, regs, sizeof(*frame)); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto err; - - /* Always write at least the signal number for the stack backtracer. */ - if (ksig->ka.sa.sa_flags & SA_SIGINFO) { - /* At sigreturn time, restore the callee-save registers too. */ - err |= copy_siginfo_to_user32(&frame->info, &ksig->info); - regs->flags |= PT_FLAGS_RESTORE_REGS; - } else { - err |= __put_user(ksig->info.si_signo, &frame->info.si_signo); - } - - /* Create the ucontext. */ - err |= __clear_user(&frame->save_area, sizeof(frame->save_area)); - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(0, &frame->uc.uc_link); - err |= __compat_save_altstack(&frame->uc.uc_stack, regs->sp); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - if (err) - goto err; - - restorer = VDSO_SYM(&__vdso_rt_sigreturn); - if (ksig->ka.sa.sa_flags & SA_RESTORER) - restorer = ptr_to_compat_reg(ksig->ka.sa.sa_restorer); - - /* - * Set up registers for signal handler. - * Registers that we don't modify keep the value they had from - * user-space at the time we took the signal. - * We always pass siginfo and mcontext, regardless of SA_SIGINFO, - * since some things rely on this (e.g. glibc's debug/segfault.c). - */ - regs->pc = ptr_to_compat_reg(ksig->ka.sa.sa_handler); - regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */ - regs->sp = ptr_to_compat_reg(frame); - regs->lr = restorer; - regs->regs[0] = (unsigned long) sig; - regs->regs[1] = ptr_to_compat_reg(&frame->info); - regs->regs[2] = ptr_to_compat_reg(&frame->uc); - regs->flags |= PT_FLAGS_CALLER_SAVES; - return 0; - -err: - trace_unhandled_signal("bad sigreturn frame", regs, - (unsigned long)frame, SIGSEGV); - return -EFAULT; -} diff --git a/arch/tile/kernel/early_printk.c b/arch/tile/kernel/early_printk.c deleted file mode 100644 index aefb2c086726..000000000000 --- a/arch/tile/kernel/early_printk.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static void early_hv_write(struct console *con, const char *s, unsigned n) -{ - tile_console_write(s, n); - - /* - * Convert NL to NLCR (close enough to CRNL) during early boot. - * We assume newlines are at the ends of strings, which turns out - * to be good enough for early boot console output. - */ - if (n && s[n-1] == '\n') - tile_console_write("\r", 1); -} - -static struct console early_hv_console = { - .name = "earlyhv", - .write = early_hv_write, - .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1, -}; - -void early_panic(const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - arch_local_irq_disable_all(); - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - early_printk("Kernel panic - not syncing: %pV", &vaf); - - va_end(args); - - dump_stack(); - hv_halt(); -} - -static int __init setup_early_printk(char *str) -{ - if (early_console) - return 1; - - early_console = &early_hv_console; - register_console(early_console); - - return 0; -} - -early_param("earlyprintk", setup_early_printk); diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S deleted file mode 100644 index 101de132e363..000000000000 --- a/arch/tile/kernel/entry.S +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include - -#ifdef __tilegx__ -#define bnzt bnezt -#endif - -STD_ENTRY(current_text_addr) - { move r0, lr; jrp lr } - STD_ENDPROC(current_text_addr) - -STD_ENTRY(KBacktraceIterator_init_current) - { move r2, lr; lnk r1 } - { move r4, r52; addli r1, r1, KBacktraceIterator_init_current - . } - { move r3, sp; j _KBacktraceIterator_init_current } - jrp lr /* keep backtracer happy */ - STD_ENDPROC(KBacktraceIterator_init_current) - -/* Loop forever on a nap during SMP boot. */ -STD_ENTRY(smp_nap) - nap - nop /* avoid provoking the icache prefetch with a jump */ - j smp_nap /* we are not architecturally guaranteed not to exit nap */ - jrp lr /* clue in the backtracer */ - STD_ENDPROC(smp_nap) - -/* - * Enable interrupts racelessly and then nap until interrupted. - * Architecturally, we are guaranteed that enabling interrupts via - * mtspr to INTERRUPT_CRITICAL_SECTION only interrupts at the next PC. - * This function's _cpu_idle_nap address is special; see intvec.S. - * When interrupted at _cpu_idle_nap, we bump the PC forward 8, and - * as a result return to the function that called _cpu_idle(). - */ -STD_ENTRY_SECTION(_cpu_idle, .cpuidle.text) - movei r1, 1 - IRQ_ENABLE_LOAD(r2, r3) - mtspr INTERRUPT_CRITICAL_SECTION, r1 - IRQ_ENABLE_APPLY(r2, r3) /* unmask, but still with ICS set */ - mtspr INTERRUPT_CRITICAL_SECTION, zero - .global _cpu_idle_nap -_cpu_idle_nap: - nap - nop /* avoid provoking the icache prefetch with a jump */ - jrp lr - STD_ENDPROC(_cpu_idle) diff --git a/arch/tile/kernel/ftrace.c b/arch/tile/kernel/ftrace.c deleted file mode 100644 index b827a418b155..000000000000 --- a/arch/tile/kernel/ftrace.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * TILE-Gx specific ftrace support - */ - -#include -#include - -#include -#include -#include -#include - -#include - -#ifdef CONFIG_DYNAMIC_FTRACE - -static int machine_stopped __read_mostly; - -int ftrace_arch_code_modify_prepare(void) -{ - machine_stopped = 1; - return 0; -} - -int ftrace_arch_code_modify_post_process(void) -{ - flush_icache_range(0, CHIP_L1I_CACHE_SIZE()); - machine_stopped = 0; - return 0; -} - -/* - * Put { move r10, lr; jal ftrace_caller } in a bundle, this lets dynamic - * tracer just add one cycle overhead to every kernel function when disabled. - */ -static unsigned long ftrace_gen_branch(unsigned long pc, unsigned long addr, - bool link) -{ - tilegx_bundle_bits opcode_x0, opcode_x1; - long pcrel_by_instr = (addr - pc) >> TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES; - - if (link) { - /* opcode: jal addr */ - opcode_x1 = - create_Opcode_X1(JUMP_OPCODE_X1) | - create_JumpOpcodeExtension_X1(JAL_JUMP_OPCODE_X1) | - create_JumpOff_X1(pcrel_by_instr); - } else { - /* opcode: j addr */ - opcode_x1 = - create_Opcode_X1(JUMP_OPCODE_X1) | - create_JumpOpcodeExtension_X1(J_JUMP_OPCODE_X1) | - create_JumpOff_X1(pcrel_by_instr); - } - - /* - * Also put { move r10, lr; jal ftrace_stub } in a bundle, which - * is used to replace the instruction in address ftrace_call. - */ - if (addr == FTRACE_ADDR || addr == (unsigned long)ftrace_stub) { - /* opcode: or r10, lr, zero */ - opcode_x0 = - create_Dest_X0(10) | - create_SrcA_X0(TREG_LR) | - create_SrcB_X0(TREG_ZERO) | - create_RRROpcodeExtension_X0(OR_RRR_0_OPCODE_X0) | - create_Opcode_X0(RRR_0_OPCODE_X0); - } else { - /* opcode: fnop */ - opcode_x0 = - create_UnaryOpcodeExtension_X0(FNOP_UNARY_OPCODE_X0) | - create_RRROpcodeExtension_X0(UNARY_RRR_0_OPCODE_X0) | - create_Opcode_X0(RRR_0_OPCODE_X0); - } - - return opcode_x1 | opcode_x0; -} - -static unsigned long ftrace_nop_replace(struct dyn_ftrace *rec) -{ - return NOP(); -} - -static unsigned long ftrace_call_replace(unsigned long pc, unsigned long addr) -{ - return ftrace_gen_branch(pc, addr, true); -} - -static int ftrace_modify_code(unsigned long pc, unsigned long old, - unsigned long new) -{ - unsigned long pc_wr; - - /* Check if the address is in kernel text space and module space. */ - if (!kernel_text_address(pc)) - return -EINVAL; - - /* Operate on writable kernel text mapping. */ - pc_wr = ktext_writable_addr(pc); - - if (probe_kernel_write((void *)pc_wr, &new, MCOUNT_INSN_SIZE)) - return -EPERM; - - smp_wmb(); - - if (!machine_stopped && num_online_cpus() > 1) - flush_icache_range(pc, pc + MCOUNT_INSN_SIZE); - - return 0; -} - -int ftrace_update_ftrace_func(ftrace_func_t func) -{ - unsigned long pc, old; - unsigned long new; - int ret; - - pc = (unsigned long)&ftrace_call; - memcpy(&old, &ftrace_call, MCOUNT_INSN_SIZE); - new = ftrace_call_replace(pc, (unsigned long)func); - - ret = ftrace_modify_code(pc, old, new); - - return ret; -} - -int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) -{ - unsigned long new, old; - unsigned long ip = rec->ip; - - old = ftrace_nop_replace(rec); - new = ftrace_call_replace(ip, addr); - - return ftrace_modify_code(rec->ip, old, new); -} - -int ftrace_make_nop(struct module *mod, - struct dyn_ftrace *rec, unsigned long addr) -{ - unsigned long ip = rec->ip; - unsigned long old; - unsigned long new; - int ret; - - old = ftrace_call_replace(ip, addr); - new = ftrace_nop_replace(rec); - ret = ftrace_modify_code(ip, old, new); - - return ret; -} - -int __init ftrace_dyn_arch_init(void) -{ - return 0; -} -#endif /* CONFIG_DYNAMIC_FTRACE */ - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER -void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, - unsigned long frame_pointer) -{ - unsigned long return_hooker = (unsigned long) &return_to_handler; - struct ftrace_graph_ent trace; - unsigned long old; - int err; - - if (unlikely(atomic_read(¤t->tracing_graph_pause))) - return; - - old = *parent; - *parent = return_hooker; - - err = ftrace_push_return_trace(old, self_addr, &trace.depth, - frame_pointer, NULL); - if (err == -EBUSY) { - *parent = old; - return; - } - - trace.func = self_addr; - - /* Only trace if the calling function expects to */ - if (!ftrace_graph_entry(&trace)) { - current->curr_ret_stack--; - *parent = old; - } -} - -#ifdef CONFIG_DYNAMIC_FTRACE -extern unsigned long ftrace_graph_call; - -static int __ftrace_modify_caller(unsigned long *callsite, - void (*func) (void), bool enable) -{ - unsigned long caller_fn = (unsigned long) func; - unsigned long pc = (unsigned long) callsite; - unsigned long branch = ftrace_gen_branch(pc, caller_fn, false); - unsigned long nop = NOP(); - unsigned long old = enable ? nop : branch; - unsigned long new = enable ? branch : nop; - - return ftrace_modify_code(pc, old, new); -} - -static int ftrace_modify_graph_caller(bool enable) -{ - int ret; - - ret = __ftrace_modify_caller(&ftrace_graph_call, - ftrace_graph_caller, - enable); - - return ret; -} - -int ftrace_enable_ftrace_graph_caller(void) -{ - return ftrace_modify_graph_caller(true); -} - -int ftrace_disable_ftrace_graph_caller(void) -{ - return ftrace_modify_graph_caller(false); -} -#endif /* CONFIG_DYNAMIC_FTRACE */ -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/tile/kernel/hardwall.c b/arch/tile/kernel/hardwall.c deleted file mode 100644 index 2fd1694ac1d0..000000000000 --- a/arch/tile/kernel/hardwall.c +++ /dev/null @@ -1,1096 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -/* - * Implement a per-cpu "hardwall" resource class such as UDN or IPI. - * We use "hardwall" nomenclature throughout for historical reasons. - * The lock here controls access to the list data structure as well as - * to the items on the list. - */ -struct hardwall_type { - int index; - int is_xdn; - int is_idn; - int disabled; - const char *name; - struct list_head list; - spinlock_t lock; - struct proc_dir_entry *proc_dir; -}; - -enum hardwall_index { - HARDWALL_UDN = 0, -#ifndef __tilepro__ - HARDWALL_IDN = 1, - HARDWALL_IPI = 2, -#endif - _HARDWALL_TYPES -}; - -static struct hardwall_type hardwall_types[] = { - { /* user-space access to UDN */ - 0, - 1, - 0, - 0, - "udn", - LIST_HEAD_INIT(hardwall_types[HARDWALL_UDN].list), - __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_UDN].lock), - NULL - }, -#ifndef __tilepro__ - { /* user-space access to IDN */ - 1, - 1, - 1, - 1, /* disabled pending hypervisor support */ - "idn", - LIST_HEAD_INIT(hardwall_types[HARDWALL_IDN].list), - __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_IDN].lock), - NULL - }, - { /* access to user-space IPI */ - 2, - 0, - 0, - 0, - "ipi", - LIST_HEAD_INIT(hardwall_types[HARDWALL_IPI].list), - __SPIN_LOCK_UNLOCKED(hardwall_types[HARDWALL_IPI].lock), - NULL - }, -#endif -}; - -/* - * This data structure tracks the cpu data, etc., associated - * one-to-one with a "struct file *" from opening a hardwall device file. - * Note that the file's private data points back to this structure. - */ -struct hardwall_info { - struct list_head list; /* for hardwall_types.list */ - struct list_head task_head; /* head of tasks in this hardwall */ - struct hardwall_type *type; /* type of this resource */ - struct cpumask cpumask; /* cpus reserved */ - int id; /* integer id for this hardwall */ - int teardown_in_progress; /* are we tearing this one down? */ - - /* Remaining fields only valid for user-network resources. */ - int ulhc_x; /* upper left hand corner x coord */ - int ulhc_y; /* upper left hand corner y coord */ - int width; /* rectangle width */ - int height; /* rectangle height */ -#if CHIP_HAS_REV1_XDN() - atomic_t xdn_pending_count; /* cores in phase 1 of drain */ -#endif -}; - - -/* /proc/tile/hardwall */ -static struct proc_dir_entry *hardwall_proc_dir; - -/* Functions to manage files in /proc/tile/hardwall. */ -static void hardwall_add_proc(struct hardwall_info *); -static void hardwall_remove_proc(struct hardwall_info *); - -/* Allow disabling UDN access. */ -static int __init noudn(char *str) -{ - pr_info("User-space UDN access is disabled\n"); - hardwall_types[HARDWALL_UDN].disabled = 1; - return 0; -} -early_param("noudn", noudn); - -#ifndef __tilepro__ -/* Allow disabling IDN access. */ -static int __init noidn(char *str) -{ - pr_info("User-space IDN access is disabled\n"); - hardwall_types[HARDWALL_IDN].disabled = 1; - return 0; -} -early_param("noidn", noidn); - -/* Allow disabling IPI access. */ -static int __init noipi(char *str) -{ - pr_info("User-space IPI access is disabled\n"); - hardwall_types[HARDWALL_IPI].disabled = 1; - return 0; -} -early_param("noipi", noipi); -#endif - - -/* - * Low-level primitives for UDN/IDN - */ - -#ifdef __tilepro__ -#define mtspr_XDN(hwt, name, val) \ - do { (void)(hwt); __insn_mtspr(SPR_UDN_##name, (val)); } while (0) -#define mtspr_MPL_XDN(hwt, name, val) \ - do { (void)(hwt); __insn_mtspr(SPR_MPL_UDN_##name, (val)); } while (0) -#define mfspr_XDN(hwt, name) \ - ((void)(hwt), __insn_mfspr(SPR_UDN_##name)) -#else -#define mtspr_XDN(hwt, name, val) \ - do { \ - if ((hwt)->is_idn) \ - __insn_mtspr(SPR_IDN_##name, (val)); \ - else \ - __insn_mtspr(SPR_UDN_##name, (val)); \ - } while (0) -#define mtspr_MPL_XDN(hwt, name, val) \ - do { \ - if ((hwt)->is_idn) \ - __insn_mtspr(SPR_MPL_IDN_##name, (val)); \ - else \ - __insn_mtspr(SPR_MPL_UDN_##name, (val)); \ - } while (0) -#define mfspr_XDN(hwt, name) \ - ((hwt)->is_idn ? __insn_mfspr(SPR_IDN_##name) : __insn_mfspr(SPR_UDN_##name)) -#endif - -/* Set a CPU bit if the CPU is online. */ -#define cpu_online_set(cpu, dst) do { \ - if (cpu_online(cpu)) \ - cpumask_set_cpu(cpu, dst); \ -} while (0) - - -/* Does the given rectangle contain the given x,y coordinate? */ -static int contains(struct hardwall_info *r, int x, int y) -{ - return (x >= r->ulhc_x && x < r->ulhc_x + r->width) && - (y >= r->ulhc_y && y < r->ulhc_y + r->height); -} - -/* Compute the rectangle parameters and validate the cpumask. */ -static int check_rectangle(struct hardwall_info *r, struct cpumask *mask) -{ - int x, y, cpu, ulhc, lrhc; - - /* The first cpu is the ULHC, the last the LRHC. */ - ulhc = find_first_bit(cpumask_bits(mask), nr_cpumask_bits); - lrhc = find_last_bit(cpumask_bits(mask), nr_cpumask_bits); - - /* Compute the rectangle attributes from the cpus. */ - r->ulhc_x = cpu_x(ulhc); - r->ulhc_y = cpu_y(ulhc); - r->width = cpu_x(lrhc) - r->ulhc_x + 1; - r->height = cpu_y(lrhc) - r->ulhc_y + 1; - - /* Width and height must be positive */ - if (r->width <= 0 || r->height <= 0) - return -EINVAL; - - /* Confirm that the cpumask is exactly the rectangle. */ - for (y = 0, cpu = 0; y < smp_height; ++y) - for (x = 0; x < smp_width; ++x, ++cpu) - if (cpumask_test_cpu(cpu, mask) != contains(r, x, y)) - return -EINVAL; - - /* - * Note that offline cpus can't be drained when this user network - * rectangle eventually closes. We used to detect this - * situation and print a warning, but it annoyed users and - * they ignored it anyway, so now we just return without a - * warning. - */ - return 0; -} - -/* - * Hardware management of hardwall setup, teardown, trapping, - * and enabling/disabling PL0 access to the networks. - */ - -/* Bit field values to mask together for writes to SPR_XDN_DIRECTION_PROTECT */ -enum direction_protect { - N_PROTECT = (1 << 0), - E_PROTECT = (1 << 1), - S_PROTECT = (1 << 2), - W_PROTECT = (1 << 3), - C_PROTECT = (1 << 4), -}; - -static inline int xdn_which_interrupt(struct hardwall_type *hwt) -{ -#ifndef __tilepro__ - if (hwt->is_idn) - return INT_IDN_FIREWALL; -#endif - return INT_UDN_FIREWALL; -} - -static void enable_firewall_interrupts(struct hardwall_type *hwt) -{ - arch_local_irq_unmask_now(xdn_which_interrupt(hwt)); -} - -static void disable_firewall_interrupts(struct hardwall_type *hwt) -{ - arch_local_irq_mask_now(xdn_which_interrupt(hwt)); -} - -/* Set up hardwall on this cpu based on the passed hardwall_info. */ -static void hardwall_setup_func(void *info) -{ - struct hardwall_info *r = info; - struct hardwall_type *hwt = r->type; - - int cpu = smp_processor_id(); /* on_each_cpu disables preemption */ - int x = cpu_x(cpu); - int y = cpu_y(cpu); - int bits = 0; - if (x == r->ulhc_x) - bits |= W_PROTECT; - if (x == r->ulhc_x + r->width - 1) - bits |= E_PROTECT; - if (y == r->ulhc_y) - bits |= N_PROTECT; - if (y == r->ulhc_y + r->height - 1) - bits |= S_PROTECT; - BUG_ON(bits == 0); - mtspr_XDN(hwt, DIRECTION_PROTECT, bits); - enable_firewall_interrupts(hwt); -} - -/* Set up all cpus on edge of rectangle to enable/disable hardwall SPRs. */ -static void hardwall_protect_rectangle(struct hardwall_info *r) -{ - int x, y, cpu, delta; - struct cpumask rect_cpus; - - cpumask_clear(&rect_cpus); - - /* First include the top and bottom edges */ - cpu = r->ulhc_y * smp_width + r->ulhc_x; - delta = (r->height - 1) * smp_width; - for (x = 0; x < r->width; ++x, ++cpu) { - cpu_online_set(cpu, &rect_cpus); - cpu_online_set(cpu + delta, &rect_cpus); - } - - /* Then the left and right edges */ - cpu -= r->width; - delta = r->width - 1; - for (y = 0; y < r->height; ++y, cpu += smp_width) { - cpu_online_set(cpu, &rect_cpus); - cpu_online_set(cpu + delta, &rect_cpus); - } - - /* Then tell all the cpus to set up their protection SPR */ - on_each_cpu_mask(&rect_cpus, hardwall_setup_func, r, 1); -} - -/* Entered from INT_xDN_FIREWALL interrupt vector with irqs disabled. */ -void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num) -{ - struct hardwall_info *rect; - struct hardwall_type *hwt; - struct task_struct *p; - struct siginfo info; - int cpu = smp_processor_id(); - int found_processes; - struct pt_regs *old_regs = set_irq_regs(regs); - - irq_enter(); - - /* Figure out which network trapped. */ - switch (fault_num) { -#ifndef __tilepro__ - case INT_IDN_FIREWALL: - hwt = &hardwall_types[HARDWALL_IDN]; - break; -#endif - case INT_UDN_FIREWALL: - hwt = &hardwall_types[HARDWALL_UDN]; - break; - default: - BUG(); - } - BUG_ON(hwt->disabled); - - /* This tile trapped a network access; find the rectangle. */ - spin_lock(&hwt->lock); - list_for_each_entry(rect, &hwt->list, list) { - if (cpumask_test_cpu(cpu, &rect->cpumask)) - break; - } - - /* - * It shouldn't be possible not to find this cpu on the - * rectangle list, since only cpus in rectangles get hardwalled. - * The hardwall is only removed after the user network is drained. - */ - BUG_ON(&rect->list == &hwt->list); - - /* - * If we already started teardown on this hardwall, don't worry; - * the abort signal has been sent and we are just waiting for things - * to quiesce. - */ - if (rect->teardown_in_progress) { - pr_notice("cpu %d: detected %s hardwall violation %#lx while teardown already in progress\n", - cpu, hwt->name, - (long)mfspr_XDN(hwt, DIRECTION_PROTECT)); - goto done; - } - - /* - * Kill off any process that is activated in this rectangle. - * We bypass security to deliver the signal, since it must be - * one of the activated processes that generated the user network - * message that caused this trap, and all the activated - * processes shared a single open file so are pretty tightly - * bound together from a security point of view to begin with. - */ - rect->teardown_in_progress = 1; - wmb(); /* Ensure visibility of rectangle before notifying processes. */ - pr_notice("cpu %d: detected %s hardwall violation %#lx...\n", - cpu, hwt->name, (long)mfspr_XDN(hwt, DIRECTION_PROTECT)); - info.si_signo = SIGILL; - info.si_errno = 0; - info.si_code = ILL_HARDWALL; - found_processes = 0; - list_for_each_entry(p, &rect->task_head, - thread.hardwall[hwt->index].list) { - BUG_ON(p->thread.hardwall[hwt->index].info != rect); - if (!(p->flags & PF_EXITING)) { - found_processes = 1; - pr_notice("hardwall: killing %d\n", p->pid); - do_send_sig_info(info.si_signo, &info, p, false); - } - } - if (!found_processes) - pr_notice("hardwall: no associated processes!\n"); - - done: - spin_unlock(&hwt->lock); - - /* - * We have to disable firewall interrupts now, or else when we - * return from this handler, we will simply re-interrupt back to - * it. However, we can't clear the protection bits, since we - * haven't yet drained the network, and that would allow packets - * to cross out of the hardwall region. - */ - disable_firewall_interrupts(hwt); - - irq_exit(); - set_irq_regs(old_regs); -} - -/* Allow access from user space to the user network. */ -void grant_hardwall_mpls(struct hardwall_type *hwt) -{ -#ifndef __tilepro__ - if (!hwt->is_xdn) { - __insn_mtspr(SPR_MPL_IPI_0_SET_0, 1); - return; - } -#endif - mtspr_MPL_XDN(hwt, ACCESS_SET_0, 1); - mtspr_MPL_XDN(hwt, AVAIL_SET_0, 1); - mtspr_MPL_XDN(hwt, COMPLETE_SET_0, 1); - mtspr_MPL_XDN(hwt, TIMER_SET_0, 1); -#if !CHIP_HAS_REV1_XDN() - mtspr_MPL_XDN(hwt, REFILL_SET_0, 1); - mtspr_MPL_XDN(hwt, CA_SET_0, 1); -#endif -} - -/* Deny access from user space to the user network. */ -void restrict_hardwall_mpls(struct hardwall_type *hwt) -{ -#ifndef __tilepro__ - if (!hwt->is_xdn) { - __insn_mtspr(SPR_MPL_IPI_0_SET_1, 1); - return; - } -#endif - mtspr_MPL_XDN(hwt, ACCESS_SET_1, 1); - mtspr_MPL_XDN(hwt, AVAIL_SET_1, 1); - mtspr_MPL_XDN(hwt, COMPLETE_SET_1, 1); - mtspr_MPL_XDN(hwt, TIMER_SET_1, 1); -#if !CHIP_HAS_REV1_XDN() - mtspr_MPL_XDN(hwt, REFILL_SET_1, 1); - mtspr_MPL_XDN(hwt, CA_SET_1, 1); -#endif -} - -/* Restrict or deny as necessary for the task we're switching to. */ -void hardwall_switch_tasks(struct task_struct *prev, - struct task_struct *next) -{ - int i; - for (i = 0; i < HARDWALL_TYPES; ++i) { - if (prev->thread.hardwall[i].info != NULL) { - if (next->thread.hardwall[i].info == NULL) - restrict_hardwall_mpls(&hardwall_types[i]); - } else if (next->thread.hardwall[i].info != NULL) { - grant_hardwall_mpls(&hardwall_types[i]); - } - } -} - -/* Does this task have the right to IPI the given cpu? */ -int hardwall_ipi_valid(int cpu) -{ -#ifdef __tilegx__ - struct hardwall_info *info = - current->thread.hardwall[HARDWALL_IPI].info; - return info && cpumask_test_cpu(cpu, &info->cpumask); -#else - return 0; -#endif -} - -/* - * Code to create, activate, deactivate, and destroy hardwall resources. - */ - -/* Create a hardwall for the given resource */ -static struct hardwall_info *hardwall_create(struct hardwall_type *hwt, - size_t size, - const unsigned char __user *bits) -{ - struct hardwall_info *iter, *info; - struct cpumask mask; - unsigned long flags; - int rc; - - /* Reject crazy sizes out of hand, a la sys_mbind(). */ - if (size > PAGE_SIZE) - return ERR_PTR(-EINVAL); - - /* Copy whatever fits into a cpumask. */ - if (copy_from_user(&mask, bits, min(sizeof(struct cpumask), size))) - return ERR_PTR(-EFAULT); - - /* - * If the size was short, clear the rest of the mask; - * otherwise validate that the rest of the user mask was zero - * (we don't try hard to be efficient when validating huge masks). - */ - if (size < sizeof(struct cpumask)) { - memset((char *)&mask + size, 0, sizeof(struct cpumask) - size); - } else if (size > sizeof(struct cpumask)) { - size_t i; - for (i = sizeof(struct cpumask); i < size; ++i) { - char c; - if (get_user(c, &bits[i])) - return ERR_PTR(-EFAULT); - if (c) - return ERR_PTR(-EINVAL); - } - } - - /* Allocate a new hardwall_info optimistically. */ - info = kmalloc(sizeof(struct hardwall_info), - GFP_KERNEL | __GFP_ZERO); - if (info == NULL) - return ERR_PTR(-ENOMEM); - INIT_LIST_HEAD(&info->task_head); - info->type = hwt; - - /* Compute the rectangle size and validate that it's plausible. */ - cpumask_copy(&info->cpumask, &mask); - info->id = find_first_bit(cpumask_bits(&mask), nr_cpumask_bits); - if (hwt->is_xdn) { - rc = check_rectangle(info, &mask); - if (rc != 0) { - kfree(info); - return ERR_PTR(rc); - } - } - - /* - * Eliminate cpus that are not part of this Linux client. - * Note that this allows for configurations that we might not want to - * support, such as one client on every even cpu, another client on - * every odd cpu. - */ - cpumask_and(&info->cpumask, &info->cpumask, cpu_online_mask); - - /* Confirm it doesn't overlap and add it to the list. */ - spin_lock_irqsave(&hwt->lock, flags); - list_for_each_entry(iter, &hwt->list, list) { - if (cpumask_intersects(&iter->cpumask, &info->cpumask)) { - spin_unlock_irqrestore(&hwt->lock, flags); - kfree(info); - return ERR_PTR(-EBUSY); - } - } - list_add_tail(&info->list, &hwt->list); - spin_unlock_irqrestore(&hwt->lock, flags); - - /* Set up appropriate hardwalling on all affected cpus. */ - if (hwt->is_xdn) - hardwall_protect_rectangle(info); - - /* Create a /proc/tile/hardwall entry. */ - hardwall_add_proc(info); - - return info; -} - -/* Activate a given hardwall on this cpu for this process. */ -static int hardwall_activate(struct hardwall_info *info) -{ - int cpu; - unsigned long flags; - struct task_struct *p = current; - struct thread_struct *ts = &p->thread; - struct hardwall_type *hwt; - - /* Require a hardwall. */ - if (info == NULL) - return -ENODATA; - - /* Not allowed to activate a hardwall that is being torn down. */ - if (info->teardown_in_progress) - return -EINVAL; - - /* - * Get our affinity; if we're not bound to this tile uniquely, - * we can't access the network registers. - */ - if (cpumask_weight(&p->cpus_allowed) != 1) - return -EPERM; - - /* Make sure we are bound to a cpu assigned to this resource. */ - cpu = smp_processor_id(); - BUG_ON(cpumask_first(&p->cpus_allowed) != cpu); - if (!cpumask_test_cpu(cpu, &info->cpumask)) - return -EINVAL; - - /* If we are already bound to this hardwall, it's a no-op. */ - hwt = info->type; - if (ts->hardwall[hwt->index].info) { - BUG_ON(ts->hardwall[hwt->index].info != info); - return 0; - } - - /* Success! This process gets to use the resource on this cpu. */ - ts->hardwall[hwt->index].info = info; - spin_lock_irqsave(&hwt->lock, flags); - list_add(&ts->hardwall[hwt->index].list, &info->task_head); - spin_unlock_irqrestore(&hwt->lock, flags); - grant_hardwall_mpls(hwt); - printk(KERN_DEBUG "Pid %d (%s) activated for %s hardwall: cpu %d\n", - p->pid, p->comm, hwt->name, cpu); - return 0; -} - -/* - * Deactivate a task's hardwall. Must hold lock for hardwall_type. - * This method may be called from exit_thread(), so we don't want to - * rely on too many fields of struct task_struct still being valid. - * We assume the cpus_allowed, pid, and comm fields are still valid. - */ -static void _hardwall_deactivate(struct hardwall_type *hwt, - struct task_struct *task) -{ - struct thread_struct *ts = &task->thread; - - if (cpumask_weight(&task->cpus_allowed) != 1) { - pr_err("pid %d (%s) releasing %s hardwall with an affinity mask containing %d cpus!\n", - task->pid, task->comm, hwt->name, - cpumask_weight(&task->cpus_allowed)); - BUG(); - } - - BUG_ON(ts->hardwall[hwt->index].info == NULL); - ts->hardwall[hwt->index].info = NULL; - list_del(&ts->hardwall[hwt->index].list); - if (task == current) - restrict_hardwall_mpls(hwt); -} - -/* Deactivate a task's hardwall. */ -static int hardwall_deactivate(struct hardwall_type *hwt, - struct task_struct *task) -{ - unsigned long flags; - int activated; - - spin_lock_irqsave(&hwt->lock, flags); - activated = (task->thread.hardwall[hwt->index].info != NULL); - if (activated) - _hardwall_deactivate(hwt, task); - spin_unlock_irqrestore(&hwt->lock, flags); - - if (!activated) - return -EINVAL; - - printk(KERN_DEBUG "Pid %d (%s) deactivated for %s hardwall: cpu %d\n", - task->pid, task->comm, hwt->name, raw_smp_processor_id()); - return 0; -} - -void hardwall_deactivate_all(struct task_struct *task) -{ - int i; - for (i = 0; i < HARDWALL_TYPES; ++i) - if (task->thread.hardwall[i].info) - hardwall_deactivate(&hardwall_types[i], task); -} - -/* Stop the switch before draining the network. */ -static void stop_xdn_switch(void *arg) -{ -#if !CHIP_HAS_REV1_XDN() - /* Freeze the switch and the demux. */ - __insn_mtspr(SPR_UDN_SP_FREEZE, - SPR_UDN_SP_FREEZE__SP_FRZ_MASK | - SPR_UDN_SP_FREEZE__DEMUX_FRZ_MASK | - SPR_UDN_SP_FREEZE__NON_DEST_EXT_MASK); -#else - /* - * Drop all packets bound for the core or off the edge. - * We rely on the normal hardwall protection setup code - * to have set the low four bits to trigger firewall interrupts, - * and shift those bits up to trigger "drop on send" semantics, - * plus adding "drop on send to core" for all switches. - * In practice it seems the switches latch the DIRECTION_PROTECT - * SPR so they won't start dropping if they're already - * delivering the last message to the core, but it doesn't - * hurt to enable it here. - */ - struct hardwall_type *hwt = arg; - unsigned long protect = mfspr_XDN(hwt, DIRECTION_PROTECT); - mtspr_XDN(hwt, DIRECTION_PROTECT, (protect | C_PROTECT) << 5); -#endif -} - -static void empty_xdn_demuxes(struct hardwall_type *hwt) -{ -#ifndef __tilepro__ - if (hwt->is_idn) { - while (__insn_mfspr(SPR_IDN_DATA_AVAIL) & (1 << 0)) - (void) __tile_idn0_receive(); - while (__insn_mfspr(SPR_IDN_DATA_AVAIL) & (1 << 1)) - (void) __tile_idn1_receive(); - return; - } -#endif - while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 0)) - (void) __tile_udn0_receive(); - while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 1)) - (void) __tile_udn1_receive(); - while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 2)) - (void) __tile_udn2_receive(); - while (__insn_mfspr(SPR_UDN_DATA_AVAIL) & (1 << 3)) - (void) __tile_udn3_receive(); -} - -/* Drain all the state from a stopped switch. */ -static void drain_xdn_switch(void *arg) -{ - struct hardwall_info *info = arg; - struct hardwall_type *hwt = info->type; - -#if CHIP_HAS_REV1_XDN() - /* - * The switches have been configured to drop any messages - * destined for cores (or off the edge of the rectangle). - * But the current message may continue to be delivered, - * so we wait until all the cores have finished any pending - * messages before we stop draining. - */ - int pending = mfspr_XDN(hwt, PENDING); - while (pending--) { - empty_xdn_demuxes(hwt); - if (hwt->is_idn) - __tile_idn_send(0); - else - __tile_udn_send(0); - } - atomic_dec(&info->xdn_pending_count); - while (atomic_read(&info->xdn_pending_count)) - empty_xdn_demuxes(hwt); -#else - int i; - int from_tile_words, ca_count; - - /* Empty out the 5 switch point fifos. */ - for (i = 0; i < 5; i++) { - int words, j; - __insn_mtspr(SPR_UDN_SP_FIFO_SEL, i); - words = __insn_mfspr(SPR_UDN_SP_STATE) & 0xF; - for (j = 0; j < words; j++) - (void) __insn_mfspr(SPR_UDN_SP_FIFO_DATA); - BUG_ON((__insn_mfspr(SPR_UDN_SP_STATE) & 0xF) != 0); - } - - /* Dump out the 3 word fifo at top. */ - from_tile_words = (__insn_mfspr(SPR_UDN_DEMUX_STATUS) >> 10) & 0x3; - for (i = 0; i < from_tile_words; i++) - (void) __insn_mfspr(SPR_UDN_DEMUX_WRITE_FIFO); - - /* Empty out demuxes. */ - empty_xdn_demuxes(hwt); - - /* Empty out catch all. */ - ca_count = __insn_mfspr(SPR_UDN_DEMUX_CA_COUNT); - for (i = 0; i < ca_count; i++) - (void) __insn_mfspr(SPR_UDN_CA_DATA); - BUG_ON(__insn_mfspr(SPR_UDN_DEMUX_CA_COUNT) != 0); - - /* Clear demux logic. */ - __insn_mtspr(SPR_UDN_DEMUX_CTL, 1); - - /* - * Write switch state; experimentation indicates that 0xc3000 - * is an idle switch point. - */ - for (i = 0; i < 5; i++) { - __insn_mtspr(SPR_UDN_SP_FIFO_SEL, i); - __insn_mtspr(SPR_UDN_SP_STATE, 0xc3000); - } -#endif -} - -/* Reset random XDN state registers at boot up and during hardwall teardown. */ -static void reset_xdn_network_state(struct hardwall_type *hwt) -{ - if (hwt->disabled) - return; - - /* Clear out other random registers so we have a clean slate. */ - mtspr_XDN(hwt, DIRECTION_PROTECT, 0); - mtspr_XDN(hwt, AVAIL_EN, 0); - mtspr_XDN(hwt, DEADLOCK_TIMEOUT, 0); - -#if !CHIP_HAS_REV1_XDN() - /* Reset UDN coordinates to their standard value */ - { - unsigned int cpu = smp_processor_id(); - unsigned int x = cpu_x(cpu); - unsigned int y = cpu_y(cpu); - __insn_mtspr(SPR_UDN_TILE_COORD, (x << 18) | (y << 7)); - } - - /* Set demux tags to predefined values and enable them. */ - __insn_mtspr(SPR_UDN_TAG_VALID, 0xf); - __insn_mtspr(SPR_UDN_TAG_0, (1 << 0)); - __insn_mtspr(SPR_UDN_TAG_1, (1 << 1)); - __insn_mtspr(SPR_UDN_TAG_2, (1 << 2)); - __insn_mtspr(SPR_UDN_TAG_3, (1 << 3)); - - /* Set other rev0 random registers to a clean state. */ - __insn_mtspr(SPR_UDN_REFILL_EN, 0); - __insn_mtspr(SPR_UDN_DEMUX_QUEUE_SEL, 0); - __insn_mtspr(SPR_UDN_SP_FIFO_SEL, 0); - - /* Start the switch and demux. */ - __insn_mtspr(SPR_UDN_SP_FREEZE, 0); -#endif -} - -void reset_network_state(void) -{ - reset_xdn_network_state(&hardwall_types[HARDWALL_UDN]); -#ifndef __tilepro__ - reset_xdn_network_state(&hardwall_types[HARDWALL_IDN]); -#endif -} - -/* Restart an XDN switch after draining. */ -static void restart_xdn_switch(void *arg) -{ - struct hardwall_type *hwt = arg; - -#if CHIP_HAS_REV1_XDN() - /* One last drain step to avoid races with injection and draining. */ - empty_xdn_demuxes(hwt); -#endif - - reset_xdn_network_state(hwt); - - /* Disable firewall interrupts. */ - disable_firewall_interrupts(hwt); -} - -/* Last reference to a hardwall is gone, so clear the network. */ -static void hardwall_destroy(struct hardwall_info *info) -{ - struct task_struct *task; - struct hardwall_type *hwt; - unsigned long flags; - - /* Make sure this file actually represents a hardwall. */ - if (info == NULL) - return; - - /* - * Deactivate any remaining tasks. It's possible to race with - * some other thread that is exiting and hasn't yet called - * deactivate (when freeing its thread_info), so we carefully - * deactivate any remaining tasks before freeing the - * hardwall_info object itself. - */ - hwt = info->type; - info->teardown_in_progress = 1; - spin_lock_irqsave(&hwt->lock, flags); - list_for_each_entry(task, &info->task_head, - thread.hardwall[hwt->index].list) - _hardwall_deactivate(hwt, task); - spin_unlock_irqrestore(&hwt->lock, flags); - - if (hwt->is_xdn) { - /* Configure the switches for draining the user network. */ - printk(KERN_DEBUG - "Clearing %s hardwall rectangle %dx%d %d,%d\n", - hwt->name, info->width, info->height, - info->ulhc_x, info->ulhc_y); - on_each_cpu_mask(&info->cpumask, stop_xdn_switch, hwt, 1); - - /* Drain the network. */ -#if CHIP_HAS_REV1_XDN() - atomic_set(&info->xdn_pending_count, - cpumask_weight(&info->cpumask)); - on_each_cpu_mask(&info->cpumask, drain_xdn_switch, info, 0); -#else - on_each_cpu_mask(&info->cpumask, drain_xdn_switch, info, 1); -#endif - - /* Restart switch and disable firewall. */ - on_each_cpu_mask(&info->cpumask, restart_xdn_switch, hwt, 1); - } - - /* Remove the /proc/tile/hardwall entry. */ - hardwall_remove_proc(info); - - /* Now free the hardwall from the list. */ - spin_lock_irqsave(&hwt->lock, flags); - BUG_ON(!list_empty(&info->task_head)); - list_del(&info->list); - spin_unlock_irqrestore(&hwt->lock, flags); - kfree(info); -} - - -static int hardwall_proc_show(struct seq_file *sf, void *v) -{ - struct hardwall_info *info = sf->private; - - seq_printf(sf, "%*pbl\n", cpumask_pr_args(&info->cpumask)); - return 0; -} - -static int hardwall_proc_open(struct inode *inode, - struct file *file) -{ - return single_open(file, hardwall_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations hardwall_proc_fops = { - .open = hardwall_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void hardwall_add_proc(struct hardwall_info *info) -{ - char buf[64]; - snprintf(buf, sizeof(buf), "%d", info->id); - proc_create_data(buf, 0444, info->type->proc_dir, - &hardwall_proc_fops, info); -} - -static void hardwall_remove_proc(struct hardwall_info *info) -{ - char buf[64]; - snprintf(buf, sizeof(buf), "%d", info->id); - remove_proc_entry(buf, info->type->proc_dir); -} - -int proc_pid_hardwall(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - int i; - int n = 0; - for (i = 0; i < HARDWALL_TYPES; ++i) { - struct hardwall_info *info = task->thread.hardwall[i].info; - if (info) - seq_printf(m, "%s: %d\n", info->type->name, info->id); - } - return n; -} - -void proc_tile_hardwall_init(struct proc_dir_entry *root) -{ - int i; - for (i = 0; i < HARDWALL_TYPES; ++i) { - struct hardwall_type *hwt = &hardwall_types[i]; - if (hwt->disabled) - continue; - if (hardwall_proc_dir == NULL) - hardwall_proc_dir = proc_mkdir("hardwall", root); - hwt->proc_dir = proc_mkdir(hwt->name, hardwall_proc_dir); - } -} - - -/* - * Character device support via ioctl/close. - */ - -static long hardwall_ioctl(struct file *file, unsigned int a, unsigned long b) -{ - struct hardwall_info *info = file->private_data; - int minor = iminor(file->f_mapping->host); - struct hardwall_type* hwt; - - if (_IOC_TYPE(a) != HARDWALL_IOCTL_BASE) - return -EINVAL; - - BUILD_BUG_ON(HARDWALL_TYPES != _HARDWALL_TYPES); - BUILD_BUG_ON(HARDWALL_TYPES != - sizeof(hardwall_types)/sizeof(hardwall_types[0])); - - if (minor < 0 || minor >= HARDWALL_TYPES) - return -EINVAL; - hwt = &hardwall_types[minor]; - WARN_ON(info && hwt != info->type); - - switch (_IOC_NR(a)) { - case _HARDWALL_CREATE: - if (hwt->disabled) - return -ENOSYS; - if (info != NULL) - return -EALREADY; - info = hardwall_create(hwt, _IOC_SIZE(a), - (const unsigned char __user *)b); - if (IS_ERR(info)) - return PTR_ERR(info); - file->private_data = info; - return 0; - - case _HARDWALL_ACTIVATE: - return hardwall_activate(info); - - case _HARDWALL_DEACTIVATE: - if (current->thread.hardwall[hwt->index].info != info) - return -EINVAL; - return hardwall_deactivate(hwt, current); - - case _HARDWALL_GET_ID: - return info ? info->id : -EINVAL; - - default: - return -EINVAL; - } -} - -#ifdef CONFIG_COMPAT -static long hardwall_compat_ioctl(struct file *file, - unsigned int a, unsigned long b) -{ - /* Sign-extend the argument so it can be used as a pointer. */ - return hardwall_ioctl(file, a, (unsigned long)compat_ptr(b)); -} -#endif - -/* The user process closed the file; revoke access to user networks. */ -static int hardwall_flush(struct file *file, fl_owner_t owner) -{ - struct hardwall_info *info = file->private_data; - struct task_struct *task, *tmp; - unsigned long flags; - - if (info) { - /* - * NOTE: if multiple threads are activated on this hardwall - * file, the other threads will continue having access to the - * user network until they are context-switched out and back - * in again. - * - * NOTE: A NULL files pointer means the task is being torn - * down, so in that case we also deactivate it. - */ - struct hardwall_type *hwt = info->type; - spin_lock_irqsave(&hwt->lock, flags); - list_for_each_entry_safe(task, tmp, &info->task_head, - thread.hardwall[hwt->index].list) { - if (task->files == owner || task->files == NULL) - _hardwall_deactivate(hwt, task); - } - spin_unlock_irqrestore(&hwt->lock, flags); - } - - return 0; -} - -/* This hardwall is gone, so destroy it. */ -static int hardwall_release(struct inode *inode, struct file *file) -{ - hardwall_destroy(file->private_data); - return 0; -} - -static const struct file_operations dev_hardwall_fops = { - .open = nonseekable_open, - .unlocked_ioctl = hardwall_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = hardwall_compat_ioctl, -#endif - .flush = hardwall_flush, - .release = hardwall_release, -}; - -static struct cdev hardwall_dev; - -static int __init dev_hardwall_init(void) -{ - int rc; - dev_t dev; - - rc = alloc_chrdev_region(&dev, 0, HARDWALL_TYPES, "hardwall"); - if (rc < 0) - return rc; - cdev_init(&hardwall_dev, &dev_hardwall_fops); - rc = cdev_add(&hardwall_dev, dev, HARDWALL_TYPES); - if (rc < 0) - return rc; - - return 0; -} -late_initcall(dev_hardwall_init); diff --git a/arch/tile/kernel/head_32.S b/arch/tile/kernel/head_32.S deleted file mode 100644 index 8d5b40ff2922..000000000000 --- a/arch/tile/kernel/head_32.S +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * TILE startup code. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * This module contains the entry code for kernel images. It performs the - * minimal setup needed to call the generic C routines. - */ - - __HEAD -ENTRY(_start) - /* Notify the hypervisor of what version of the API we want */ - { - movei r1, TILE_CHIP - movei r2, TILE_CHIP_REV - } - { - moveli r0, _HV_VERSION_OLD_HV_INIT - jal _hv_init - } - /* Get a reasonable default ASID in r0 */ - { - move r0, zero - jal _hv_inquire_asid - } - /* Install the default page table */ - { - moveli r6, lo16(swapper_pgprot - PAGE_OFFSET) - move r4, r0 /* use starting ASID of range for this page table */ - } - { - moveli r0, lo16(swapper_pg_dir - PAGE_OFFSET) - auli r6, r6, ha16(swapper_pgprot - PAGE_OFFSET) - } - { - lw r2, r6 - addi r6, r6, 4 - } - { - lw r3, r6 - auli r0, r0, ha16(swapper_pg_dir - PAGE_OFFSET) - } - { - finv r6 - move r1, zero /* high 32 bits of CPA is zero */ - } - { - moveli lr, lo16(1f) - moveli r5, CTX_PAGE_FLAG - } - { - auli lr, lr, ha16(1f) - j _hv_install_context - } -1: - - /* Get our processor number and save it away in SAVE_K_0. */ - jal _hv_inquire_topology - mulll_uu r4, r1, r2 /* r1 == y, r2 == width */ - add r4, r4, r0 /* r0 == x, so r4 == cpu == y*width + x */ - -#ifdef CONFIG_SMP - /* - * Load up our per-cpu offset. When the first (master) tile - * boots, this value is still zero, so we will load boot_pc - * with start_kernel, and boot_sp at the top of init_stack. - * The master tile initializes the per-cpu offset array, so that - * when subsequent (secondary) tiles boot, they will instead load - * from their per-cpu versions of boot_sp and boot_pc. - */ - moveli r5, lo16(__per_cpu_offset) - auli r5, r5, ha16(__per_cpu_offset) - s2a r5, r4, r5 - lw r5, r5 - bnz r5, 1f - - /* - * Save the width and height to the smp_topology variable - * for later use. - */ - moveli r0, lo16(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET) - auli r0, r0, ha16(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET) - { - sw r0, r2 - addi r0, r0, (HV_TOPOLOGY_HEIGHT_OFFSET - HV_TOPOLOGY_WIDTH_OFFSET) - } - sw r0, r3 -1: -#else - move r5, zero -#endif - - /* Load and go with the correct pc and sp. */ - { - addli r1, r5, lo16(boot_sp) - addli r0, r5, lo16(boot_pc) - } - { - auli r1, r1, ha16(boot_sp) - auli r0, r0, ha16(boot_pc) - } - lw r0, r0 - lw sp, r1 - or r4, sp, r4 - mtspr SPR_SYSTEM_SAVE_K_0, r4 /* save ksp0 + cpu */ - { - move lr, zero /* stop backtraces in the called function */ - jr r0 - } - ENDPROC(_start) - -__PAGE_ALIGNED_BSS - .align PAGE_SIZE -ENTRY(empty_zero_page) - .fill PAGE_SIZE,1,0 - END(empty_zero_page) - - .macro PTE va, cpa, bits1, no_org=0 - .ifeq \no_org - .org swapper_pg_dir + PGD_INDEX(\va) * HV_PTE_SIZE - .endif - .word HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED | \ - (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) - .word (\bits1) | (HV_CPA_TO_PTFN(\cpa) << (HV_PTE_INDEX_PTFN - 32)) - .endm - -__PAGE_ALIGNED_DATA - .align PAGE_SIZE -ENTRY(swapper_pg_dir) - /* - * All data pages from PAGE_OFFSET to MEM_USER_INTRPT are mapped as - * VA = PA + PAGE_OFFSET. We remap things with more precise access - * permissions and more respect for size of RAM later. - */ - .set addr, 0 - .rept (MEM_USER_INTRPT - PAGE_OFFSET) >> PGDIR_SHIFT - PTE addr + PAGE_OFFSET, addr, (1 << (HV_PTE_INDEX_READABLE - 32)) | \ - (1 << (HV_PTE_INDEX_WRITABLE - 32)) - .set addr, addr + PGDIR_SIZE - .endr - - /* The true text VAs are mapped as VA = PA + MEM_SV_START */ - PTE MEM_SV_START, 0, (1 << (HV_PTE_INDEX_READABLE - 32)) | \ - (1 << (HV_PTE_INDEX_EXECUTABLE - 32)) - .org swapper_pg_dir + PGDIR_SIZE - END(swapper_pg_dir) - - /* - * Isolate swapper_pgprot to its own cache line, since each cpu - * starting up will read it using VA-is-PA and local homing. - * This would otherwise likely conflict with other data on the cache - * line, once we have set its permanent home in the page tables. - */ - __INITDATA - .align CHIP_L2_LINE_SIZE() -ENTRY(swapper_pgprot) - PTE 0, 0, (1 << (HV_PTE_INDEX_READABLE - 32)) | \ - (1 << (HV_PTE_INDEX_WRITABLE - 32)), 1 - .align CHIP_L2_LINE_SIZE() - END(swapper_pgprot) diff --git a/arch/tile/kernel/head_64.S b/arch/tile/kernel/head_64.S deleted file mode 100644 index bd0e12f283f3..000000000000 --- a/arch/tile/kernel/head_64.S +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * TILE startup code. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Extract two 32-bit bit values that were read into one register. */ -#ifdef __BIG_ENDIAN__ -#define GET_FIRST_INT(rd, rs) shrsi rd, rs, 32 -#define GET_SECOND_INT(rd, rs) addxi rd, rs, 0 -#else -#define GET_FIRST_INT(rd, rs) addxi rd, rs, 0 -#define GET_SECOND_INT(rd, rs) shrsi rd, rs, 32 -#endif - -/* - * This module contains the entry code for kernel images. It performs the - * minimal setup needed to call the generic C routines. - */ - - __HEAD -ENTRY(_start) - /* Notify the hypervisor of what version of the API we want */ - { -#if KERNEL_PL == 1 && _HV_VERSION == 13 - /* Support older hypervisors by asking for API version 12. */ - movei r0, _HV_VERSION_OLD_HV_INIT -#else - movei r0, _HV_VERSION -#endif - movei r1, TILE_CHIP - } - { - movei r2, TILE_CHIP_REV - movei r3, KERNEL_PL - } - jal _hv_init - /* Get a reasonable default ASID in r0 */ - { - move r0, zero - jal _hv_inquire_asid - } - - /* - * Install the default page table. The relocation required to - * statically define the table is a bit too complex, so we have - * to plug in the pointer from the L0 to the L1 table by hand. - * We only do this on the first cpu to boot, though, since the - * other CPUs should see a properly-constructed page table. - */ - { - GET_FIRST_INT(r2, r0) /* ASID for hv_install_context */ - moveli r4, hw1_last(swapper_pgprot - PAGE_OFFSET) - } - { - shl16insli r4, r4, hw0(swapper_pgprot - PAGE_OFFSET) - } - { - ld r1, r4 /* access_pte for hv_install_context */ - } - { - moveli r0, hw1_last(.Lsv_data_pmd - PAGE_OFFSET) - moveli r6, hw1_last(temp_data_pmd - PAGE_OFFSET) - } - { - /* After initializing swapper_pgprot, HV_PTE_GLOBAL is set. */ - bfextu r7, r1, HV_PTE_INDEX_GLOBAL, HV_PTE_INDEX_GLOBAL - finv r4 - } - bnez r7, .Lno_write - { - shl16insli r0, r0, hw0(.Lsv_data_pmd - PAGE_OFFSET) - shl16insli r6, r6, hw0(temp_data_pmd - PAGE_OFFSET) - } - { - /* Cut off the low bits of the PT address. */ - shrui r6, r6, HV_LOG2_PAGE_TABLE_ALIGN - /* Start with our access pte. */ - move r5, r1 - } - { - /* Stuff the address into the page table pointer slot of the PTE. */ - bfins r5, r6, HV_PTE_INDEX_PTFN, \ - HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1 - } - { - /* Store the L0 data PTE. */ - st r0, r5 - addli r6, r6, (temp_code_pmd - temp_data_pmd) >> \ - HV_LOG2_PAGE_TABLE_ALIGN - } - { - addli r0, r0, .Lsv_code_pmd - .Lsv_data_pmd - bfins r5, r6, HV_PTE_INDEX_PTFN, \ - HV_PTE_INDEX_PTFN + HV_PTE_PTFN_BITS - 1 - } - /* Store the L0 code PTE. */ - st r0, r5 - -.Lno_write: - moveli lr, hw2_last(1f) - { - shl16insli lr, lr, hw1(1f) - moveli r0, hw1_last(swapper_pg_dir - PAGE_OFFSET) - } - { - shl16insli lr, lr, hw0(1f) - shl16insli r0, r0, hw0(swapper_pg_dir - PAGE_OFFSET) - } - { - moveli r3, CTX_PAGE_FLAG - j _hv_install_context - } -1: - - /* Install the interrupt base. */ - moveli r0, hw2_last(intrpt_start) - shl16insli r0, r0, hw1(intrpt_start) - shl16insli r0, r0, hw0(intrpt_start) - mtspr SPR_INTERRUPT_VECTOR_BASE_K, r0 - - /* Get our processor number and save it away in SAVE_K_0. */ - jal _hv_inquire_topology - { - GET_FIRST_INT(r5, r1) /* r5 = width */ - GET_SECOND_INT(r4, r0) /* r4 = y */ - } - { - GET_FIRST_INT(r6, r0) /* r6 = x */ - mul_lu_lu r4, r4, r5 - } - { - add r4, r4, r6 /* r4 == cpu == y*width + x */ - } - -#ifdef CONFIG_SMP - /* - * Load up our per-cpu offset. When the first (master) tile - * boots, this value is still zero, so we will load boot_pc - * with start_kernel, and boot_sp with at the top of init_stack. - * The master tile initializes the per-cpu offset array, so that - * when subsequent (secondary) tiles boot, they will instead load - * from their per-cpu versions of boot_sp and boot_pc. - */ - moveli r5, hw2_last(__per_cpu_offset) - shl16insli r5, r5, hw1(__per_cpu_offset) - shl16insli r5, r5, hw0(__per_cpu_offset) - shl3add r5, r4, r5 - ld r5, r5 - bnez r5, 1f - - /* - * Save the width and height to the smp_topology variable - * for later use. - */ - moveli r0, hw2_last(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET) - shl16insli r0, r0, hw1(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET) - shl16insli r0, r0, hw0(smp_topology + HV_TOPOLOGY_WIDTH_OFFSET) - st r0, r1 -1: -#else - move r5, zero -#endif - - /* Load and go with the correct pc and sp. */ - { - moveli r1, hw2_last(boot_sp) - moveli r0, hw2_last(boot_pc) - } - { - shl16insli r1, r1, hw1(boot_sp) - shl16insli r0, r0, hw1(boot_pc) - } - { - shl16insli r1, r1, hw0(boot_sp) - shl16insli r0, r0, hw0(boot_pc) - } - { - add r1, r1, r5 - add r0, r0, r5 - } - ld r0, r0 - ld sp, r1 - shli r4, r4, CPU_SHIFT - bfins r4, sp, 0, CPU_SHIFT-1 - mtspr SPR_SYSTEM_SAVE_K_0, r4 /* save ksp0 + cpu */ - { - move lr, zero /* stop backtraces in the called function */ - jr r0 - } - ENDPROC(_start) - -__PAGE_ALIGNED_BSS - .align PAGE_SIZE -ENTRY(empty_zero_page) - .fill PAGE_SIZE,1,0 - END(empty_zero_page) - - .macro PTE cpa, bits1 - .quad HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED |\ - HV_PTE_GLOBAL | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) |\ - (\bits1) | (HV_CPA_TO_PTFN(\cpa) << HV_PTE_INDEX_PTFN) - .endm - -__PAGE_ALIGNED_DATA - .align PAGE_SIZE -ENTRY(swapper_pg_dir) - .org swapper_pg_dir + PGD_INDEX(PAGE_OFFSET) * HV_PTE_SIZE -.Lsv_data_pmd: - .quad 0 /* PTE temp_data_pmd - PAGE_OFFSET, 0 */ - .org swapper_pg_dir + PGD_INDEX(MEM_SV_START) * HV_PTE_SIZE -.Lsv_code_pmd: - .quad 0 /* PTE temp_code_pmd - PAGE_OFFSET, 0 */ - .org swapper_pg_dir + SIZEOF_PGD - END(swapper_pg_dir) - - .align HV_PAGE_TABLE_ALIGN -ENTRY(temp_data_pmd) - /* - * We fill the PAGE_OFFSET pmd with huge pages with - * VA = PA + PAGE_OFFSET. We remap things with more precise access - * permissions later. - */ - .set addr, 0 - .rept PTRS_PER_PMD - PTE addr, HV_PTE_READABLE | HV_PTE_WRITABLE - .set addr, addr + HPAGE_SIZE - .endr - .org temp_data_pmd + SIZEOF_PMD - END(temp_data_pmd) - - .align HV_PAGE_TABLE_ALIGN -ENTRY(temp_code_pmd) - /* - * We fill the MEM_SV_START pmd with huge pages with - * VA = PA + PAGE_OFFSET. We remap things with more precise access - * permissions later. - */ - .set addr, 0 - .rept PTRS_PER_PMD - PTE addr, HV_PTE_READABLE | HV_PTE_EXECUTABLE - .set addr, addr + HPAGE_SIZE - .endr - .org temp_code_pmd + SIZEOF_PMD - END(temp_code_pmd) - - /* - * Isolate swapper_pgprot to its own cache line, since each cpu - * starting up will read it using VA-is-PA and local homing. - * This would otherwise likely conflict with other data on the cache - * line, once we have set its permanent home in the page tables. - */ - __INITDATA - .align CHIP_L2_LINE_SIZE() -ENTRY(swapper_pgprot) - .quad HV_PTE_PRESENT | (HV_PTE_MODE_CACHE_NO_L3 << HV_PTE_INDEX_MODE) - .align CHIP_L2_LINE_SIZE() - END(swapper_pgprot) diff --git a/arch/tile/kernel/hvglue.S b/arch/tile/kernel/hvglue.S deleted file mode 100644 index 70c661448638..000000000000 --- a/arch/tile/kernel/hvglue.S +++ /dev/null @@ -1,76 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* Hypervisor call vector addresses; see */ -.macro gensym sym, val, size -.org \val -.global _\sym -.type _\sym,function -_\sym: -.size _\sym,\size -#ifndef CONFIG_TILE_HVGLUE_TRACE -.globl \sym -.set \sym,_\sym -#endif -.endm - -.section .hvglue,"x",@nobits -.align 8 -gensym hv_init, 0x20, 32 -gensym hv_install_context, 0x40, 32 -gensym hv_sysconf, 0x60, 32 -gensym hv_get_rtc, 0x80, 32 -gensym hv_set_rtc, 0xa0, 32 -gensym hv_flush_asid, 0xc0, 32 -gensym hv_flush_page, 0xe0, 32 -gensym hv_flush_pages, 0x100, 32 -gensym hv_restart, 0x120, 32 -gensym hv_halt, 0x140, 32 -gensym hv_power_off, 0x160, 32 -gensym hv_inquire_physical, 0x180, 32 -gensym hv_inquire_memory_controller, 0x1a0, 32 -gensym hv_inquire_virtual, 0x1c0, 32 -gensym hv_inquire_asid, 0x1e0, 32 -gensym hv_nanosleep, 0x200, 32 -gensym hv_console_read_if_ready, 0x220, 32 -gensym hv_console_write, 0x240, 32 -gensym hv_downcall_dispatch, 0x260, 32 -gensym hv_inquire_topology, 0x280, 32 -gensym hv_fs_findfile, 0x2a0, 32 -gensym hv_fs_fstat, 0x2c0, 32 -gensym hv_fs_pread, 0x2e0, 32 -gensym hv_physaddr_read64, 0x300, 32 -gensym hv_physaddr_write64, 0x320, 32 -gensym hv_get_command_line, 0x340, 32 -gensym hv_set_caching, 0x360, 32 -gensym hv_bzero_page, 0x380, 32 -gensym hv_register_message_state, 0x3a0, 32 -gensym hv_send_message, 0x3c0, 32 -gensym hv_receive_message, 0x3e0, 32 -gensym hv_inquire_context, 0x400, 32 -gensym hv_start_all_tiles, 0x420, 32 -gensym hv_dev_open, 0x440, 32 -gensym hv_dev_close, 0x460, 32 -gensym hv_dev_pread, 0x480, 32 -gensym hv_dev_pwrite, 0x4a0, 32 -gensym hv_dev_poll, 0x4c0, 32 -gensym hv_dev_poll_cancel, 0x4e0, 32 -gensym hv_dev_preada, 0x500, 32 -gensym hv_dev_pwritea, 0x520, 32 -gensym hv_flush_remote, 0x540, 32 -gensym hv_console_putc, 0x560, 32 -gensym hv_inquire_tiles, 0x580, 32 -gensym hv_confstr, 0x5a0, 32 -gensym hv_reexec, 0x5c0, 32 -gensym hv_set_command_line, 0x5e0, 32 -gensym hv_clear_intr, 0x600, 32 -gensym hv_enable_intr, 0x620, 32 -gensym hv_disable_intr, 0x640, 32 -gensym hv_raise_intr, 0x660, 32 -gensym hv_trigger_ipi, 0x680, 32 -gensym hv_store_mapping, 0x6a0, 32 -gensym hv_inquire_realpa, 0x6c0, 32 -gensym hv_flush_all, 0x6e0, 32 -gensym hv_get_ipi_pte, 0x700, 32 -gensym hv_set_pte_super_shift, 0x720, 32 -gensym hv_console_set_ipi, 0x7e0, 32 -gensym hv_send_nmi, 0x820, 32 -gensym hv_glue_internals, 0x820, 30688 diff --git a/arch/tile/kernel/hvglue_trace.c b/arch/tile/kernel/hvglue_trace.c deleted file mode 100644 index add0d71395c6..000000000000 --- a/arch/tile/kernel/hvglue_trace.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -/* - * Pull in the hypervisor header so we declare all the ABI functions - * with the underscore versions, then undef the names so that we can - * provide our own wrapper versions. - */ -#define hv_init _hv_init -#define hv_install_context _hv_install_context -#define hv_sysconf _hv_sysconf -#define hv_get_rtc _hv_get_rtc -#define hv_set_rtc _hv_set_rtc -#define hv_flush_asid _hv_flush_asid -#define hv_flush_page _hv_flush_page -#define hv_flush_pages _hv_flush_pages -#define hv_restart _hv_restart -#define hv_halt _hv_halt -#define hv_power_off _hv_power_off -#define hv_inquire_physical _hv_inquire_physical -#define hv_inquire_memory_controller _hv_inquire_memory_controller -#define hv_inquire_virtual _hv_inquire_virtual -#define hv_inquire_asid _hv_inquire_asid -#define hv_nanosleep _hv_nanosleep -#define hv_console_read_if_ready _hv_console_read_if_ready -#define hv_console_write _hv_console_write -#define hv_downcall_dispatch _hv_downcall_dispatch -#define hv_inquire_topology _hv_inquire_topology -#define hv_fs_findfile _hv_fs_findfile -#define hv_fs_fstat _hv_fs_fstat -#define hv_fs_pread _hv_fs_pread -#define hv_physaddr_read64 _hv_physaddr_read64 -#define hv_physaddr_write64 _hv_physaddr_write64 -#define hv_get_command_line _hv_get_command_line -#define hv_set_caching _hv_set_caching -#define hv_bzero_page _hv_bzero_page -#define hv_register_message_state _hv_register_message_state -#define hv_send_message _hv_send_message -#define hv_receive_message _hv_receive_message -#define hv_inquire_context _hv_inquire_context -#define hv_start_all_tiles _hv_start_all_tiles -#define hv_dev_open _hv_dev_open -#define hv_dev_close _hv_dev_close -#define hv_dev_pread _hv_dev_pread -#define hv_dev_pwrite _hv_dev_pwrite -#define hv_dev_poll _hv_dev_poll -#define hv_dev_poll_cancel _hv_dev_poll_cancel -#define hv_dev_preada _hv_dev_preada -#define hv_dev_pwritea _hv_dev_pwritea -#define hv_flush_remote _hv_flush_remote -#define hv_console_putc _hv_console_putc -#define hv_inquire_tiles _hv_inquire_tiles -#define hv_confstr _hv_confstr -#define hv_reexec _hv_reexec -#define hv_set_command_line _hv_set_command_line -#define hv_clear_intr _hv_clear_intr -#define hv_enable_intr _hv_enable_intr -#define hv_disable_intr _hv_disable_intr -#define hv_raise_intr _hv_raise_intr -#define hv_trigger_ipi _hv_trigger_ipi -#define hv_store_mapping _hv_store_mapping -#define hv_inquire_realpa _hv_inquire_realpa -#define hv_flush_all _hv_flush_all -#define hv_get_ipi_pte _hv_get_ipi_pte -#define hv_set_pte_super_shift _hv_set_pte_super_shift -#define hv_console_set_ipi _hv_console_set_ipi -#define hv_send_nmi _hv_send_nmi -#include -#undef hv_init -#undef hv_install_context -#undef hv_sysconf -#undef hv_get_rtc -#undef hv_set_rtc -#undef hv_flush_asid -#undef hv_flush_page -#undef hv_flush_pages -#undef hv_restart -#undef hv_halt -#undef hv_power_off -#undef hv_inquire_physical -#undef hv_inquire_memory_controller -#undef hv_inquire_virtual -#undef hv_inquire_asid -#undef hv_nanosleep -#undef hv_console_read_if_ready -#undef hv_console_write -#undef hv_downcall_dispatch -#undef hv_inquire_topology -#undef hv_fs_findfile -#undef hv_fs_fstat -#undef hv_fs_pread -#undef hv_physaddr_read64 -#undef hv_physaddr_write64 -#undef hv_get_command_line -#undef hv_set_caching -#undef hv_bzero_page -#undef hv_register_message_state -#undef hv_send_message -#undef hv_receive_message -#undef hv_inquire_context -#undef hv_start_all_tiles -#undef hv_dev_open -#undef hv_dev_close -#undef hv_dev_pread -#undef hv_dev_pwrite -#undef hv_dev_poll -#undef hv_dev_poll_cancel -#undef hv_dev_preada -#undef hv_dev_pwritea -#undef hv_flush_remote -#undef hv_console_putc -#undef hv_inquire_tiles -#undef hv_confstr -#undef hv_reexec -#undef hv_set_command_line -#undef hv_clear_intr -#undef hv_enable_intr -#undef hv_disable_intr -#undef hv_raise_intr -#undef hv_trigger_ipi -#undef hv_store_mapping -#undef hv_inquire_realpa -#undef hv_flush_all -#undef hv_get_ipi_pte -#undef hv_set_pte_super_shift -#undef hv_console_set_ipi -#undef hv_send_nmi - -/* - * Provide macros based on to provide a wrapper - * function that invokes the same function with an underscore prefix. - * We can't use the existing __SC_xxx macros because we need to - * support up to nine arguments rather than up to six, and also this - * way the file stands alone from possible changes in the - * implementation of . - */ -#define HV_WRAP0(type, name) \ - type name(void); \ - type name(void) \ - { \ - return _##name(); \ - } -#define __HV_DECL1(t1, a1) t1 a1 -#define __HV_DECL2(t2, a2, ...) t2 a2, __HV_DECL1(__VA_ARGS__) -#define __HV_DECL3(t3, a3, ...) t3 a3, __HV_DECL2(__VA_ARGS__) -#define __HV_DECL4(t4, a4, ...) t4 a4, __HV_DECL3(__VA_ARGS__) -#define __HV_DECL5(t5, a5, ...) t5 a5, __HV_DECL4(__VA_ARGS__) -#define __HV_DECL6(t6, a6, ...) t6 a6, __HV_DECL5(__VA_ARGS__) -#define __HV_DECL7(t7, a7, ...) t7 a7, __HV_DECL6(__VA_ARGS__) -#define __HV_DECL8(t8, a8, ...) t8 a8, __HV_DECL7(__VA_ARGS__) -#define __HV_DECL9(t9, a9, ...) t9 a9, __HV_DECL8(__VA_ARGS__) -#define __HV_PASS1(t1, a1) a1 -#define __HV_PASS2(t2, a2, ...) a2, __HV_PASS1(__VA_ARGS__) -#define __HV_PASS3(t3, a3, ...) a3, __HV_PASS2(__VA_ARGS__) -#define __HV_PASS4(t4, a4, ...) a4, __HV_PASS3(__VA_ARGS__) -#define __HV_PASS5(t5, a5, ...) a5, __HV_PASS4(__VA_ARGS__) -#define __HV_PASS6(t6, a6, ...) a6, __HV_PASS5(__VA_ARGS__) -#define __HV_PASS7(t7, a7, ...) a7, __HV_PASS6(__VA_ARGS__) -#define __HV_PASS8(t8, a8, ...) a8, __HV_PASS7(__VA_ARGS__) -#define __HV_PASS9(t9, a9, ...) a9, __HV_PASS8(__VA_ARGS__) -#define HV_WRAPx(x, type, name, ...) \ - type name(__HV_DECL##x(__VA_ARGS__)); \ - type name(__HV_DECL##x(__VA_ARGS__)) \ - { \ - return _##name(__HV_PASS##x(__VA_ARGS__)); \ - } -#define HV_WRAP1(type, name, ...) HV_WRAPx(1, type, name, __VA_ARGS__) -#define HV_WRAP2(type, name, ...) HV_WRAPx(2, type, name, __VA_ARGS__) -#define HV_WRAP3(type, name, ...) HV_WRAPx(3, type, name, __VA_ARGS__) -#define HV_WRAP4(type, name, ...) HV_WRAPx(4, type, name, __VA_ARGS__) -#define HV_WRAP5(type, name, ...) HV_WRAPx(5, type, name, __VA_ARGS__) -#define HV_WRAP6(type, name, ...) HV_WRAPx(6, type, name, __VA_ARGS__) -#define HV_WRAP7(type, name, ...) HV_WRAPx(7, type, name, __VA_ARGS__) -#define HV_WRAP8(type, name, ...) HV_WRAPx(8, type, name, __VA_ARGS__) -#define HV_WRAP9(type, name, ...) HV_WRAPx(9, type, name, __VA_ARGS__) - -/* List all the hypervisor API functions. */ -HV_WRAP4(void, hv_init, HV_VersionNumber, interface_version_number, - int, chip_num, int, chip_rev_num, int, client_pl) -HV_WRAP1(long, hv_sysconf, HV_SysconfQuery, query) -HV_WRAP3(int, hv_confstr, HV_ConfstrQuery, query, HV_VirtAddr, buf, int, len) -#if CHIP_HAS_IPI() -HV_WRAP3(int, hv_get_ipi_pte, HV_Coord, tile, int, pl, HV_PTE*, pte) -HV_WRAP3(int, hv_console_set_ipi, int, ipi, int, event, HV_Coord, coord); -#else -HV_WRAP1(void, hv_enable_intr, HV_IntrMask, enab_mask) -HV_WRAP1(void, hv_disable_intr, HV_IntrMask, disab_mask) -HV_WRAP1(void, hv_clear_intr, HV_IntrMask, clear_mask) -HV_WRAP1(void, hv_raise_intr, HV_IntrMask, raise_mask) -HV_WRAP2(HV_Errno, hv_trigger_ipi, HV_Coord, tile, int, interrupt) -#endif /* !CHIP_HAS_IPI() */ -HV_WRAP3(int, hv_store_mapping, HV_VirtAddr, va, unsigned int, len, - HV_PhysAddr, pa) -HV_WRAP2(HV_PhysAddr, hv_inquire_realpa, HV_PhysAddr, cpa, unsigned int, len) -HV_WRAP0(HV_RTCTime, hv_get_rtc) -HV_WRAP1(void, hv_set_rtc, HV_RTCTime, time) -HV_WRAP4(int, hv_install_context, HV_PhysAddr, page_table, HV_PTE, access, - HV_ASID, asid, __hv32, flags) -HV_WRAP2(int, hv_set_pte_super_shift, int, level, int, log2_count) -HV_WRAP0(HV_Context, hv_inquire_context) -HV_WRAP1(int, hv_flush_asid, HV_ASID, asid) -HV_WRAP2(int, hv_flush_page, HV_VirtAddr, address, HV_PageSize, page_size) -HV_WRAP3(int, hv_flush_pages, HV_VirtAddr, start, HV_PageSize, page_size, - unsigned long, size) -HV_WRAP1(int, hv_flush_all, int, preserve_global) -HV_WRAP2(void, hv_restart, HV_VirtAddr, cmd, HV_VirtAddr, args) -HV_WRAP0(void, hv_halt) -HV_WRAP0(void, hv_power_off) -HV_WRAP1(int, hv_reexec, HV_PhysAddr, entry) -HV_WRAP0(HV_Topology, hv_inquire_topology) -HV_WRAP3(HV_Errno, hv_inquire_tiles, HV_InqTileSet, set, HV_VirtAddr, cpumask, - int, length) -HV_WRAP1(HV_PhysAddrRange, hv_inquire_physical, int, idx) -HV_WRAP2(HV_MemoryControllerInfo, hv_inquire_memory_controller, HV_Coord, coord, - int, controller) -HV_WRAP1(HV_VirtAddrRange, hv_inquire_virtual, int, idx) -HV_WRAP1(HV_ASIDRange, hv_inquire_asid, int, idx) -HV_WRAP1(void, hv_nanosleep, int, nanosecs) -HV_WRAP0(int, hv_console_read_if_ready) -HV_WRAP1(void, hv_console_putc, int, byte) -HV_WRAP2(int, hv_console_write, HV_VirtAddr, bytes, int, len) -HV_WRAP0(void, hv_downcall_dispatch) -HV_WRAP1(int, hv_fs_findfile, HV_VirtAddr, filename) -HV_WRAP1(HV_FS_StatInfo, hv_fs_fstat, int, inode) -HV_WRAP4(int, hv_fs_pread, int, inode, HV_VirtAddr, buf, - int, length, int, offset) -HV_WRAP2(unsigned long long, hv_physaddr_read64, HV_PhysAddr, addr, - HV_PTE, access) -HV_WRAP3(void, hv_physaddr_write64, HV_PhysAddr, addr, HV_PTE, access, - unsigned long long, val) -HV_WRAP2(int, hv_get_command_line, HV_VirtAddr, buf, int, length) -HV_WRAP2(HV_Errno, hv_set_command_line, HV_VirtAddr, buf, int, length) -HV_WRAP1(void, hv_set_caching, unsigned long, bitmask) -HV_WRAP2(void, hv_bzero_page, HV_VirtAddr, va, unsigned int, size) -HV_WRAP1(HV_Errno, hv_register_message_state, HV_MsgState*, msgstate) -HV_WRAP4(int, hv_send_message, HV_Recipient *, recips, int, nrecip, - HV_VirtAddr, buf, int, buflen) -HV_WRAP3(HV_RcvMsgInfo, hv_receive_message, HV_MsgState, msgstate, - HV_VirtAddr, buf, int, buflen) -HV_WRAP0(void, hv_start_all_tiles) -HV_WRAP2(int, hv_dev_open, HV_VirtAddr, name, __hv32, flags) -HV_WRAP1(int, hv_dev_close, int, devhdl) -HV_WRAP5(int, hv_dev_pread, int, devhdl, __hv32, flags, HV_VirtAddr, va, - __hv32, len, __hv64, offset) -HV_WRAP5(int, hv_dev_pwrite, int, devhdl, __hv32, flags, HV_VirtAddr, va, - __hv32, len, __hv64, offset) -HV_WRAP3(int, hv_dev_poll, int, devhdl, __hv32, events, HV_IntArg, intarg) -HV_WRAP1(int, hv_dev_poll_cancel, int, devhdl) -HV_WRAP6(int, hv_dev_preada, int, devhdl, __hv32, flags, __hv32, sgl_len, - HV_SGL *, sglp, __hv64, offset, HV_IntArg, intarg) -HV_WRAP6(int, hv_dev_pwritea, int, devhdl, __hv32, flags, __hv32, sgl_len, - HV_SGL *, sglp, __hv64, offset, HV_IntArg, intarg) -HV_WRAP9(int, hv_flush_remote, HV_PhysAddr, cache_pa, - unsigned long, cache_control, unsigned long*, cache_cpumask, - HV_VirtAddr, tlb_va, unsigned long, tlb_length, - unsigned long, tlb_pgsize, unsigned long*, tlb_cpumask, - HV_Remote_ASID*, asids, int, asidcount) -HV_WRAP3(HV_NMI_Info, hv_send_nmi, HV_Coord, tile, unsigned long, info, - __hv64, flags) diff --git a/arch/tile/kernel/intvec_32.S b/arch/tile/kernel/intvec_32.S deleted file mode 100644 index 9ff75e3a318a..000000000000 --- a/arch/tile/kernel/intvec_32.S +++ /dev/null @@ -1,1906 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Linux interrupt vectors. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg) - -#define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR) - - .macro push_reg reg, ptr=sp, delta=-4 - { - sw \ptr, \reg - addli \ptr, \ptr, \delta - } - .endm - - .macro pop_reg reg, ptr=sp, delta=4 - { - lw \reg, \ptr - addli \ptr, \ptr, \delta - } - .endm - - .macro pop_reg_zero reg, zreg, ptr=sp, delta=4 - { - move \zreg, zero - lw \reg, \ptr - addi \ptr, \ptr, \delta - } - .endm - - .macro push_extra_callee_saves reg - PTREGS_PTR(\reg, PTREGS_OFFSET_REG(51)) - push_reg r51, \reg - push_reg r50, \reg - push_reg r49, \reg - push_reg r48, \reg - push_reg r47, \reg - push_reg r46, \reg - push_reg r45, \reg - push_reg r44, \reg - push_reg r43, \reg - push_reg r42, \reg - push_reg r41, \reg - push_reg r40, \reg - push_reg r39, \reg - push_reg r38, \reg - push_reg r37, \reg - push_reg r36, \reg - push_reg r35, \reg - push_reg r34, \reg, PTREGS_OFFSET_BASE - PTREGS_OFFSET_REG(34) - .endm - - .macro panic str - .pushsection .rodata, "a" -1: - .asciz "\str" - .popsection - { - moveli r0, lo16(1b) - } - { - auli r0, r0, ha16(1b) - jal panic - } - .endm - -#ifdef __COLLECT_LINKER_FEEDBACK__ - .pushsection .text.intvec_feedback,"ax" -intvec_feedback: - .popsection -#endif - - /* - * Default interrupt handler. - * - * vecnum is where we'll put this code. - * c_routine is the C routine we'll call. - * - * The C routine is passed two arguments: - * - A pointer to the pt_regs state. - * - The interrupt vector number. - * - * The "processing" argument specifies the code for processing - * the interrupt. Defaults to "handle_interrupt". - */ - .macro int_hand vecnum, vecname, c_routine, processing=handle_interrupt - .org (\vecnum << 8) -intvec_\vecname: - .ifc \vecnum, INT_SWINT_1 - blz TREG_SYSCALL_NR_NAME, sys_cmpxchg - .endif - - /* Temporarily save a register so we have somewhere to work. */ - - mtspr SPR_SYSTEM_SAVE_K_1, r0 - mfspr r0, SPR_EX_CONTEXT_K_1 - - /* The cmpxchg code clears sp to force us to reset it here on fault. */ - { - bz sp, 2f - andi r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ - } - - .ifc \vecnum, INT_DOUBLE_FAULT - /* - * For double-faults from user-space, fall through to the normal - * register save and stack setup path. Otherwise, it's the - * hypervisor giving us one last chance to dump diagnostics, and we - * branch to the kernel_double_fault routine to do so. - */ - bz r0, 1f - j _kernel_double_fault -1: - .else - /* - * If we're coming from user-space, then set sp to the top of - * the kernel stack. Otherwise, assume sp is already valid. - */ - { - bnz r0, 0f - move r0, sp - } - .endif - - .ifc \c_routine, do_page_fault - /* - * The page_fault handler may be downcalled directly by the - * hypervisor even when Linux is running and has ICS set. - * - * In this case the contents of EX_CONTEXT_K_1 reflect the - * previous fault and can't be relied on to choose whether or - * not to reinitialize the stack pointer. So we add a test - * to see whether SYSTEM_SAVE_K_2 has the high bit set, - * and if so we don't reinitialize sp, since we must be coming - * from Linux. (In fact the precise case is !(val & ~1), - * but any Linux PC has to have the high bit set.) - * - * Note that the hypervisor *always* sets SYSTEM_SAVE_K_2 for - * any path that turns into a downcall to one of our TLB handlers. - */ - mfspr r0, SPR_SYSTEM_SAVE_K_2 - { - blz r0, 0f /* high bit in S_S_1_2 is for a PC to use */ - move r0, sp - } - .endif - -2: - /* - * SYSTEM_SAVE_K_0 holds the cpu number in the low bits, and - * the current stack top in the higher bits. So we recover - * our stack top by just masking off the low bits, then - * point sp at the top aligned address on the actual stack page. - */ - mfspr r0, SPR_SYSTEM_SAVE_K_0 - mm r0, r0, zero, LOG2_NR_CPU_IDS, 31 - -0: - /* - * Align the stack mod 64 so we can properly predict what - * cache lines we need to write-hint to reduce memory fetch - * latency as we enter the kernel. The layout of memory is - * as follows, with cache line 0 at the lowest VA, and cache - * line 4 just below the r0 value this "andi" computes. - * Note that we never write to cache line 4, and we skip - * cache line 1 for syscalls. - * - * cache line 4: ptregs padding (two words) - * cache line 3: r46...lr, pc, ex1, faultnum, orig_r0, flags, pad - * cache line 2: r30...r45 - * cache line 1: r14...r29 - * cache line 0: 2 x frame, r0..r13 - */ -#if STACK_TOP_DELTA != 64 -#error STACK_TOP_DELTA must be 64 for assumptions here and in task_pt_regs() -#endif - andi r0, r0, -64 - - /* - * Push the first four registers on the stack, so that we can set - * them to vector-unique values before we jump to the common code. - * - * Registers are pushed on the stack as a struct pt_regs, - * with the sp initially just above the struct, and when we're - * done, sp points to the base of the struct, minus - * C_ABI_SAVE_AREA_SIZE, so we can directly jal to C code. - * - * This routine saves just the first four registers, plus the - * stack context so we can do proper backtracing right away, - * and defers to handle_interrupt to save the rest. - * The backtracer needs pc, ex1, lr, sp, r52, and faultnum. - */ - addli r0, r0, PTREGS_OFFSET_LR - (PTREGS_SIZE + KSTK_PTREGS_GAP) - wh64 r0 /* cache line 3 */ - { - sw r0, lr - addli r0, r0, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR - } - { - sw r0, sp - addli sp, r0, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_SP - } - { - sw sp, r52 - addli sp, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(52) - } - wh64 sp /* cache line 0 */ - { - sw sp, r1 - addli sp, sp, PTREGS_OFFSET_REG(2) - PTREGS_OFFSET_REG(1) - } - { - sw sp, r2 - addli sp, sp, PTREGS_OFFSET_REG(3) - PTREGS_OFFSET_REG(2) - } - { - sw sp, r3 - addli sp, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(3) - } - mfspr r0, SPR_EX_CONTEXT_K_0 - .ifc \processing,handle_syscall - /* - * Bump the saved PC by one bundle so that when we return, we won't - * execute the same swint instruction again. We need to do this while - * we're in the critical section. - */ - addi r0, r0, 8 - .endif - { - sw sp, r0 - addli sp, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC - } - mfspr r0, SPR_EX_CONTEXT_K_1 - { - sw sp, r0 - addi sp, sp, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1 - /* - * Use r0 for syscalls so it's a temporary; use r1 for interrupts - * so that it gets passed through unchanged to the handler routine. - * Note that the .if conditional confusingly spans bundles. - */ - .ifc \processing,handle_syscall - movei r0, \vecnum - } - { - sw sp, r0 - .else - movei r1, \vecnum - } - { - sw sp, r1 - .endif - addli sp, sp, PTREGS_OFFSET_REG(0) - PTREGS_OFFSET_FAULTNUM - } - mfspr r0, SPR_SYSTEM_SAVE_K_1 /* Original r0 */ - { - sw sp, r0 - addi sp, sp, -PTREGS_OFFSET_REG(0) - 4 - } - { - sw sp, zero /* write zero into "Next SP" frame pointer */ - addi sp, sp, -4 /* leave SP pointing at bottom of frame */ - } - .ifc \processing,handle_syscall - j handle_syscall - .else - /* - * Capture per-interrupt SPR context to registers. - * We overload the meaning of r3 on this path such that if its bit 31 - * is set, we have to mask all interrupts including NMIs before - * clearing the interrupt critical section bit. - * See discussion below at "finish_interrupt_save". - */ - .ifc \c_routine, do_page_fault - mfspr r2, SPR_SYSTEM_SAVE_K_3 /* address of page fault */ - mfspr r3, SPR_SYSTEM_SAVE_K_2 /* info about page fault */ - .else - .ifc \vecnum, INT_DOUBLE_FAULT - { - mfspr r2, SPR_SYSTEM_SAVE_K_2 /* double fault info from HV */ - movei r3, 0 - } - .else - .ifc \c_routine, do_trap - { - mfspr r2, GPV_REASON - movei r3, 0 - } - .else - .ifc \c_routine, handle_perf_interrupt - { - mfspr r2, PERF_COUNT_STS - movei r3, -1 /* not used, but set for consistency */ - } - .else - .ifc \c_routine, handle_perf_interrupt - { - mfspr r2, AUX_PERF_COUNT_STS - movei r3, -1 /* not used, but set for consistency */ - } - .else - movei r3, 0 - .endif - .endif - .endif - .endif - .endif - /* Put function pointer in r0 */ - moveli r0, lo16(\c_routine) - { - auli r0, r0, ha16(\c_routine) - j \processing - } - .endif - ENDPROC(intvec_\vecname) - -#ifdef __COLLECT_LINKER_FEEDBACK__ - .pushsection .text.intvec_feedback,"ax" - .org (\vecnum << 5) - FEEDBACK_ENTER_EXPLICIT(intvec_\vecname, .intrpt, 1 << 8) - jrp lr - .popsection -#endif - - .endm - - - /* - * Save the rest of the registers that we didn't save in the actual - * vector itself. We can't use r0-r10 inclusive here. - */ - .macro finish_interrupt_save, function - - /* If it's a syscall, save a proper orig_r0, otherwise just zero. */ - PTREGS_PTR(r52, PTREGS_OFFSET_ORIG_R0) - { - .ifc \function,handle_syscall - sw r52, r0 - .else - sw r52, zero - .endif - PTREGS_PTR(r52, PTREGS_OFFSET_TP) - } - - /* - * For ordinary syscalls, we save neither caller- nor callee- - * save registers, since the syscall invoker doesn't expect the - * caller-saves to be saved, and the called kernel functions will - * take care of saving the callee-saves for us. - * - * For interrupts we save just the caller-save registers. Saving - * them is required (since the "caller" can't save them). Again, - * the called kernel functions will restore the callee-save - * registers for us appropriately. - * - * On return, we normally restore nothing special for syscalls, - * and just the caller-save registers for interrupts. - * - * However, there are some important caveats to all this: - * - * - We always save a few callee-save registers to give us - * some scratchpad registers to carry across function calls. - * - * - fork/vfork/etc require us to save all the callee-save - * registers, which we do in PTREGS_SYSCALL_ALL_REGS, below. - * - * - We always save r0..r5 and r10 for syscalls, since we need - * to reload them a bit later for the actual kernel call, and - * since we might need them for -ERESTARTNOINTR, etc. - * - * - Before invoking a signal handler, we save the unsaved - * callee-save registers so they are visible to the - * signal handler or any ptracer. - * - * - If the unsaved callee-save registers are modified, we set - * a bit in pt_regs so we know to reload them from pt_regs - * and not just rely on the kernel function unwinding. - * (Done for ptrace register writes and SA_SIGINFO handler.) - */ - { - sw r52, tp - PTREGS_PTR(r52, PTREGS_OFFSET_REG(33)) - } - wh64 r52 /* cache line 2 */ - push_reg r33, r52 - push_reg r32, r52 - push_reg r31, r52 - .ifc \function,handle_syscall - push_reg r30, r52, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(30) - push_reg TREG_SYSCALL_NR_NAME, r52, \ - PTREGS_OFFSET_REG(5) - PTREGS_OFFSET_SYSCALL - .else - - push_reg r30, r52, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(30) - wh64 r52 /* cache line 1 */ - push_reg r29, r52 - push_reg r28, r52 - push_reg r27, r52 - push_reg r26, r52 - push_reg r25, r52 - push_reg r24, r52 - push_reg r23, r52 - push_reg r22, r52 - push_reg r21, r52 - push_reg r20, r52 - push_reg r19, r52 - push_reg r18, r52 - push_reg r17, r52 - push_reg r16, r52 - push_reg r15, r52 - push_reg r14, r52 - push_reg r13, r52 - push_reg r12, r52 - push_reg r11, r52 - push_reg r10, r52 - push_reg r9, r52 - push_reg r8, r52 - push_reg r7, r52 - push_reg r6, r52 - - .endif - - push_reg r5, r52 - sw r52, r4 - - /* Load tp with our per-cpu offset. */ -#ifdef CONFIG_SMP - { - mfspr r20, SPR_SYSTEM_SAVE_K_0 - moveli r21, lo16(__per_cpu_offset) - } - { - auli r21, r21, ha16(__per_cpu_offset) - mm r20, r20, zero, 0, LOG2_NR_CPU_IDS-1 - } - s2a r20, r20, r21 - lw tp, r20 -#else - move tp, zero -#endif - - /* - * If we will be returning to the kernel, we will need to - * reset the interrupt masks to the state they had before. - * Set DISABLE_IRQ in flags iff we came from PL1 with irqs disabled. - * We load flags in r32 here so we can jump to .Lrestore_regs - * directly after do_page_fault_ics() if necessary. - */ - mfspr r32, SPR_EX_CONTEXT_K_1 - { - andi r32, r32, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ - PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS) - } - bzt r32, 1f /* zero if from user space */ - IRQS_DISABLED(r32) /* zero if irqs enabled */ -#if PT_FLAGS_DISABLE_IRQ != 1 -# error Value of IRQS_DISABLED used to set PT_FLAGS_DISABLE_IRQ; fix -#endif -1: - .ifnc \function,handle_syscall - /* Record the fact that we saved the caller-save registers above. */ - ori r32, r32, PT_FLAGS_CALLER_SAVES - .endif - sw r21, r32 - -#ifdef __COLLECT_LINKER_FEEDBACK__ - /* - * Notify the feedback routines that we were in the - * appropriate fixed interrupt vector area. Note that we - * still have ICS set at this point, so we can't invoke any - * atomic operations or we will panic. The feedback - * routines internally preserve r0..r10 and r30 up. - */ - .ifnc \function,handle_syscall - shli r20, r1, 5 - .else - moveli r20, INT_SWINT_1 << 5 - .endif - addli r20, r20, lo16(intvec_feedback) - auli r20, r20, ha16(intvec_feedback) - jalr r20 - - /* And now notify the feedback routines that we are here. */ - FEEDBACK_ENTER(\function) -#endif - - /* - * we've captured enough state to the stack (including in - * particular our EX_CONTEXT state) that we can now release - * the interrupt critical section and replace it with our - * standard "interrupts disabled" mask value. This allows - * synchronous interrupts (and profile interrupts) to punch - * through from this point onwards. - * - * If bit 31 of r3 is set during a non-NMI interrupt, we know we - * are on the path where the hypervisor has punched through our - * ICS with a page fault, so we call out to do_page_fault_ics() - * to figure out what to do with it. If the fault was in - * an atomic op, we unlock the atomic lock, adjust the - * saved register state a little, and return "zero" in r4, - * falling through into the normal page-fault interrupt code. - * If the fault was in a kernel-space atomic operation, then - * do_page_fault_ics() resolves it itself, returns "one" in r4, - * and as a result goes directly to restoring registers and iret, - * without trying to adjust the interrupt masks at all. - * The do_page_fault_ics() API involves passing and returning - * a five-word struct (in registers) to avoid writing the - * save and restore code here. - */ - .ifc \function,handle_nmi - IRQ_DISABLE_ALL(r20) - .else - .ifnc \function,handle_syscall - bgezt r3, 1f - { - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - jal do_page_fault_ics - } - FEEDBACK_REENTER(\function) - bzt r4, 1f - j .Lrestore_regs -1: - .endif - IRQ_DISABLE(r20, r21) - .endif - mtspr INTERRUPT_CRITICAL_SECTION, zero - - /* - * Prepare the first 256 stack bytes to be rapidly accessible - * without having to fetch the background data. We don't really - * know how far to write-hint, but kernel stacks generally - * aren't that big, and write-hinting here does take some time. - */ - addi r52, sp, -64 - { - wh64 r52 - addi r52, r52, -64 - } - { - wh64 r52 - addi r52, r52, -64 - } - { - wh64 r52 - addi r52, r52, -64 - } - wh64 r52 - -#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING) - .ifnc \function,handle_nmi - /* - * We finally have enough state set up to notify the irq - * tracing code that irqs were disabled on entry to the handler. - * The TRACE_IRQS_OFF call clobbers registers r0-r29. - * For syscalls, we already have the register state saved away - * on the stack, so we don't bother to do any register saves here, - * and later we pop the registers back off the kernel stack. - * For interrupt handlers, save r0-r3 in callee-saved registers. - */ - .ifnc \function,handle_syscall - { move r30, r0; move r31, r1 } - { move r32, r2; move r33, r3 } - .endif - TRACE_IRQS_OFF -#ifdef CONFIG_CONTEXT_TRACKING - jal context_tracking_user_exit -#endif - .ifnc \function,handle_syscall - { move r0, r30; move r1, r31 } - { move r2, r32; move r3, r33 } - .endif - .endif -#endif - - .endm - - .macro check_single_stepping, kind, not_single_stepping - /* - * Check for single stepping in user-level priv - * kind can be "normal", "ill", or "syscall" - * At end, if fall-thru - * r29: thread_info->step_state - * r28: &pt_regs->pc - * r27: pt_regs->pc - * r26: thread_info->step_state->buffer - */ - - /* Check for single stepping */ - GET_THREAD_INFO(r29) - { - /* Get pointer to field holding step state */ - addi r29, r29, THREAD_INFO_STEP_STATE_OFFSET - - /* Get pointer to EX1 in register state */ - PTREGS_PTR(r27, PTREGS_OFFSET_EX1) - } - { - /* Get pointer to field holding PC */ - PTREGS_PTR(r28, PTREGS_OFFSET_PC) - - /* Load the pointer to the step state */ - lw r29, r29 - } - /* Load EX1 */ - lw r27, r27 - { - /* Points to flags */ - addi r23, r29, SINGLESTEP_STATE_FLAGS_OFFSET - - /* No single stepping if there is no step state structure */ - bzt r29, \not_single_stepping - } - { - /* mask off ICS and any other high bits */ - andi r27, r27, SPR_EX_CONTEXT_1_1__PL_MASK - - /* Load pointer to single step instruction buffer */ - lw r26, r29 - } - /* Check priv state */ - bnz r27, \not_single_stepping - - /* Get flags */ - lw r22, r23 - { - /* Branch if single-step mode not enabled */ - bbnst r22, \not_single_stepping - - /* Clear enabled flag */ - andi r22, r22, ~SINGLESTEP_STATE_MASK_IS_ENABLED - } - .ifc \kind,normal - { - /* Load PC */ - lw r27, r28 - - /* Point to the entry containing the original PC */ - addi r24, r29, SINGLESTEP_STATE_ORIG_PC_OFFSET - } - { - /* Disable single stepping flag */ - sw r23, r22 - } - { - /* Get the original pc */ - lw r24, r24 - - /* See if the PC is at the start of the single step buffer */ - seq r25, r26, r27 - } - /* - * NOTE: it is really expected that the PC be in the single step buffer - * at this point - */ - bzt r25, \not_single_stepping - - /* Restore the original PC */ - sw r28, r24 - .else - .ifc \kind,syscall - { - /* Load PC */ - lw r27, r28 - - /* Point to the entry containing the next PC */ - addi r24, r29, SINGLESTEP_STATE_NEXT_PC_OFFSET - } - { - /* Increment the stopped PC by the bundle size */ - addi r26, r26, 8 - - /* Disable single stepping flag */ - sw r23, r22 - } - { - /* Get the next pc */ - lw r24, r24 - - /* - * See if the PC is one bundle past the start of the - * single step buffer - */ - seq r25, r26, r27 - } - { - /* - * NOTE: it is really expected that the PC be in the - * single step buffer at this point - */ - bzt r25, \not_single_stepping - } - /* Set to the next PC */ - sw r28, r24 - .else - { - /* Point to 3rd bundle in buffer */ - addi r25, r26, 16 - - /* Load PC */ - lw r27, r28 - } - { - /* Disable single stepping flag */ - sw r23, r22 - - /* See if the PC is in the single step buffer */ - slte_u r24, r26, r27 - } - { - slte_u r25, r27, r25 - - /* - * NOTE: it is really expected that the PC be in the - * single step buffer at this point - */ - bzt r24, \not_single_stepping - } - bzt r25, \not_single_stepping - .endif - .endif - .endm - - /* - * Redispatch a downcall. - */ - .macro dc_dispatch vecnum, vecname - .org (\vecnum << 8) -intvec_\vecname: - j _hv_downcall_dispatch - ENDPROC(intvec_\vecname) - .endm - - /* - * Common code for most interrupts. The C function we're eventually - * going to is in r0, and the faultnum is in r1; the original - * values for those registers are on the stack. - */ - .pushsection .text.handle_interrupt,"ax" -handle_interrupt: - finish_interrupt_save handle_interrupt - - /* - * Check for if we are single stepping in user level. If so, then - * we need to restore the PC. - */ - - check_single_stepping normal, .Ldispatch_interrupt -.Ldispatch_interrupt: - - /* Jump to the C routine; it should enable irqs as soon as possible. */ - { - jalr r0 - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - } - FEEDBACK_REENTER(handle_interrupt) - { - movei r30, 0 /* not an NMI */ - j interrupt_return - } - STD_ENDPROC(handle_interrupt) - -/* - * This routine takes a boolean in r30 indicating if this is an NMI. - * If so, we also expect a boolean in r31 indicating whether to - * re-enable the oprofile interrupts. - * - * Note that .Lresume_userspace is jumped to directly in several - * places, and we need to make sure r30 is set correctly in those - * callers as well. - */ -STD_ENTRY(interrupt_return) - /* If we're resuming to kernel space, don't check thread flags. */ - { - bnz r30, .Lrestore_all /* NMIs don't special-case user-space */ - PTREGS_PTR(r29, PTREGS_OFFSET_EX1) - } - lw r29, r29 - andi r29, r29, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ - bzt r29, .Lresume_userspace - -#ifdef CONFIG_PREEMPT - /* Returning to kernel space. Check if we need preemption. */ - GET_THREAD_INFO(r29) - addli r28, r29, THREAD_INFO_FLAGS_OFFSET - { - lw r28, r28 - addli r29, r29, THREAD_INFO_PREEMPT_COUNT_OFFSET - } - { - andi r28, r28, _TIF_NEED_RESCHED - lw r29, r29 - } - bzt r28, 1f - bnz r29, 1f - /* Disable interrupts explicitly for preemption. */ - IRQ_DISABLE(r20,r21) - TRACE_IRQS_OFF - jal preempt_schedule_irq - FEEDBACK_REENTER(interrupt_return) -1: -#endif - - /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */ - { - PTREGS_PTR(r29, PTREGS_OFFSET_PC) - moveli r27, lo16(_cpu_idle_nap) - } - { - lw r28, r29 - auli r27, r27, ha16(_cpu_idle_nap) - } - { - seq r27, r27, r28 - } - { - bbns r27, .Lrestore_all - addi r28, r28, 8 - } - sw r29, r28 - j .Lrestore_all - -.Lresume_userspace: - FEEDBACK_REENTER(interrupt_return) - - /* - * Disable interrupts so as to make sure we don't - * miss an interrupt that sets any of the thread flags (like - * need_resched or sigpending) between sampling and the iret. - * Routines like schedule() or do_signal() may re-enable - * interrupts before returning. - */ - IRQ_DISABLE(r20, r21) - TRACE_IRQS_OFF /* Note: clobbers registers r0-r29 */ - - /* - * See if there are any work items (including single-shot items) - * to do. If so, save the callee-save registers to pt_regs - * and then dispatch to C code. - */ - GET_THREAD_INFO(r21) - { - addi r22, r21, THREAD_INFO_FLAGS_OFFSET - moveli r20, lo16(_TIF_ALLWORK_MASK) - } - { - lw r22, r22 - auli r20, r20, ha16(_TIF_ALLWORK_MASK) - } - and r1, r22, r20 - { - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - bzt r1, .Lrestore_all - } - push_extra_callee_saves r0 - jal prepare_exit_to_usermode - - /* - * In the NMI case we - * omit the call to single_process_check_nohz, which normally checks - * to see if we should start or stop the scheduler tick, because - * we can't call arbitrary Linux code from an NMI context. - * We always call the homecache TLB deferral code to re-trigger - * the deferral mechanism. - * - * The other chunk of responsibility this code has is to reset the - * interrupt masks appropriately to reset irqs and NMIs. We have - * to call TRACE_IRQS_OFF and TRACE_IRQS_ON to support all the - * lockdep-type stuff, but we can't set ICS until afterwards, since - * ICS can only be used in very tight chunks of code to avoid - * tripping over various assertions that it is off. - * - * (There is what looks like a window of vulnerability here since - * we might take a profile interrupt between the two SPR writes - * that set the mask, but since we write the low SPR word first, - * and our interrupt entry code checks the low SPR word, any - * profile interrupt will actually disable interrupts in both SPRs - * before returning, which is OK.) - */ -.Lrestore_all: - PTREGS_PTR(r0, PTREGS_OFFSET_EX1) - { - lw r0, r0 - PTREGS_PTR(r32, PTREGS_OFFSET_FLAGS) - } - { - andi r0, r0, SPR_EX_CONTEXT_1_1__PL_MASK - lw r32, r32 - } - bnz r0, 1f - j 2f -#if PT_FLAGS_DISABLE_IRQ != 1 -# error Assuming PT_FLAGS_DISABLE_IRQ == 1 so we can use bbnst below -#endif -1: bbnst r32, 2f - IRQ_DISABLE(r20,r21) - TRACE_IRQS_OFF - movei r0, 1 - mtspr INTERRUPT_CRITICAL_SECTION, r0 - bzt r30, .Lrestore_regs - j 3f -2: TRACE_IRQS_ON - movei r0, 1 - mtspr INTERRUPT_CRITICAL_SECTION, r0 - IRQ_ENABLE(r20, r21) - bzt r30, .Lrestore_regs -3: - - /* We are relying on INT_PERF_COUNT at 33, and AUX_PERF_COUNT at 48 */ - { - moveli r0, lo16(1 << (INT_PERF_COUNT - 32)) - bz r31, .Lrestore_regs - } - auli r0, r0, ha16(1 << (INT_AUX_PERF_COUNT - 32)) - mtspr SPR_INTERRUPT_MASK_RESET_K_1, r0 - - /* - * We now commit to returning from this interrupt, since we will be - * doing things like setting EX_CONTEXT SPRs and unwinding the stack - * frame. No calls should be made to any other code after this point. - * This code should only be entered with ICS set. - * r32 must still be set to ptregs.flags. - * We launch loads to each cache line separately first, so we can - * get some parallelism out of the memory subsystem. - * We start zeroing caller-saved registers throughout, since - * that will save some cycles if this turns out to be a syscall. - */ -.Lrestore_regs: - FEEDBACK_REENTER(interrupt_return) /* called from elsewhere */ - - /* - * Rotate so we have one high bit and one low bit to test. - * - low bit says whether to restore all the callee-saved registers, - * or just r30-r33, and r52 up. - * - high bit (i.e. sign bit) says whether to restore all the - * caller-saved registers, or just r0. - */ -#if PT_FLAGS_CALLER_SAVES != 2 || PT_FLAGS_RESTORE_REGS != 4 -# error Rotate trick does not work :-) -#endif - { - rli r20, r32, 30 - PTREGS_PTR(sp, PTREGS_OFFSET_REG(0)) - } - - /* - * Load cache lines 0, 2, and 3 in that order, then use - * the last loaded value, which makes it likely that the other - * cache lines have also loaded, at which point we should be - * able to safely read all the remaining words on those cache - * lines without waiting for the memory subsystem. - */ - pop_reg_zero r0, r28, sp, PTREGS_OFFSET_REG(30) - PTREGS_OFFSET_REG(0) - pop_reg_zero r30, r2, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(30) - pop_reg_zero r21, r3, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC - pop_reg_zero lr, r4, sp, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_EX1 - { - mtspr SPR_EX_CONTEXT_K_0, r21 - move r5, zero - } - { - mtspr SPR_EX_CONTEXT_K_1, lr - andi lr, lr, SPR_EX_CONTEXT_1_1__PL_MASK /* mask off ICS */ - } - - /* Restore callee-saveds that we actually use. */ - pop_reg_zero r52, r6, sp, PTREGS_OFFSET_REG(31) - PTREGS_OFFSET_REG(52) - pop_reg_zero r31, r7 - pop_reg_zero r32, r8 - pop_reg_zero r33, r9, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(33) - - /* - * If we modified other callee-saveds, restore them now. - * This is rare, but could be via ptrace or signal handler. - */ - { - move r10, zero - bbs r20, .Lrestore_callees - } -.Lcontinue_restore_regs: - - /* Check if we're returning from a syscall. */ - { - move r11, zero - blzt r20, 1f /* no, so go restore callee-save registers */ - } - - /* - * Check if we're returning to userspace. - * Note that if we're not, we don't worry about zeroing everything. - */ - { - addli sp, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(29) - bnz lr, .Lkernel_return - } - - /* - * On return from syscall, we've restored r0 from pt_regs, but we - * clear the remainder of the caller-saved registers. We could - * restore the syscall arguments, but there's not much point, - * and it ensures user programs aren't trying to use the - * caller-saves if we clear them, as well as avoiding leaking - * kernel pointers into userspace. - */ - pop_reg_zero lr, r12, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR - pop_reg_zero tp, r13, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP - { - lw sp, sp - move r14, zero - move r15, zero - } - { move r16, zero; move r17, zero } - { move r18, zero; move r19, zero } - { move r20, zero; move r21, zero } - { move r22, zero; move r23, zero } - { move r24, zero; move r25, zero } - { move r26, zero; move r27, zero } - - /* Set r1 to errno if we are returning an error, otherwise zero. */ - { - moveli r29, 4096 - sub r1, zero, r0 - } - slt_u r29, r1, r29 - { - mnz r1, r29, r1 - move r29, zero - } - iret - - /* - * Not a syscall, so restore caller-saved registers. - * First kick off a load for cache line 1, which we're touching - * for the first time here. - */ - .align 64 -1: pop_reg r29, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(29) - pop_reg r1 - pop_reg r2 - pop_reg r3 - pop_reg r4 - pop_reg r5 - pop_reg r6 - pop_reg r7 - pop_reg r8 - pop_reg r9 - pop_reg r10 - pop_reg r11 - pop_reg r12 - pop_reg r13 - pop_reg r14 - pop_reg r15 - pop_reg r16 - pop_reg r17 - pop_reg r18 - pop_reg r19 - pop_reg r20 - pop_reg r21 - pop_reg r22 - pop_reg r23 - pop_reg r24 - pop_reg r25 - pop_reg r26 - pop_reg r27 - pop_reg r28, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(28) - /* r29 already restored above */ - bnz lr, .Lkernel_return - pop_reg lr, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR - pop_reg tp, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP - lw sp, sp - iret - - /* - * We can't restore tp when in kernel mode, since a thread might - * have migrated from another cpu and brought a stale tp value. - */ -.Lkernel_return: - pop_reg lr, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR - lw sp, sp - iret - - /* Restore callee-saved registers from r34 to r51. */ -.Lrestore_callees: - addli sp, sp, PTREGS_OFFSET_REG(34) - PTREGS_OFFSET_REG(29) - pop_reg r34 - pop_reg r35 - pop_reg r36 - pop_reg r37 - pop_reg r38 - pop_reg r39 - pop_reg r40 - pop_reg r41 - pop_reg r42 - pop_reg r43 - pop_reg r44 - pop_reg r45 - pop_reg r46 - pop_reg r47 - pop_reg r48 - pop_reg r49 - pop_reg r50 - pop_reg r51, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(51) - j .Lcontinue_restore_regs - STD_ENDPROC(interrupt_return) - - /* - * Some interrupts don't check for single stepping - */ - .pushsection .text.handle_interrupt_no_single_step,"ax" -handle_interrupt_no_single_step: - finish_interrupt_save handle_interrupt_no_single_step - { - jalr r0 - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - } - FEEDBACK_REENTER(handle_interrupt_no_single_step) - { - movei r30, 0 /* not an NMI */ - j interrupt_return - } - STD_ENDPROC(handle_interrupt_no_single_step) - - /* - * "NMI" interrupts mask ALL interrupts before calling the - * handler, and don't check thread flags, etc., on the way - * back out. In general, the only things we do here for NMIs - * are the register save/restore, fixing the PC if we were - * doing single step, and the dataplane kernel-TLB management. - * We don't (for example) deal with start/stop of the sched tick. - */ - .pushsection .text.handle_nmi,"ax" -handle_nmi: - finish_interrupt_save handle_nmi - check_single_stepping normal, .Ldispatch_nmi -.Ldispatch_nmi: - { - jalr r0 - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - } - FEEDBACK_REENTER(handle_nmi) - { - movei r30, 1 - seq r31, r0, zero - } - j interrupt_return - STD_ENDPROC(handle_nmi) - - /* - * Parallel code for syscalls to handle_interrupt. - */ - .pushsection .text.handle_syscall,"ax" -handle_syscall: - finish_interrupt_save handle_syscall - - /* - * Check for if we are single stepping in user level. If so, then - * we need to restore the PC. - */ - check_single_stepping syscall, .Ldispatch_syscall -.Ldispatch_syscall: - - /* Enable irqs. */ - TRACE_IRQS_ON - IRQ_ENABLE(r20, r21) - - /* Bump the counter for syscalls made on this tile. */ - moveli r20, lo16(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET) - auli r20, r20, ha16(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET) - add r20, r20, tp - lw r21, r20 - addi r21, r21, 1 - { - sw r20, r21 - GET_THREAD_INFO(r31) - } - - /* Trace syscalls, if requested. */ - addi r31, r31, THREAD_INFO_FLAGS_OFFSET - lw r30, r31 - andi r30, r30, _TIF_SYSCALL_TRACE - bzt r30, .Lrestore_syscall_regs - { - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - jal do_syscall_trace_enter - } - FEEDBACK_REENTER(handle_syscall) - blz r0, .Lsyscall_sigreturn_skip - - /* - * We always reload our registers from the stack at this - * point. They might be valid, if we didn't build with - * TRACE_IRQFLAGS, and this isn't a dataplane tile, and we're not - * doing syscall tracing, but there are enough cases now that it - * seems simplest just to do the reload unconditionally. - */ -.Lrestore_syscall_regs: - PTREGS_PTR(r11, PTREGS_OFFSET_REG(0)) - pop_reg r0, r11 - pop_reg r1, r11 - pop_reg r2, r11 - pop_reg r3, r11 - pop_reg r4, r11 - pop_reg r5, r11, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(5) - pop_reg TREG_SYSCALL_NR_NAME, r11 - - /* Ensure that the syscall number is within the legal range. */ - moveli r21, __NR_syscalls - { - slt_u r21, TREG_SYSCALL_NR_NAME, r21 - moveli r20, lo16(sys_call_table) - } - { - bbns r21, .Linvalid_syscall - auli r20, r20, ha16(sys_call_table) - } - s2a r20, TREG_SYSCALL_NR_NAME, r20 - lw r20, r20 - - /* Jump to syscall handler. */ - jalr r20 -.Lhandle_syscall_link: /* value of "lr" after "jalr r20" above */ - - /* - * Write our r0 onto the stack so it gets restored instead - * of whatever the user had there before. - */ - PTREGS_PTR(r29, PTREGS_OFFSET_REG(0)) - sw r29, r0 - -.Lsyscall_sigreturn_skip: - FEEDBACK_REENTER(handle_syscall) - - /* Do syscall trace again, if requested. */ - lw r30, r31 - andi r30, r30, _TIF_SYSCALL_TRACE - bzt r30, 1f - { - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - jal do_syscall_trace_exit - } - FEEDBACK_REENTER(handle_syscall) -1: { - movei r30, 0 /* not an NMI */ - j .Lresume_userspace /* jump into middle of interrupt_return */ - } - -.Linvalid_syscall: - /* Report an invalid syscall back to the user program */ - { - PTREGS_PTR(r29, PTREGS_OFFSET_REG(0)) - movei r28, -ENOSYS - } - sw r29, r28 - { - movei r30, 0 /* not an NMI */ - j .Lresume_userspace /* jump into middle of interrupt_return */ - } - STD_ENDPROC(handle_syscall) - - /* Return the address for oprofile to suppress in backtraces. */ -STD_ENTRY_SECTION(handle_syscall_link_address, .text.handle_syscall) - lnk r0 - { - addli r0, r0, .Lhandle_syscall_link - . - jrp lr - } - STD_ENDPROC(handle_syscall_link_address) - -STD_ENTRY(ret_from_fork) - jal sim_notify_fork - jal schedule_tail - FEEDBACK_REENTER(ret_from_fork) - { - movei r30, 0 /* not an NMI */ - j .Lresume_userspace /* jump into middle of interrupt_return */ - } - STD_ENDPROC(ret_from_fork) - -STD_ENTRY(ret_from_kernel_thread) - jal sim_notify_fork - jal schedule_tail - FEEDBACK_REENTER(ret_from_fork) - { - move r0, r31 - jalr r30 - } - FEEDBACK_REENTER(ret_from_kernel_thread) - { - movei r30, 0 /* not an NMI */ - j interrupt_return - } - STD_ENDPROC(ret_from_kernel_thread) - - /* - * Code for ill interrupt. - */ - .pushsection .text.handle_ill,"ax" -handle_ill: - finish_interrupt_save handle_ill - - /* - * Check for if we are single stepping in user level. If so, then - * we need to restore the PC. - */ - check_single_stepping ill, .Ldispatch_normal_ill - - { - /* See if the PC is the 1st bundle in the buffer */ - seq r25, r27, r26 - - /* Point to the 2nd bundle in the buffer */ - addi r26, r26, 8 - } - { - /* Point to the original pc */ - addi r24, r29, SINGLESTEP_STATE_ORIG_PC_OFFSET - - /* Branch if the PC is the 1st bundle in the buffer */ - bnz r25, 3f - } - { - /* See if the PC is the 2nd bundle of the buffer */ - seq r25, r27, r26 - - /* Set PC to next instruction */ - addi r24, r29, SINGLESTEP_STATE_NEXT_PC_OFFSET - } - { - /* Point to flags */ - addi r25, r29, SINGLESTEP_STATE_FLAGS_OFFSET - - /* Branch if PC is in the second bundle */ - bz r25, 2f - } - /* Load flags */ - lw r25, r25 - { - /* - * Get the offset for the register to restore - * Note: the lower bound is 2, so we have implicit scaling by 4. - * No multiplication of the register number by the size of a register - * is needed. - */ - mm r27, r25, zero, SINGLESTEP_STATE_TARGET_LB, \ - SINGLESTEP_STATE_TARGET_UB - - /* Mask Rewrite_LR */ - andi r25, r25, SINGLESTEP_STATE_MASK_UPDATE - } - { - addi r29, r29, SINGLESTEP_STATE_UPDATE_VALUE_OFFSET - - /* Don't rewrite temp register */ - bz r25, 3f - } - { - /* Get the temp value */ - lw r29, r29 - - /* Point to where the register is stored */ - add r27, r27, sp - } - - /* Add in the C ABI save area size to the register offset */ - addi r27, r27, C_ABI_SAVE_AREA_SIZE - - /* Restore the user's register with the temp value */ - sw r27, r29 - j 3f - -2: - /* Must be in the third bundle */ - addi r24, r29, SINGLESTEP_STATE_BRANCH_NEXT_PC_OFFSET - -3: - /* set PC and continue */ - lw r26, r24 - { - sw r28, r26 - GET_THREAD_INFO(r0) - } - - /* - * Clear TIF_SINGLESTEP to prevent recursion if we execute an ill. - * The normal non-arch flow redundantly clears TIF_SINGLESTEP, but we - * need to clear it here and can't really impose on all other arches. - * So what's another write between friends? - */ - - addi r1, r0, THREAD_INFO_FLAGS_OFFSET - { - lw r2, r1 - addi r0, r0, THREAD_INFO_TASK_OFFSET /* currently a no-op */ - } - andi r2, r2, ~_TIF_SINGLESTEP - sw r1, r2 - - /* Issue a sigtrap */ - { - lw r0, r0 /* indirect thru thread_info to get task_info*/ - addi r1, sp, C_ABI_SAVE_AREA_SIZE /* put ptregs pointer into r1 */ - } - - jal send_sigtrap /* issue a SIGTRAP */ - FEEDBACK_REENTER(handle_ill) - { - movei r30, 0 /* not an NMI */ - j .Lresume_userspace /* jump into middle of interrupt_return */ - } - -.Ldispatch_normal_ill: - { - jalr r0 - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - } - FEEDBACK_REENTER(handle_ill) - { - movei r30, 0 /* not an NMI */ - j interrupt_return - } - STD_ENDPROC(handle_ill) - -/* Various stub interrupt handlers and syscall handlers */ - -STD_ENTRY_LOCAL(_kernel_double_fault) - mfspr r1, SPR_EX_CONTEXT_K_0 - move r2, lr - move r3, sp - move r4, r52 - addi sp, sp, -C_ABI_SAVE_AREA_SIZE - j kernel_double_fault - STD_ENDPROC(_kernel_double_fault) - -STD_ENTRY_LOCAL(bad_intr) - mfspr r2, SPR_EX_CONTEXT_K_0 - panic "Unhandled interrupt %#x: PC %#lx" - STD_ENDPROC(bad_intr) - -/* - * Special-case sigreturn to not write r0 to the stack on return. - * This is technically more efficient, but it also avoids difficulties - * in the 64-bit OS when handling 32-bit compat code, since we must not - * sign-extend r0 for the sigreturn return-value case. - */ -#define PTREGS_SYSCALL_SIGRETURN(x, reg) \ - STD_ENTRY(_##x); \ - addli lr, lr, .Lsyscall_sigreturn_skip - .Lhandle_syscall_link; \ - { \ - PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \ - j x \ - }; \ - STD_ENDPROC(_##x) - -PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0) - -/* Save additional callee-saves to pt_regs and jump to standard function. */ -STD_ENTRY(_sys_clone) - push_extra_callee_saves r4 - j sys_clone - STD_ENDPROC(_sys_clone) - -/* - * This entrypoint is taken for the cmpxchg and atomic_update fast - * swints. We may wish to generalize it to other fast swints at some - * point, but for now there are just two very similar ones, which - * makes it faster. - * - * The fast swint code is designed to have a small footprint. It does - * not save or restore any GPRs, counting on the caller-save registers - * to be available to it on entry. It does not modify any callee-save - * registers (including "lr"). It does not check what PL it is being - * called at, so you'd better not call it other than at PL0. - * The wrapper assumes it only clobbers r20-r29, so if - * it ever is necessary to use more registers, be aware. - * - * It does not use the stack, but since it might be re-interrupted by - * a page fault which would assume the stack was valid, it does - * save/restore the stack pointer and zero it out to make sure it gets reset. - * Since we always keep interrupts disabled, the hypervisor won't - * clobber our EX_CONTEXT_K_x registers, so we don't save/restore them - * (other than to advance the PC on return). - * - * We have to manually validate the user vs kernel address range - * (since at PL1 we can read/write both), and for performance reasons - * we don't allow cmpxchg on the fc000000 memory region, since we only - * validate that the user address is below PAGE_OFFSET. - * - * We place it in the __HEAD section to ensure it is relatively - * near to the intvec_SWINT_1 code (reachable by a conditional branch). - * - * Our use of ATOMIC_LOCK_REG here must match do_page_fault_ics(). - * - * As we do in lib/atomic_asm_32.S, we bypass a store if the value we - * would store is the same as the value we just loaded. - */ - __HEAD - .align 64 - /* Align much later jump on the start of a cache line. */ - nop -#if PAGE_SIZE >= 0x10000 - nop -#endif -ENTRY(sys_cmpxchg) - - /* - * Save "sp" and set it zero for any possible page fault. - * - * HACK: We want to both zero sp and check r0's alignment, - * so we do both at once. If "sp" becomes nonzero we - * know r0 is unaligned and branch to the error handler that - * restores sp, so this is OK. - * - * ICS is disabled right now so having a garbage but nonzero - * sp is OK, since we won't execute any faulting instructions - * when it is nonzero. - */ - { - move r27, sp - andi sp, r0, 3 - } - - /* - * Get the lock address in ATOMIC_LOCK_REG, and also validate that the - * address is less than PAGE_OFFSET, since that won't trap at PL1. - * We only use bits less than PAGE_SHIFT to avoid having to worry - * about aliasing among multiple mappings of the same physical page, - * and we ignore the low 3 bits so we have one lock that covers - * both a cmpxchg64() and a cmpxchg() on either its low or high word. - * NOTE: this must match __atomic_hashed_lock() in lib/atomic_32.c. - */ - -#if (PAGE_OFFSET & 0xffff) != 0 -# error Code here assumes PAGE_OFFSET can be loaded with just hi16() -#endif - - { - /* Check for unaligned input. */ - bnz sp, .Lcmpxchg_badaddr - auli r23, zero, hi16(PAGE_OFFSET) /* hugepage-aligned */ - } - { - /* - * Slide bits into position for 'mm'. We want to ignore - * the low 3 bits of r0, and consider only the next - * ATOMIC_HASH_SHIFT bits. - * Because of C pointer arithmetic, we want to compute this: - * - * ((char*)atomic_locks + - * (((r0 >> 3) & ((1 << ATOMIC_HASH_SHIFT) - 1)) << 2)) - * - * Instead of two shifts we just ">> 1", and use 'mm' - * to ignore the low and high bits we don't want. - */ - shri r25, r0, 1 - - slt_u r23, r0, r23 - - /* - * Ensure that the TLB is loaded before we take out the lock. - * This will start fetching the value all the way into our L1 - * as well (and if it gets modified before we grab the lock, - * it will be invalidated from our cache before we reload it). - */ - lw r26, r0 - } - { - auli r21, zero, ha16(atomic_locks) - - bbns r23, .Lcmpxchg_badaddr - } -#if PAGE_SIZE < 0x10000 - /* atomic_locks is page-aligned so for big pages we don't need this. */ - addli r21, r21, lo16(atomic_locks) -#endif - { - /* - * Insert the hash bits into the page-aligned pointer. - * ATOMIC_HASH_SHIFT is so big that we don't actually hash - * the unmasked address bits, as that may cause unnecessary - * collisions. - */ - mm ATOMIC_LOCK_REG_NAME, r25, r21, 2, (ATOMIC_HASH_SHIFT + 2) - 1 - - seqi r23, TREG_SYSCALL_NR_NAME, __NR_FAST_cmpxchg64 - } - { - /* Branch away at this point if we're doing a 64-bit cmpxchg. */ - bbs r23, .Lcmpxchg64 - andi r23, r0, 7 /* Precompute alignment for cmpxchg64. */ - } - { - /* - * We very carefully align the code that actually runs with - * the lock held (twelve bundles) so that we know it is all in - * the icache when we start. This instruction (the jump) is - * at the start of the first cache line, address zero mod 64; - * we jump to the very end of the second cache line to get that - * line loaded in the icache, then fall through to issue the tns - * in the third cache line, at which point it's all cached. - * Note that is for performance, not correctness. - */ - j .Lcmpxchg32_tns - } - -/* Symbol for do_page_fault_ics() to use to compare against the PC. */ -.global __sys_cmpxchg_grab_lock -__sys_cmpxchg_grab_lock: - - /* - * Perform the actual cmpxchg or atomic_update. - */ -.Ldo_cmpxchg32: - { - lw r21, r0 - seqi r23, TREG_SYSCALL_NR_NAME, __NR_FAST_atomic_update - move r24, r2 - } - { - seq r22, r21, r1 /* See if cmpxchg matches. */ - and r25, r21, r1 /* If atomic_update, compute (*mem & mask) */ - } - { - or r22, r22, r23 /* Skip compare branch for atomic_update. */ - add r25, r25, r2 /* Compute (*mem & mask) + addend. */ - } - { - mvnz r24, r23, r25 /* Use atomic_update value if appropriate. */ - bbns r22, .Lcmpxchg32_nostore - } - seq r22, r24, r21 /* Are we storing the value we loaded? */ - bbs r22, .Lcmpxchg32_nostore - sw r0, r24 - - /* The following instruction is the start of the second cache line. */ - /* Do slow mtspr here so the following "mf" waits less. */ - { - move sp, r27 - mtspr SPR_EX_CONTEXT_K_0, r28 - } - mf - - { - move r0, r21 - sw ATOMIC_LOCK_REG_NAME, zero - } - iret - - /* Duplicated code here in the case where we don't overlap "mf" */ -.Lcmpxchg32_nostore: - { - move r0, r21 - sw ATOMIC_LOCK_REG_NAME, zero - } - { - move sp, r27 - mtspr SPR_EX_CONTEXT_K_0, r28 - } - iret - - /* - * The locking code is the same for 32-bit cmpxchg/atomic_update, - * and for 64-bit cmpxchg. We provide it as a macro and put - * it into both versions. We can't share the code literally - * since it depends on having the right branch-back address. - */ - .macro cmpxchg_lock, bitwidth - - /* Lock; if we succeed, jump back up to the read-modify-write. */ -#ifdef CONFIG_SMP - tns r21, ATOMIC_LOCK_REG_NAME -#else - /* - * Non-SMP preserves all the lock infrastructure, to keep the - * code simpler for the interesting (SMP) case. However, we do - * one small optimization here and in atomic_asm.S, which is - * to fake out acquiring the actual lock in the atomic_lock table. - */ - movei r21, 0 -#endif - - /* Issue the slow SPR here while the tns result is in flight. */ - mfspr r28, SPR_EX_CONTEXT_K_0 - - { - addi r28, r28, 8 /* return to the instruction after the swint1 */ - bzt r21, .Ldo_cmpxchg\bitwidth - } - /* - * The preceding instruction is the last thing that must be - * hot in the icache before we do the "tns" above. - */ - -#ifdef CONFIG_SMP - /* - * We failed to acquire the tns lock on our first try. Now use - * bounded exponential backoff to retry, like __atomic_spinlock(). - */ - { - moveli r23, 2048 /* maximum backoff time in cycles */ - moveli r25, 32 /* starting backoff time in cycles */ - } -1: mfspr r26, CYCLE_LOW /* get start point for this backoff */ -2: mfspr r22, CYCLE_LOW /* test to see if we've backed off enough */ - sub r22, r22, r26 - slt r22, r22, r25 - bbst r22, 2b - { - shli r25, r25, 1 /* double the backoff; retry the tns */ - tns r21, ATOMIC_LOCK_REG_NAME - } - slt r26, r23, r25 /* is the proposed backoff too big? */ - { - mvnz r25, r26, r23 - bzt r21, .Ldo_cmpxchg\bitwidth - } - j 1b -#endif /* CONFIG_SMP */ - .endm - -.Lcmpxchg32_tns: - /* - * This is the last instruction on the second cache line. - * The nop here loads the second line, then we fall through - * to the tns to load the third line before we take the lock. - */ - nop - cmpxchg_lock 32 - - /* - * This code is invoked from sys_cmpxchg after most of the - * preconditions have been checked. We still need to check - * that r0 is 8-byte aligned, since if it's not we won't - * actually be atomic. However, ATOMIC_LOCK_REG has the atomic - * lock pointer and r27/r28 have the saved SP/PC. - * r23 is holding "r0 & 7" so we can test for alignment. - * The compare value is in r2/r3; the new value is in r4/r5. - * On return, we must put the old value in r0/r1. - */ - .align 64 -.Lcmpxchg64: - { - bzt r23, .Lcmpxchg64_tns - } - j .Lcmpxchg_badaddr - -.Ldo_cmpxchg64: - { - lw r21, r0 - addi r25, r0, 4 - } - { - lw r1, r25 - } - seq r26, r21, r2 - { - bz r26, .Lcmpxchg64_mismatch - seq r26, r1, r3 - } - { - bz r26, .Lcmpxchg64_mismatch - } - sw r0, r4 - sw r25, r5 - - /* - * The 32-bit path provides optimized "match" and "mismatch" - * iret paths, but we don't have enough bundles in this cache line - * to do that, so we just make even the "mismatch" path do an "mf". - */ -.Lcmpxchg64_mismatch: - { - move sp, r27 - mtspr SPR_EX_CONTEXT_K_0, r28 - } - mf - { - move r0, r21 - sw ATOMIC_LOCK_REG_NAME, zero - } - iret - -.Lcmpxchg64_tns: - cmpxchg_lock 64 - - - /* - * Reset sp and revector to sys_cmpxchg_badaddr(), which will - * just raise the appropriate signal and exit. Doing it this - * way means we don't have to duplicate the code in intvec.S's - * int_hand macro that locates the top of the stack. - */ -.Lcmpxchg_badaddr: - { - moveli TREG_SYSCALL_NR_NAME, __NR_cmpxchg_badaddr - move sp, r27 - } - j intvec_SWINT_1 - ENDPROC(sys_cmpxchg) - ENTRY(__sys_cmpxchg_end) - - -/* The single-step support may need to read all the registers. */ -int_unalign: - push_extra_callee_saves r0 - j do_trap - -/* Include .intrpt array of interrupt vectors */ - .section ".intrpt", "ax" - -#ifndef CONFIG_USE_PMC -#define handle_perf_interrupt bad_intr -#endif - -#ifndef CONFIG_HARDWALL -#define do_hardwall_trap bad_intr -#endif - - int_hand INT_ITLB_MISS, ITLB_MISS, \ - do_page_fault, handle_interrupt_no_single_step - int_hand INT_MEM_ERROR, MEM_ERROR, bad_intr - int_hand INT_ILL, ILL, do_trap, handle_ill - int_hand INT_GPV, GPV, do_trap - int_hand INT_SN_ACCESS, SN_ACCESS, do_trap - int_hand INT_IDN_ACCESS, IDN_ACCESS, do_trap - int_hand INT_UDN_ACCESS, UDN_ACCESS, do_trap - int_hand INT_IDN_REFILL, IDN_REFILL, bad_intr - int_hand INT_UDN_REFILL, UDN_REFILL, bad_intr - int_hand INT_IDN_COMPLETE, IDN_COMPLETE, bad_intr - int_hand INT_UDN_COMPLETE, UDN_COMPLETE, bad_intr - int_hand INT_SWINT_3, SWINT_3, do_trap - int_hand INT_SWINT_2, SWINT_2, do_trap - int_hand INT_SWINT_1, SWINT_1, SYSCALL, handle_syscall - int_hand INT_SWINT_0, SWINT_0, do_trap - int_hand INT_UNALIGN_DATA, UNALIGN_DATA, int_unalign - int_hand INT_DTLB_MISS, DTLB_MISS, do_page_fault - int_hand INT_DTLB_ACCESS, DTLB_ACCESS, do_page_fault - int_hand INT_DMATLB_MISS, DMATLB_MISS, do_page_fault - int_hand INT_DMATLB_ACCESS, DMATLB_ACCESS, do_page_fault - int_hand INT_SNITLB_MISS, SNITLB_MISS, do_page_fault - int_hand INT_SN_NOTIFY, SN_NOTIFY, bad_intr - int_hand INT_SN_FIREWALL, SN_FIREWALL, do_hardwall_trap - int_hand INT_IDN_FIREWALL, IDN_FIREWALL, bad_intr - int_hand INT_UDN_FIREWALL, UDN_FIREWALL, do_hardwall_trap - int_hand INT_TILE_TIMER, TILE_TIMER, do_timer_interrupt - int_hand INT_IDN_TIMER, IDN_TIMER, bad_intr - int_hand INT_UDN_TIMER, UDN_TIMER, bad_intr - int_hand INT_DMA_NOTIFY, DMA_NOTIFY, bad_intr - int_hand INT_IDN_CA, IDN_CA, bad_intr - int_hand INT_UDN_CA, UDN_CA, bad_intr - int_hand INT_IDN_AVAIL, IDN_AVAIL, bad_intr - int_hand INT_UDN_AVAIL, UDN_AVAIL, bad_intr - int_hand INT_PERF_COUNT, PERF_COUNT, \ - handle_perf_interrupt, handle_nmi - int_hand INT_INTCTRL_3, INTCTRL_3, bad_intr -#if CONFIG_KERNEL_PL == 2 - dc_dispatch INT_INTCTRL_2, INTCTRL_2 - int_hand INT_INTCTRL_1, INTCTRL_1, bad_intr -#else - int_hand INT_INTCTRL_2, INTCTRL_2, bad_intr - dc_dispatch INT_INTCTRL_1, INTCTRL_1 -#endif - int_hand INT_INTCTRL_0, INTCTRL_0, bad_intr - int_hand INT_MESSAGE_RCV_DWNCL, MESSAGE_RCV_DWNCL, \ - hv_message_intr - int_hand INT_DEV_INTR_DWNCL, DEV_INTR_DWNCL, \ - tile_dev_intr - int_hand INT_I_ASID, I_ASID, bad_intr - int_hand INT_D_ASID, D_ASID, bad_intr - int_hand INT_DMATLB_MISS_DWNCL, DMATLB_MISS_DWNCL, \ - do_page_fault - int_hand INT_SNITLB_MISS_DWNCL, SNITLB_MISS_DWNCL, \ - do_page_fault - int_hand INT_DMATLB_ACCESS_DWNCL, DMATLB_ACCESS_DWNCL, \ - do_page_fault - int_hand INT_SN_CPL, SN_CPL, bad_intr - int_hand INT_DOUBLE_FAULT, DOUBLE_FAULT, do_trap - int_hand INT_AUX_PERF_COUNT, AUX_PERF_COUNT, \ - handle_perf_interrupt, handle_nmi - - /* Synthetic interrupt delivered only by the simulator */ - int_hand INT_BREAKPOINT, BREAKPOINT, do_breakpoint diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S deleted file mode 100644 index 3b51bdf37d11..000000000000 --- a/arch/tile/kernel/intvec_64.S +++ /dev/null @@ -1,1564 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Linux interrupt vectors. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PTREGS_PTR(reg, ptreg) addli reg, sp, C_ABI_SAVE_AREA_SIZE + (ptreg) - -#define PTREGS_OFFSET_SYSCALL PTREGS_OFFSET_REG(TREG_SYSCALL_NR) - -#if CONFIG_KERNEL_PL == 1 || CONFIG_KERNEL_PL == 2 -/* - * Set "result" non-zero if ex1 holds the PL of the kernel - * (with or without ICS being set). Note this works only - * because we never find the PL at level 3. - */ -# define IS_KERNEL_EX1(result, ex1) andi result, ex1, CONFIG_KERNEL_PL -#else -# error Recode IS_KERNEL_EX1 for CONFIG_KERNEL_PL -#endif - - .macro push_reg reg, ptr=sp, delta=-8 - { - st \ptr, \reg - addli \ptr, \ptr, \delta - } - .endm - - .macro pop_reg reg, ptr=sp, delta=8 - { - ld \reg, \ptr - addli \ptr, \ptr, \delta - } - .endm - - .macro pop_reg_zero reg, zreg, ptr=sp, delta=8 - { - move \zreg, zero - ld \reg, \ptr - addi \ptr, \ptr, \delta - } - .endm - - .macro push_extra_callee_saves reg - PTREGS_PTR(\reg, PTREGS_OFFSET_REG(51)) - push_reg r51, \reg - push_reg r50, \reg - push_reg r49, \reg - push_reg r48, \reg - push_reg r47, \reg - push_reg r46, \reg - push_reg r45, \reg - push_reg r44, \reg - push_reg r43, \reg - push_reg r42, \reg - push_reg r41, \reg - push_reg r40, \reg - push_reg r39, \reg - push_reg r38, \reg - push_reg r37, \reg - push_reg r36, \reg - push_reg r35, \reg - push_reg r34, \reg, PTREGS_OFFSET_BASE - PTREGS_OFFSET_REG(34) - .endm - - .macro panic str - .pushsection .rodata, "a" -1: - .asciz "\str" - .popsection - { - moveli r0, hw2_last(1b) - } - { - shl16insli r0, r0, hw1(1b) - } - { - shl16insli r0, r0, hw0(1b) - jal panic - } - .endm - - /* - * Unalign data exception fast handling: In order to handle - * unaligned data access, a fast JIT version is generated and stored - * in a specific area in user space. We first need to do a quick poke - * to see if the JIT is available. We use certain bits in the fault - * PC (3 to 9 is used for 16KB page size) as index to address the JIT - * code area. The first 64bit word is the fault PC, and the 2nd one is - * the fault bundle itself. If these 2 words both match, then we - * directly "iret" to JIT code. If not, a slow path is invoked to - * generate new JIT code. Note: the current JIT code WILL be - * overwritten if it existed. So, ideally we can handle 128 unalign - * fixups via JIT. For lookup efficiency and to effectively support - * tight loops with multiple unaligned reference, a simple - * direct-mapped cache is used. - * - * SPR_EX_CONTEXT_K_0 is modified to return to JIT code. - * SPR_EX_CONTEXT_K_1 has ICS set. - * SPR_EX_CONTEXT_0_0 is setup to user program's next PC. - * SPR_EX_CONTEXT_0_1 = 0. - */ - .macro int_hand_unalign_fast vecnum, vecname - .org (\vecnum << 8) -intvec_\vecname: - /* Put r3 in SPR_SYSTEM_SAVE_K_1. */ - mtspr SPR_SYSTEM_SAVE_K_1, r3 - - mfspr r3, SPR_EX_CONTEXT_K_1 - /* - * Examine if exception comes from user without ICS set. - * If not, just go directly to the slow path. - */ - bnez r3, hand_unalign_slow_nonuser - - mfspr r3, SPR_SYSTEM_SAVE_K_0 - - /* Get &thread_info->unalign_jit_tmp[0] in r3. */ - bfexts r3, r3, 0, CPU_SHIFT-1 - mm r3, zero, LOG2_THREAD_SIZE, 63 - addli r3, r3, THREAD_INFO_UNALIGN_JIT_TMP_OFFSET - - /* - * Save r0, r1, r2 into thread_info array r3 points to - * from low to high memory in order. - */ - st_add r3, r0, 8 - st_add r3, r1, 8 - { - st_add r3, r2, 8 - andi r2, sp, 7 - } - - /* Save stored r3 value so we can revert it on a page fault. */ - mfspr r1, SPR_SYSTEM_SAVE_K_1 - st r3, r1 - - { - /* Generate a SIGBUS if sp is not 8-byte aligned. */ - bnez r2, hand_unalign_slow_badsp - } - - /* - * Get the thread_info in r0; load r1 with pc. Set the low bit of sp - * as an indicator to the page fault code in case we fault. - */ - { - ori sp, sp, 1 - mfspr r1, SPR_EX_CONTEXT_K_0 - } - - /* Add the jit_info offset in thread_info; extract r1 [3:9] into r2. */ - { - addli r0, r3, THREAD_INFO_UNALIGN_JIT_BASE_OFFSET - \ - (THREAD_INFO_UNALIGN_JIT_TMP_OFFSET + (3 * 8)) - bfextu r2, r1, 3, (2 + PAGE_SHIFT - UNALIGN_JIT_SHIFT) - } - - /* Load the jit_info; multiply r2 by 128. */ - { - ld r0, r0 - shli r2, r2, UNALIGN_JIT_SHIFT - } - - /* - * If r0 is NULL, the JIT page is not mapped, so go to slow path; - * add offset r2 to r0 at the same time. - */ - { - beqz r0, hand_unalign_slow - add r2, r0, r2 - } - - /* - * We are loading from userspace (both the JIT info PC and - * instruction word, and the instruction word we executed) - * and since either could fault while holding the interrupt - * critical section, we must tag this region and check it in - * do_page_fault() to handle it properly. - */ -ENTRY(__start_unalign_asm_code) - - /* Load first word of JIT in r0 and increment r2 by 8. */ - ld_add r0, r2, 8 - - /* - * Compare the PC with the 1st word in JIT; load the fault bundle - * into r1. - */ - { - cmpeq r0, r0, r1 - ld r1, r1 - } - - /* Go to slow path if PC doesn't match. */ - beqz r0, hand_unalign_slow - - /* - * Load the 2nd word of JIT, which is supposed to be the fault - * bundle for a cache hit. Increment r2; after this bundle r2 will - * point to the potential start of the JIT code we want to run. - */ - ld_add r0, r2, 8 - - /* No further accesses to userspace are done after this point. */ -ENTRY(__end_unalign_asm_code) - - /* Compare the real bundle with what is saved in the JIT area. */ - { - cmpeq r0, r1, r0 - mtspr SPR_EX_CONTEXT_0_1, zero - } - - /* Go to slow path if the fault bundle does not match. */ - beqz r0, hand_unalign_slow - - /* - * A cache hit is found. - * r2 points to start of JIT code (3rd word). - * r0 is the fault pc. - * r1 is the fault bundle. - * Reset the low bit of sp. - */ - { - mfspr r0, SPR_EX_CONTEXT_K_0 - andi sp, sp, ~1 - } - - /* Write r2 into EX_CONTEXT_K_0 and increment PC. */ - { - mtspr SPR_EX_CONTEXT_K_0, r2 - addi r0, r0, 8 - } - - /* - * Set ICS on kernel EX_CONTEXT_K_1 in order to "iret" to - * user with ICS set. This way, if the JIT fixup causes another - * unalign exception (which shouldn't be possible) the user - * process will be terminated with SIGBUS. Also, our fixup will - * run without interleaving with external interrupts. - * Each fixup is at most 14 bundles, so it won't hold ICS for long. - */ - { - movei r1, PL_ICS_EX1(USER_PL, 1) - mtspr SPR_EX_CONTEXT_0_0, r0 - } - - { - mtspr SPR_EX_CONTEXT_K_1, r1 - addi r3, r3, -(3 * 8) - } - - /* Restore r0..r3. */ - ld_add r0, r3, 8 - ld_add r1, r3, 8 - ld_add r2, r3, 8 - ld r3, r3 - - iret - ENDPROC(intvec_\vecname) - .endm - -#ifdef __COLLECT_LINKER_FEEDBACK__ - .pushsection .text.intvec_feedback,"ax" -intvec_feedback: - .popsection -#endif - - /* - * Default interrupt handler. - * - * vecnum is where we'll put this code. - * c_routine is the C routine we'll call. - * - * The C routine is passed two arguments: - * - A pointer to the pt_regs state. - * - The interrupt vector number. - * - * The "processing" argument specifies the code for processing - * the interrupt. Defaults to "handle_interrupt". - */ - .macro __int_hand vecnum, vecname, c_routine,processing=handle_interrupt -intvec_\vecname: - /* Temporarily save a register so we have somewhere to work. */ - - mtspr SPR_SYSTEM_SAVE_K_1, r0 - mfspr r0, SPR_EX_CONTEXT_K_1 - - /* - * The unalign data fastpath code sets the low bit in sp to - * force us to reset it here on fault. - */ - { - blbs sp, 2f - IS_KERNEL_EX1(r0, r0) - } - - .ifc \vecnum, INT_DOUBLE_FAULT - /* - * For double-faults from user-space, fall through to the normal - * register save and stack setup path. Otherwise, it's the - * hypervisor giving us one last chance to dump diagnostics, and we - * branch to the kernel_double_fault routine to do so. - */ - beqz r0, 1f - j _kernel_double_fault -1: - .else - /* - * If we're coming from user-space, then set sp to the top of - * the kernel stack. Otherwise, assume sp is already valid. - */ - { - bnez r0, 0f - move r0, sp - } - .endif - - .ifc \c_routine, do_page_fault - /* - * The page_fault handler may be downcalled directly by the - * hypervisor even when Linux is running and has ICS set. - * - * In this case the contents of EX_CONTEXT_K_1 reflect the - * previous fault and can't be relied on to choose whether or - * not to reinitialize the stack pointer. So we add a test - * to see whether SYSTEM_SAVE_K_2 has the high bit set, - * and if so we don't reinitialize sp, since we must be coming - * from Linux. (In fact the precise case is !(val & ~1), - * but any Linux PC has to have the high bit set.) - * - * Note that the hypervisor *always* sets SYSTEM_SAVE_K_2 for - * any path that turns into a downcall to one of our TLB handlers. - * - * FIXME: if we end up never using this path, perhaps we should - * prevent the hypervisor from generating downcalls in this case. - * The advantage of getting a downcall is we can panic in Linux. - */ - mfspr r0, SPR_SYSTEM_SAVE_K_2 - { - bltz r0, 0f /* high bit in S_S_1_2 is for a PC to use */ - move r0, sp - } - .endif - -2: - /* - * SYSTEM_SAVE_K_0 holds the cpu number in the high bits, and - * the current stack top in the lower bits. So we recover - * our starting stack value by sign-extending the low bits, then - * point sp at the top aligned address on the actual stack page. - */ - mfspr r0, SPR_SYSTEM_SAVE_K_0 - bfexts r0, r0, 0, CPU_SHIFT-1 - -0: - /* - * Align the stack mod 64 so we can properly predict what - * cache lines we need to write-hint to reduce memory fetch - * latency as we enter the kernel. The layout of memory is - * as follows, with cache line 0 at the lowest VA, and cache - * line 8 just below the r0 value this "andi" computes. - * Note that we never write to cache line 8, and we skip - * cache lines 1-3 for syscalls. - * - * cache line 8: ptregs padding (two words) - * cache line 7: sp, lr, pc, ex1, faultnum, orig_r0, flags, cmpexch - * cache line 6: r46...r53 (tp) - * cache line 5: r38...r45 - * cache line 4: r30...r37 - * cache line 3: r22...r29 - * cache line 2: r14...r21 - * cache line 1: r6...r13 - * cache line 0: 2 x frame, r0..r5 - */ -#if STACK_TOP_DELTA != 64 -#error STACK_TOP_DELTA must be 64 for assumptions here and in task_pt_regs() -#endif - andi r0, r0, -64 - - /* - * Push the first four registers on the stack, so that we can set - * them to vector-unique values before we jump to the common code. - * - * Registers are pushed on the stack as a struct pt_regs, - * with the sp initially just above the struct, and when we're - * done, sp points to the base of the struct, minus - * C_ABI_SAVE_AREA_SIZE, so we can directly jal to C code. - * - * This routine saves just the first four registers, plus the - * stack context so we can do proper backtracing right away, - * and defers to handle_interrupt to save the rest. - * The backtracer needs pc, ex1, lr, sp, r52, and faultnum, - * and needs sp set to its final location at the bottom of - * the stack frame. - */ - addli r0, r0, PTREGS_OFFSET_LR - (PTREGS_SIZE + KSTK_PTREGS_GAP) - wh64 r0 /* cache line 7 */ - { - st r0, lr - addli r0, r0, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR - } - { - st r0, sp - addli sp, r0, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_SP - } - wh64 sp /* cache line 6 */ - { - st sp, r52 - addli sp, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(52) - } - wh64 sp /* cache line 0 */ - { - st sp, r1 - addli sp, sp, PTREGS_OFFSET_REG(2) - PTREGS_OFFSET_REG(1) - } - { - st sp, r2 - addli sp, sp, PTREGS_OFFSET_REG(3) - PTREGS_OFFSET_REG(2) - } - { - st sp, r3 - addli sp, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_REG(3) - } - mfspr r0, SPR_EX_CONTEXT_K_0 - .ifc \processing,handle_syscall - /* - * Bump the saved PC by one bundle so that when we return, we won't - * execute the same swint instruction again. We need to do this while - * we're in the critical section. - */ - addi r0, r0, 8 - .endif - { - st sp, r0 - addli sp, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC - } - mfspr r0, SPR_EX_CONTEXT_K_1 - { - st sp, r0 - addi sp, sp, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1 - /* - * Use r0 for syscalls so it's a temporary; use r1 for interrupts - * so that it gets passed through unchanged to the handler routine. - * Note that the .if conditional confusingly spans bundles. - */ - .ifc \processing,handle_syscall - movei r0, \vecnum - } - { - st sp, r0 - .else - movei r1, \vecnum - } - { - st sp, r1 - .endif - addli sp, sp, PTREGS_OFFSET_REG(0) - PTREGS_OFFSET_FAULTNUM - } - mfspr r0, SPR_SYSTEM_SAVE_K_1 /* Original r0 */ - { - st sp, r0 - addi sp, sp, -PTREGS_OFFSET_REG(0) - 8 - } - { - st sp, zero /* write zero into "Next SP" frame pointer */ - addi sp, sp, -8 /* leave SP pointing at bottom of frame */ - } - .ifc \processing,handle_syscall - j handle_syscall - .else - /* Capture per-interrupt SPR context to registers. */ - .ifc \c_routine, do_page_fault - mfspr r2, SPR_SYSTEM_SAVE_K_3 /* address of page fault */ - mfspr r3, SPR_SYSTEM_SAVE_K_2 /* info about page fault */ - .else - .ifc \vecnum, INT_ILL_TRANS - mfspr r2, ILL_VA_PC - .else - .ifc \vecnum, INT_DOUBLE_FAULT - mfspr r2, SPR_SYSTEM_SAVE_K_2 /* double fault info from HV */ - .else - .ifc \c_routine, do_trap - mfspr r2, GPV_REASON - .else - .ifc \c_routine, handle_perf_interrupt - mfspr r2, PERF_COUNT_STS - .else - .ifc \c_routine, handle_perf_interrupt - mfspr r2, AUX_PERF_COUNT_STS - .endif - .ifc \c_routine, do_nmi - mfspr r2, SPR_SYSTEM_SAVE_K_2 /* nmi type */ - .else - .endif - .endif - .endif - .endif - .endif - .endif - /* Put function pointer in r0 */ - moveli r0, hw2_last(\c_routine) - shl16insli r0, r0, hw1(\c_routine) - { - shl16insli r0, r0, hw0(\c_routine) - j \processing - } - .endif - ENDPROC(intvec_\vecname) - -#ifdef __COLLECT_LINKER_FEEDBACK__ - .pushsection .text.intvec_feedback,"ax" - .org (\vecnum << 5) - FEEDBACK_ENTER_EXPLICIT(intvec_\vecname, .intrpt, 1 << 8) - jrp lr - .popsection -#endif - - .endm - - - /* - * Save the rest of the registers that we didn't save in the actual - * vector itself. We can't use r0-r10 inclusive here. - */ - .macro finish_interrupt_save, function - - /* If it's a syscall, save a proper orig_r0, otherwise just zero. */ - PTREGS_PTR(r52, PTREGS_OFFSET_ORIG_R0) - { - .ifc \function,handle_syscall - st r52, r0 - .else - st r52, zero - .endif - PTREGS_PTR(r52, PTREGS_OFFSET_TP) - } - st r52, tp - { - mfspr tp, CMPEXCH_VALUE - PTREGS_PTR(r52, PTREGS_OFFSET_CMPEXCH) - } - - /* - * For ordinary syscalls, we save neither caller- nor callee- - * save registers, since the syscall invoker doesn't expect the - * caller-saves to be saved, and the called kernel functions will - * take care of saving the callee-saves for us. - * - * For interrupts we save just the caller-save registers. Saving - * them is required (since the "caller" can't save them). Again, - * the called kernel functions will restore the callee-save - * registers for us appropriately. - * - * On return, we normally restore nothing special for syscalls, - * and just the caller-save registers for interrupts. - * - * However, there are some important caveats to all this: - * - * - We always save a few callee-save registers to give us - * some scratchpad registers to carry across function calls. - * - * - fork/vfork/etc require us to save all the callee-save - * registers, which we do in PTREGS_SYSCALL_ALL_REGS, below. - * - * - We always save r0..r5 and r10 for syscalls, since we need - * to reload them a bit later for the actual kernel call, and - * since we might need them for -ERESTARTNOINTR, etc. - * - * - Before invoking a signal handler, we save the unsaved - * callee-save registers so they are visible to the - * signal handler or any ptracer. - * - * - If the unsaved callee-save registers are modified, we set - * a bit in pt_regs so we know to reload them from pt_regs - * and not just rely on the kernel function unwinding. - * (Done for ptrace register writes and SA_SIGINFO handler.) - */ - { - st r52, tp - PTREGS_PTR(r52, PTREGS_OFFSET_REG(33)) - } - wh64 r52 /* cache line 4 */ - push_reg r33, r52 - push_reg r32, r52 - push_reg r31, r52 - .ifc \function,handle_syscall - push_reg r30, r52, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(30) - push_reg TREG_SYSCALL_NR_NAME, r52, \ - PTREGS_OFFSET_REG(5) - PTREGS_OFFSET_SYSCALL - .else - - push_reg r30, r52, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(30) - wh64 r52 /* cache line 3 */ - push_reg r29, r52 - push_reg r28, r52 - push_reg r27, r52 - push_reg r26, r52 - push_reg r25, r52 - push_reg r24, r52 - push_reg r23, r52 - push_reg r22, r52 - wh64 r52 /* cache line 2 */ - push_reg r21, r52 - push_reg r20, r52 - push_reg r19, r52 - push_reg r18, r52 - push_reg r17, r52 - push_reg r16, r52 - push_reg r15, r52 - push_reg r14, r52 - wh64 r52 /* cache line 1 */ - push_reg r13, r52 - push_reg r12, r52 - push_reg r11, r52 - push_reg r10, r52 - push_reg r9, r52 - push_reg r8, r52 - push_reg r7, r52 - push_reg r6, r52 - - .endif - - push_reg r5, r52 - st r52, r4 - - /* - * If we will be returning to the kernel, we will need to - * reset the interrupt masks to the state they had before. - * Set DISABLE_IRQ in flags iff we came from kernel pl with - * irqs disabled. - */ - mfspr r32, SPR_EX_CONTEXT_K_1 - { - IS_KERNEL_EX1(r32, r32) - PTREGS_PTR(r21, PTREGS_OFFSET_FLAGS) - } - beqzt r32, 1f /* zero if from user space */ - IRQS_DISABLED(r32) /* zero if irqs enabled */ -#if PT_FLAGS_DISABLE_IRQ != 1 -# error Value of IRQS_DISABLED used to set PT_FLAGS_DISABLE_IRQ; fix -#endif -1: - .ifnc \function,handle_syscall - /* Record the fact that we saved the caller-save registers above. */ - ori r32, r32, PT_FLAGS_CALLER_SAVES - .endif - st r21, r32 - - /* - * we've captured enough state to the stack (including in - * particular our EX_CONTEXT state) that we can now release - * the interrupt critical section and replace it with our - * standard "interrupts disabled" mask value. This allows - * synchronous interrupts (and profile interrupts) to punch - * through from this point onwards. - * - * It's important that no code before this point touch memory - * other than our own stack (to keep the invariant that this - * is all that gets touched under ICS), and that no code after - * this point reference any interrupt-specific SPR, in particular - * the EX_CONTEXT_K_ values. - */ - .ifc \function,handle_nmi - IRQ_DISABLE_ALL(r20) - .else - IRQ_DISABLE(r20, r21) - .endif - mtspr INTERRUPT_CRITICAL_SECTION, zero - - /* Load tp with our per-cpu offset. */ -#ifdef CONFIG_SMP - { - mfspr r20, SPR_SYSTEM_SAVE_K_0 - moveli r21, hw2_last(__per_cpu_offset) - } - { - shl16insli r21, r21, hw1(__per_cpu_offset) - bfextu r20, r20, CPU_SHIFT, 63 - } - shl16insli r21, r21, hw0(__per_cpu_offset) - shl3add r20, r20, r21 - ld tp, r20 -#else - move tp, zero -#endif - -#ifdef __COLLECT_LINKER_FEEDBACK__ - /* - * Notify the feedback routines that we were in the - * appropriate fixed interrupt vector area. Note that we - * still have ICS set at this point, so we can't invoke any - * atomic operations or we will panic. The feedback - * routines internally preserve r0..r10 and r30 up. - */ - .ifnc \function,handle_syscall - shli r20, r1, 5 - .else - moveli r20, INT_SWINT_1 << 5 - .endif - moveli r21, hw2_last(intvec_feedback) - shl16insli r21, r21, hw1(intvec_feedback) - shl16insli r21, r21, hw0(intvec_feedback) - add r20, r20, r21 - jalr r20 - - /* And now notify the feedback routines that we are here. */ - FEEDBACK_ENTER(\function) -#endif - - /* - * Prepare the first 256 stack bytes to be rapidly accessible - * without having to fetch the background data. - */ - addi r52, sp, -64 - { - wh64 r52 - addi r52, r52, -64 - } - { - wh64 r52 - addi r52, r52, -64 - } - { - wh64 r52 - addi r52, r52, -64 - } - wh64 r52 - -#if defined(CONFIG_TRACE_IRQFLAGS) || defined(CONFIG_CONTEXT_TRACKING) - .ifnc \function,handle_nmi - /* - * We finally have enough state set up to notify the irq - * tracing code that irqs were disabled on entry to the handler. - * The TRACE_IRQS_OFF call clobbers registers r0-r29. - * For syscalls, we already have the register state saved away - * on the stack, so we don't bother to do any register saves here, - * and later we pop the registers back off the kernel stack. - * For interrupt handlers, save r0-r3 in callee-saved registers. - */ - .ifnc \function,handle_syscall - { move r30, r0; move r31, r1 } - { move r32, r2; move r33, r3 } - .endif - TRACE_IRQS_OFF -#ifdef CONFIG_CONTEXT_TRACKING - jal context_tracking_user_exit -#endif - .ifnc \function,handle_syscall - { move r0, r30; move r1, r31 } - { move r2, r32; move r3, r33 } - .endif - .endif -#endif - - .endm - - /* - * Redispatch a downcall. - */ - .macro dc_dispatch vecnum, vecname - .org (\vecnum << 8) -intvec_\vecname: - j _hv_downcall_dispatch - ENDPROC(intvec_\vecname) - .endm - - /* - * Common code for most interrupts. The C function we're eventually - * going to is in r0, and the faultnum is in r1; the original - * values for those registers are on the stack. - */ - .pushsection .text.handle_interrupt,"ax" -handle_interrupt: - finish_interrupt_save handle_interrupt - - /* Jump to the C routine; it should enable irqs as soon as possible. */ - { - jalr r0 - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - } - FEEDBACK_REENTER(handle_interrupt) - { - movei r30, 0 /* not an NMI */ - j interrupt_return - } - STD_ENDPROC(handle_interrupt) - -/* - * This routine takes a boolean in r30 indicating if this is an NMI. - * If so, we also expect a boolean in r31 indicating whether to - * re-enable the oprofile interrupts. - * - * Note that .Lresume_userspace is jumped to directly in several - * places, and we need to make sure r30 is set correctly in those - * callers as well. - */ -STD_ENTRY(interrupt_return) - /* If we're resuming to kernel space, don't check thread flags. */ - { - bnez r30, .Lrestore_all /* NMIs don't special-case user-space */ - PTREGS_PTR(r29, PTREGS_OFFSET_EX1) - } - ld r29, r29 - IS_KERNEL_EX1(r29, r29) - { - beqzt r29, .Lresume_userspace - move r29, sp - } - -#ifdef CONFIG_PREEMPT - /* Returning to kernel space. Check if we need preemption. */ - EXTRACT_THREAD_INFO(r29) - addli r28, r29, THREAD_INFO_FLAGS_OFFSET - { - ld r28, r28 - addli r29, r29, THREAD_INFO_PREEMPT_COUNT_OFFSET - } - { - andi r28, r28, _TIF_NEED_RESCHED - ld4s r29, r29 - } - beqzt r28, 1f - bnez r29, 1f - /* Disable interrupts explicitly for preemption. */ - IRQ_DISABLE(r20,r21) - TRACE_IRQS_OFF - jal preempt_schedule_irq - FEEDBACK_REENTER(interrupt_return) -1: -#endif - - /* If we're resuming to _cpu_idle_nap, bump PC forward by 8. */ - { - moveli r27, hw2_last(_cpu_idle_nap) - PTREGS_PTR(r29, PTREGS_OFFSET_PC) - } - { - ld r28, r29 - shl16insli r27, r27, hw1(_cpu_idle_nap) - } - { - shl16insli r27, r27, hw0(_cpu_idle_nap) - } - { - cmpeq r27, r27, r28 - } - { - blbc r27, .Lrestore_all - addi r28, r28, 8 - } - st r29, r28 - j .Lrestore_all - -.Lresume_userspace: - FEEDBACK_REENTER(interrupt_return) - - /* - * Disable interrupts so as to make sure we don't - * miss an interrupt that sets any of the thread flags (like - * need_resched or sigpending) between sampling and the iret. - * Routines like schedule() or do_signal() may re-enable - * interrupts before returning. - */ - IRQ_DISABLE(r20, r21) - TRACE_IRQS_OFF /* Note: clobbers registers r0-r29 */ - - /* - * See if there are any work items (including single-shot items) - * to do. If so, save the callee-save registers to pt_regs - * and then dispatch to C code. - */ - move r21, sp - EXTRACT_THREAD_INFO(r21) - { - addi r22, r21, THREAD_INFO_FLAGS_OFFSET - moveli r20, hw1_last(_TIF_ALLWORK_MASK) - } - { - ld r22, r22 - shl16insli r20, r20, hw0(_TIF_ALLWORK_MASK) - } - and r1, r22, r20 - { - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - beqzt r1, .Lrestore_all - } - push_extra_callee_saves r0 - jal prepare_exit_to_usermode - - /* - * In the NMI case we - * omit the call to single_process_check_nohz, which normally checks - * to see if we should start or stop the scheduler tick, because - * we can't call arbitrary Linux code from an NMI context. - * We always call the homecache TLB deferral code to re-trigger - * the deferral mechanism. - * - * The other chunk of responsibility this code has is to reset the - * interrupt masks appropriately to reset irqs and NMIs. We have - * to call TRACE_IRQS_OFF and TRACE_IRQS_ON to support all the - * lockdep-type stuff, but we can't set ICS until afterwards, since - * ICS can only be used in very tight chunks of code to avoid - * tripping over various assertions that it is off. - */ -.Lrestore_all: - PTREGS_PTR(r0, PTREGS_OFFSET_EX1) - { - ld r0, r0 - PTREGS_PTR(r32, PTREGS_OFFSET_FLAGS) - } - { - IS_KERNEL_EX1(r0, r0) - ld r32, r32 - } - bnez r0, 1f - j 2f -#if PT_FLAGS_DISABLE_IRQ != 1 -# error Assuming PT_FLAGS_DISABLE_IRQ == 1 so we can use blbct below -#endif -1: blbct r32, 2f - IRQ_DISABLE(r20,r21) - TRACE_IRQS_OFF - movei r0, 1 - mtspr INTERRUPT_CRITICAL_SECTION, r0 - beqzt r30, .Lrestore_regs - j 3f -2: TRACE_IRQS_ON - IRQ_ENABLE_LOAD(r20, r21) - movei r0, 1 - mtspr INTERRUPT_CRITICAL_SECTION, r0 - IRQ_ENABLE_APPLY(r20, r21) - beqzt r30, .Lrestore_regs -3: - -#if INT_PERF_COUNT + 1 != INT_AUX_PERF_COUNT -# error Bad interrupt assumption -#endif - { - movei r0, 3 /* two adjacent bits for the PERF_COUNT mask */ - beqz r31, .Lrestore_regs - } - shli r0, r0, INT_PERF_COUNT - mtspr SPR_INTERRUPT_MASK_RESET_K, r0 - - /* - * We now commit to returning from this interrupt, since we will be - * doing things like setting EX_CONTEXT SPRs and unwinding the stack - * frame. No calls should be made to any other code after this point. - * This code should only be entered with ICS set. - * r32 must still be set to ptregs.flags. - * We launch loads to each cache line separately first, so we can - * get some parallelism out of the memory subsystem. - * We start zeroing caller-saved registers throughout, since - * that will save some cycles if this turns out to be a syscall. - */ -.Lrestore_regs: - - /* - * Rotate so we have one high bit and one low bit to test. - * - low bit says whether to restore all the callee-saved registers, - * or just r30-r33, and r52 up. - * - high bit (i.e. sign bit) says whether to restore all the - * caller-saved registers, or just r0. - */ -#if PT_FLAGS_CALLER_SAVES != 2 || PT_FLAGS_RESTORE_REGS != 4 -# error Rotate trick does not work :-) -#endif - { - rotli r20, r32, 62 - PTREGS_PTR(sp, PTREGS_OFFSET_REG(0)) - } - - /* - * Load cache lines 0, 4, 6 and 7, in that order, then use - * the last loaded value, which makes it likely that the other - * cache lines have also loaded, at which point we should be - * able to safely read all the remaining words on those cache - * lines without waiting for the memory subsystem. - */ - pop_reg r0, sp, PTREGS_OFFSET_REG(30) - PTREGS_OFFSET_REG(0) - pop_reg r30, sp, PTREGS_OFFSET_REG(52) - PTREGS_OFFSET_REG(30) - pop_reg_zero r52, r3, sp, PTREGS_OFFSET_CMPEXCH - PTREGS_OFFSET_REG(52) - pop_reg_zero r21, r27, sp, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_CMPEXCH - pop_reg_zero lr, r2, sp, PTREGS_OFFSET_PC - PTREGS_OFFSET_EX1 - { - mtspr CMPEXCH_VALUE, r21 - move r4, zero - } - pop_reg r21, sp, PTREGS_OFFSET_REG(31) - PTREGS_OFFSET_PC - { - mtspr SPR_EX_CONTEXT_K_1, lr - IS_KERNEL_EX1(lr, lr) - } - { - mtspr SPR_EX_CONTEXT_K_0, r21 - move r5, zero - } - - /* Restore callee-saveds that we actually use. */ - pop_reg_zero r31, r6 - pop_reg_zero r32, r7 - pop_reg_zero r33, r8, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(33) - - /* - * If we modified other callee-saveds, restore them now. - * This is rare, but could be via ptrace or signal handler. - */ - { - move r9, zero - blbs r20, .Lrestore_callees - } -.Lcontinue_restore_regs: - - /* Check if we're returning from a syscall. */ - { - move r10, zero - bltzt r20, 1f /* no, so go restore callee-save registers */ - } - - /* - * Check if we're returning to userspace. - * Note that if we're not, we don't worry about zeroing everything. - */ - { - addli sp, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(29) - bnez lr, .Lkernel_return - } - - /* - * On return from syscall, we've restored r0 from pt_regs, but we - * clear the remainder of the caller-saved registers. We could - * restore the syscall arguments, but there's not much point, - * and it ensures user programs aren't trying to use the - * caller-saves if we clear them, as well as avoiding leaking - * kernel pointers into userspace. - */ - pop_reg_zero lr, r11, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR - pop_reg_zero tp, r12, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP - { - ld sp, sp - move r13, zero - move r14, zero - } - { move r15, zero; move r16, zero } - { move r17, zero; move r18, zero } - { move r19, zero; move r20, zero } - { move r21, zero; move r22, zero } - { move r23, zero; move r24, zero } - { move r25, zero; move r26, zero } - - /* Set r1 to errno if we are returning an error, otherwise zero. */ - { - moveli r29, 4096 - sub r1, zero, r0 - } - { - move r28, zero - cmpltu r29, r1, r29 - } - { - mnz r1, r29, r1 - move r29, zero - } - iret - - /* - * Not a syscall, so restore caller-saved registers. - * First kick off loads for cache lines 1-3, which we're touching - * for the first time here. - */ - .align 64 -1: pop_reg r29, sp, PTREGS_OFFSET_REG(21) - PTREGS_OFFSET_REG(29) - pop_reg r21, sp, PTREGS_OFFSET_REG(13) - PTREGS_OFFSET_REG(21) - pop_reg r13, sp, PTREGS_OFFSET_REG(1) - PTREGS_OFFSET_REG(13) - pop_reg r1 - pop_reg r2 - pop_reg r3 - pop_reg r4 - pop_reg r5 - pop_reg r6 - pop_reg r7 - pop_reg r8 - pop_reg r9 - pop_reg r10 - pop_reg r11 - pop_reg r12, sp, 16 - /* r13 already restored above */ - pop_reg r14 - pop_reg r15 - pop_reg r16 - pop_reg r17 - pop_reg r18 - pop_reg r19 - pop_reg r20, sp, 16 - /* r21 already restored above */ - pop_reg r22 - pop_reg r23 - pop_reg r24 - pop_reg r25 - pop_reg r26 - pop_reg r27 - pop_reg r28, sp, PTREGS_OFFSET_LR - PTREGS_OFFSET_REG(28) - /* r29 already restored above */ - bnez lr, .Lkernel_return - pop_reg lr, sp, PTREGS_OFFSET_TP - PTREGS_OFFSET_LR - pop_reg tp, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_TP - ld sp, sp - iret - - /* - * We can't restore tp when in kernel mode, since a thread might - * have migrated from another cpu and brought a stale tp value. - */ -.Lkernel_return: - pop_reg lr, sp, PTREGS_OFFSET_SP - PTREGS_OFFSET_LR - ld sp, sp - iret - - /* Restore callee-saved registers from r34 to r51. */ -.Lrestore_callees: - addli sp, sp, PTREGS_OFFSET_REG(34) - PTREGS_OFFSET_REG(29) - pop_reg r34 - pop_reg r35 - pop_reg r36 - pop_reg r37 - pop_reg r38 - pop_reg r39 - pop_reg r40 - pop_reg r41 - pop_reg r42 - pop_reg r43 - pop_reg r44 - pop_reg r45 - pop_reg r46 - pop_reg r47 - pop_reg r48 - pop_reg r49 - pop_reg r50 - pop_reg r51, sp, PTREGS_OFFSET_REG(29) - PTREGS_OFFSET_REG(51) - j .Lcontinue_restore_regs - STD_ENDPROC(interrupt_return) - - /* - * "NMI" interrupts mask ALL interrupts before calling the - * handler, and don't check thread flags, etc., on the way - * back out. In general, the only things we do here for NMIs - * are register save/restore and dataplane kernel-TLB management. - * We don't (for example) deal with start/stop of the sched tick. - */ - .pushsection .text.handle_nmi,"ax" -handle_nmi: - finish_interrupt_save handle_nmi - { - jalr r0 - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - } - FEEDBACK_REENTER(handle_nmi) - { - movei r30, 1 - cmpeq r31, r0, zero - } - j interrupt_return - STD_ENDPROC(handle_nmi) - - /* - * Parallel code for syscalls to handle_interrupt. - */ - .pushsection .text.handle_syscall,"ax" -handle_syscall: - finish_interrupt_save handle_syscall - - /* Enable irqs. */ - TRACE_IRQS_ON - IRQ_ENABLE(r20, r21) - - /* Bump the counter for syscalls made on this tile. */ - moveli r20, hw2_last(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET) - shl16insli r20, r20, hw1(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET) - shl16insli r20, r20, hw0(irq_stat + IRQ_CPUSTAT_SYSCALL_COUNT_OFFSET) - add r20, r20, tp - ld4s r21, r20 - { - addi r21, r21, 1 - move r31, sp - } - { - st4 r20, r21 - EXTRACT_THREAD_INFO(r31) - } - - /* Trace syscalls, if requested. */ - addi r31, r31, THREAD_INFO_FLAGS_OFFSET - { - ld r30, r31 - moveli r32, _TIF_SYSCALL_ENTRY_WORK - } - and r30, r30, r32 - { - addi r30, r31, THREAD_INFO_STATUS_OFFSET - THREAD_INFO_FLAGS_OFFSET - beqzt r30, .Lrestore_syscall_regs - } - { - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - jal do_syscall_trace_enter - } - FEEDBACK_REENTER(handle_syscall) - bltz r0, .Lsyscall_sigreturn_skip - - /* - * We always reload our registers from the stack at this - * point. They might be valid, if we didn't build with - * TRACE_IRQFLAGS, and this isn't a dataplane tile, and we're not - * doing syscall tracing, but there are enough cases now that it - * seems simplest just to do the reload unconditionally. - */ -.Lrestore_syscall_regs: - { - ld r30, r30 - PTREGS_PTR(r11, PTREGS_OFFSET_REG(0)) - } - pop_reg r0, r11 - pop_reg r1, r11 - pop_reg r2, r11 - pop_reg r3, r11 - pop_reg r4, r11 - pop_reg r5, r11, PTREGS_OFFSET_SYSCALL - PTREGS_OFFSET_REG(5) - { - ld TREG_SYSCALL_NR_NAME, r11 - moveli r21, __NR_syscalls - } - - /* Ensure that the syscall number is within the legal range. */ - { - moveli r20, hw2(sys_call_table) -#ifdef CONFIG_COMPAT - blbs r30, .Lcompat_syscall -#endif - } - { - cmpltu r21, TREG_SYSCALL_NR_NAME, r21 - shl16insli r20, r20, hw1(sys_call_table) - } - { - blbc r21, .Linvalid_syscall - shl16insli r20, r20, hw0(sys_call_table) - } -.Lload_syscall_pointer: - shl3add r20, TREG_SYSCALL_NR_NAME, r20 - ld r20, r20 - - /* Jump to syscall handler. */ - jalr r20 -.Lhandle_syscall_link: /* value of "lr" after "jalr r20" above */ - - /* - * Write our r0 onto the stack so it gets restored instead - * of whatever the user had there before. - * In compat mode, sign-extend r0 before storing it. - */ - { - PTREGS_PTR(r29, PTREGS_OFFSET_REG(0)) - blbct r30, 1f - } - addxi r0, r0, 0 -1: st r29, r0 - -.Lsyscall_sigreturn_skip: - FEEDBACK_REENTER(handle_syscall) - - /* Do syscall trace again, if requested. */ - { - ld r30, r31 - moveli r32, _TIF_SYSCALL_EXIT_WORK - } - and r0, r30, r32 - { - andi r0, r30, _TIF_SINGLESTEP - beqzt r0, 1f - } - { - PTREGS_PTR(r0, PTREGS_OFFSET_BASE) - jal do_syscall_trace_exit - } - FEEDBACK_REENTER(handle_syscall) - andi r0, r30, _TIF_SINGLESTEP - -1: beqzt r0, 2f - - /* Single stepping -- notify ptrace. */ - { - movei r0, SIGTRAP - jal ptrace_notify - } - FEEDBACK_REENTER(handle_syscall) - -2: { - movei r30, 0 /* not an NMI */ - j .Lresume_userspace /* jump into middle of interrupt_return */ - } - -#ifdef CONFIG_COMPAT -.Lcompat_syscall: - /* - * Load the base of the compat syscall table in r20, and - * range-check the syscall number (duplicated from 64-bit path). - * Sign-extend all the user's passed arguments to make them consistent. - * Also save the original "r(n)" values away in "r(11+n)" in - * case the syscall table entry wants to validate them. - */ - moveli r20, hw2(compat_sys_call_table) - { - cmpltu r21, TREG_SYSCALL_NR_NAME, r21 - shl16insli r20, r20, hw1(compat_sys_call_table) - } - { - blbc r21, .Linvalid_syscall - shl16insli r20, r20, hw0(compat_sys_call_table) - } - { move r11, r0; addxi r0, r0, 0 } - { move r12, r1; addxi r1, r1, 0 } - { move r13, r2; addxi r2, r2, 0 } - { move r14, r3; addxi r3, r3, 0 } - { move r15, r4; addxi r4, r4, 0 } - { move r16, r5; addxi r5, r5, 0 } - j .Lload_syscall_pointer -#endif - -.Linvalid_syscall: - /* Report an invalid syscall back to the user program */ - { - PTREGS_PTR(r29, PTREGS_OFFSET_REG(0)) - movei r28, -ENOSYS - } - st r29, r28 - { - movei r30, 0 /* not an NMI */ - j .Lresume_userspace /* jump into middle of interrupt_return */ - } - STD_ENDPROC(handle_syscall) - - /* Return the address for oprofile to suppress in backtraces. */ -STD_ENTRY_SECTION(handle_syscall_link_address, .text.handle_syscall) - lnk r0 - { - addli r0, r0, .Lhandle_syscall_link - . - jrp lr - } - STD_ENDPROC(handle_syscall_link_address) - -STD_ENTRY(ret_from_fork) - jal sim_notify_fork - jal schedule_tail - FEEDBACK_REENTER(ret_from_fork) - { - movei r30, 0 /* not an NMI */ - j .Lresume_userspace /* jump into middle of interrupt_return */ - } - STD_ENDPROC(ret_from_fork) - -STD_ENTRY(ret_from_kernel_thread) - jal sim_notify_fork - jal schedule_tail - FEEDBACK_REENTER(ret_from_fork) - { - move r0, r31 - jalr r30 - } - FEEDBACK_REENTER(ret_from_kernel_thread) - { - movei r30, 0 /* not an NMI */ - j interrupt_return - } - STD_ENDPROC(ret_from_kernel_thread) - -/* Various stub interrupt handlers and syscall handlers */ - -STD_ENTRY_LOCAL(_kernel_double_fault) - mfspr r1, SPR_EX_CONTEXT_K_0 - move r2, lr - move r3, sp - move r4, r52 - addi sp, sp, -C_ABI_SAVE_AREA_SIZE - j kernel_double_fault - STD_ENDPROC(_kernel_double_fault) - -STD_ENTRY_LOCAL(bad_intr) - mfspr r2, SPR_EX_CONTEXT_K_0 - panic "Unhandled interrupt %#x: PC %#lx" - STD_ENDPROC(bad_intr) - -/* - * Special-case sigreturn to not write r0 to the stack on return. - * This is technically more efficient, but it also avoids difficulties - * in the 64-bit OS when handling 32-bit compat code, since we must not - * sign-extend r0 for the sigreturn return-value case. - */ -#define PTREGS_SYSCALL_SIGRETURN(x, reg) \ - STD_ENTRY(_##x); \ - addli lr, lr, .Lsyscall_sigreturn_skip - .Lhandle_syscall_link; \ - { \ - PTREGS_PTR(reg, PTREGS_OFFSET_BASE); \ - j x \ - }; \ - STD_ENDPROC(_##x) - -PTREGS_SYSCALL_SIGRETURN(sys_rt_sigreturn, r0) -#ifdef CONFIG_COMPAT -PTREGS_SYSCALL_SIGRETURN(compat_sys_rt_sigreturn, r0) -#endif - -/* Save additional callee-saves to pt_regs and jump to standard function. */ -STD_ENTRY(_sys_clone) - push_extra_callee_saves r4 - j sys_clone - STD_ENDPROC(_sys_clone) - - /* - * Recover r3, r2, r1 and r0 here saved by unalign fast vector. - * The vector area limit is 32 bundles, so we handle the reload here. - * r0, r1, r2 are in thread_info from low to high memory in order. - * r3 points to location the original r3 was saved. - * We put this code in the __HEAD section so it can be reached - * via a conditional branch from the fast path. - */ - __HEAD -hand_unalign_slow: - andi sp, sp, ~1 -hand_unalign_slow_badsp: - addi r3, r3, -(3 * 8) - ld_add r0, r3, 8 - ld_add r1, r3, 8 - ld r2, r3 -hand_unalign_slow_nonuser: - mfspr r3, SPR_SYSTEM_SAVE_K_1 - __int_hand INT_UNALIGN_DATA, UNALIGN_DATA_SLOW, int_unalign - -/* The unaligned data support needs to read all the registers. */ -int_unalign: - push_extra_callee_saves r0 - j do_unaligned -ENDPROC(hand_unalign_slow) - -/* Fill the return address stack with nonzero entries. */ -STD_ENTRY(fill_ra_stack) - { - move r0, lr - jal 1f - } -1: jal 2f -2: jal 3f -3: jal 4f -4: jrp r0 - STD_ENDPROC(fill_ra_stack) - - .macro int_hand vecnum, vecname, c_routine, processing=handle_interrupt - .org (\vecnum << 8) - __int_hand \vecnum, \vecname, \c_routine, \processing - .endm - -/* Include .intrpt array of interrupt vectors */ - .section ".intrpt", "ax" - .global intrpt_start -intrpt_start: - -#ifndef CONFIG_USE_PMC -#define handle_perf_interrupt bad_intr -#endif - -#ifndef CONFIG_HARDWALL -#define do_hardwall_trap bad_intr -#endif - - int_hand INT_MEM_ERROR, MEM_ERROR, do_trap - int_hand INT_SINGLE_STEP_3, SINGLE_STEP_3, bad_intr -#if CONFIG_KERNEL_PL == 2 - int_hand INT_SINGLE_STEP_2, SINGLE_STEP_2, gx_singlestep_handle - int_hand INT_SINGLE_STEP_1, SINGLE_STEP_1, bad_intr -#else - int_hand INT_SINGLE_STEP_2, SINGLE_STEP_2, bad_intr - int_hand INT_SINGLE_STEP_1, SINGLE_STEP_1, gx_singlestep_handle -#endif - int_hand INT_SINGLE_STEP_0, SINGLE_STEP_0, bad_intr - int_hand INT_IDN_COMPLETE, IDN_COMPLETE, bad_intr - int_hand INT_UDN_COMPLETE, UDN_COMPLETE, bad_intr - int_hand INT_ITLB_MISS, ITLB_MISS, do_page_fault - int_hand INT_ILL, ILL, do_trap - int_hand INT_GPV, GPV, do_trap - int_hand INT_IDN_ACCESS, IDN_ACCESS, do_trap - int_hand INT_UDN_ACCESS, UDN_ACCESS, do_trap - int_hand INT_SWINT_3, SWINT_3, do_trap - int_hand INT_SWINT_2, SWINT_2, do_trap - int_hand INT_SWINT_1, SWINT_1, SYSCALL, handle_syscall - int_hand INT_SWINT_0, SWINT_0, do_trap - int_hand INT_ILL_TRANS, ILL_TRANS, do_trap - int_hand_unalign_fast INT_UNALIGN_DATA, UNALIGN_DATA - int_hand INT_DTLB_MISS, DTLB_MISS, do_page_fault - int_hand INT_DTLB_ACCESS, DTLB_ACCESS, do_page_fault - int_hand INT_IDN_FIREWALL, IDN_FIREWALL, do_hardwall_trap - int_hand INT_UDN_FIREWALL, UDN_FIREWALL, do_hardwall_trap - int_hand INT_TILE_TIMER, TILE_TIMER, do_timer_interrupt - int_hand INT_IDN_TIMER, IDN_TIMER, bad_intr - int_hand INT_UDN_TIMER, UDN_TIMER, bad_intr - int_hand INT_IDN_AVAIL, IDN_AVAIL, bad_intr - int_hand INT_UDN_AVAIL, UDN_AVAIL, bad_intr - int_hand INT_IPI_3, IPI_3, bad_intr -#if CONFIG_KERNEL_PL == 2 - int_hand INT_IPI_2, IPI_2, tile_dev_intr - int_hand INT_IPI_1, IPI_1, bad_intr -#else - int_hand INT_IPI_2, IPI_2, bad_intr - int_hand INT_IPI_1, IPI_1, tile_dev_intr -#endif - int_hand INT_IPI_0, IPI_0, bad_intr - int_hand INT_PERF_COUNT, PERF_COUNT, \ - handle_perf_interrupt, handle_nmi - int_hand INT_AUX_PERF_COUNT, AUX_PERF_COUNT, \ - handle_perf_interrupt, handle_nmi - int_hand INT_INTCTRL_3, INTCTRL_3, bad_intr -#if CONFIG_KERNEL_PL == 2 - dc_dispatch INT_INTCTRL_2, INTCTRL_2 - int_hand INT_INTCTRL_1, INTCTRL_1, bad_intr -#else - int_hand INT_INTCTRL_2, INTCTRL_2, bad_intr - dc_dispatch INT_INTCTRL_1, INTCTRL_1 -#endif - int_hand INT_INTCTRL_0, INTCTRL_0, bad_intr - int_hand INT_MESSAGE_RCV_DWNCL, MESSAGE_RCV_DWNCL, \ - hv_message_intr - int_hand INT_DEV_INTR_DWNCL, DEV_INTR_DWNCL, bad_intr - int_hand INT_I_ASID, I_ASID, bad_intr - int_hand INT_D_ASID, D_ASID, bad_intr - int_hand INT_DOUBLE_FAULT, DOUBLE_FAULT, do_trap - - /* Synthetic interrupt delivered only by the simulator */ - int_hand INT_BREAKPOINT, BREAKPOINT, do_breakpoint - /* Synthetic interrupt delivered by hv */ - int_hand INT_NMI_DWNCL, NMI_DWNCL, do_nmi, handle_nmi diff --git a/arch/tile/kernel/irq.c b/arch/tile/kernel/irq.c deleted file mode 100644 index 22044fc691ef..000000000000 --- a/arch/tile/kernel/irq.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Bit-flag stored in irq_desc->chip_data to indicate HW-cleared irqs. */ -#define IS_HW_CLEARED 1 - -/* - * The set of interrupts we enable for arch_local_irq_enable(). - * This is initialized to have just a single interrupt that the kernel - * doesn't actually use as a sentinel. During kernel init, - * interrupts are added as the kernel gets prepared to support them. - * NOTE: we could probably initialize them all statically up front. - */ -DEFINE_PER_CPU(unsigned long long, interrupts_enabled_mask) = - INITIAL_INTERRUPTS_ENABLED; -EXPORT_PER_CPU_SYMBOL(interrupts_enabled_mask); - -/* Define per-tile device interrupt statistics state. */ -DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_internodealigned_in_smp; -EXPORT_PER_CPU_SYMBOL(irq_stat); - -/* - * Define per-tile irq disable mask; the hardware/HV only has a single - * mask that we use to implement both masking and disabling. - */ -static DEFINE_PER_CPU(unsigned long, irq_disable_mask) - ____cacheline_internodealigned_in_smp; - -/* - * Per-tile IRQ nesting depth. Used to make sure we enable newly - * enabled IRQs before exiting the outermost interrupt. - */ -static DEFINE_PER_CPU(int, irq_depth); - -#if CHIP_HAS_IPI() -/* Use SPRs to manipulate device interrupts. */ -#define mask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_SET_K, irq_mask) -#define unmask_irqs(irq_mask) __insn_mtspr(SPR_IPI_MASK_RESET_K, irq_mask) -#define clear_irqs(irq_mask) __insn_mtspr(SPR_IPI_EVENT_RESET_K, irq_mask) -#else -/* Use HV to manipulate device interrupts. */ -#define mask_irqs(irq_mask) hv_disable_intr(irq_mask) -#define unmask_irqs(irq_mask) hv_enable_intr(irq_mask) -#define clear_irqs(irq_mask) hv_clear_intr(irq_mask) -#endif - -/* - * The interrupt handling path, implemented in terms of HV interrupt - * emulation on TILEPro, and IPI hardware on TILE-Gx. - * Entered with interrupts disabled. - */ -void tile_dev_intr(struct pt_regs *regs, int intnum) -{ - int depth = __this_cpu_inc_return(irq_depth); - unsigned long original_irqs; - unsigned long remaining_irqs; - struct pt_regs *old_regs; - -#if CHIP_HAS_IPI() - /* - * Pending interrupts are listed in an SPR. We might be - * nested, so be sure to only handle irqs that weren't already - * masked by a previous interrupt. Then, mask out the ones - * we're going to handle. - */ - unsigned long masked = __insn_mfspr(SPR_IPI_MASK_K); - original_irqs = __insn_mfspr(SPR_IPI_EVENT_K) & ~masked; - __insn_mtspr(SPR_IPI_MASK_SET_K, original_irqs); -#else - /* - * Hypervisor performs the equivalent of the Gx code above and - * then puts the pending interrupt mask into a system save reg - * for us to find. - */ - original_irqs = __insn_mfspr(SPR_SYSTEM_SAVE_K_3); -#endif - remaining_irqs = original_irqs; - - /* Track time spent here in an interrupt context. */ - old_regs = set_irq_regs(regs); - irq_enter(); - -#ifdef CONFIG_DEBUG_STACKOVERFLOW - /* Debugging check for stack overflow: less than 1/8th stack free? */ - { - long sp = stack_pointer - (long) current_thread_info(); - if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) { - pr_emerg("%s: stack overflow: %ld\n", - __func__, sp - sizeof(struct thread_info)); - dump_stack(); - } - } -#endif - while (remaining_irqs) { - unsigned long irq = __ffs(remaining_irqs); - remaining_irqs &= ~(1UL << irq); - - /* Count device irqs; Linux IPIs are counted elsewhere. */ - if (irq != IRQ_RESCHEDULE) - __this_cpu_inc(irq_stat.irq_dev_intr_count); - - generic_handle_irq(irq); - } - - /* - * If we weren't nested, turn on all enabled interrupts, - * including any that were reenabled during interrupt - * handling. - */ - if (depth == 1) - unmask_irqs(~__this_cpu_read(irq_disable_mask)); - - __this_cpu_dec(irq_depth); - - /* - * Track time spent against the current process again and - * process any softirqs if they are waiting. - */ - irq_exit(); - set_irq_regs(old_regs); -} - - -/* - * Remove an irq from the disabled mask. If we're in an interrupt - * context, defer enabling the HW interrupt until we leave. - */ -static void tile_irq_chip_enable(struct irq_data *d) -{ - get_cpu_var(irq_disable_mask) &= ~(1UL << d->irq); - if (__this_cpu_read(irq_depth) == 0) - unmask_irqs(1UL << d->irq); - put_cpu_var(irq_disable_mask); -} - -/* - * Add an irq to the disabled mask. We disable the HW interrupt - * immediately so that there's no possibility of it firing. If we're - * in an interrupt context, the return path is careful to avoid - * unmasking a newly disabled interrupt. - */ -static void tile_irq_chip_disable(struct irq_data *d) -{ - get_cpu_var(irq_disable_mask) |= (1UL << d->irq); - mask_irqs(1UL << d->irq); - put_cpu_var(irq_disable_mask); -} - -/* Mask an interrupt. */ -static void tile_irq_chip_mask(struct irq_data *d) -{ - mask_irqs(1UL << d->irq); -} - -/* Unmask an interrupt. */ -static void tile_irq_chip_unmask(struct irq_data *d) -{ - unmask_irqs(1UL << d->irq); -} - -/* - * Clear an interrupt before processing it so that any new assertions - * will trigger another irq. - */ -static void tile_irq_chip_ack(struct irq_data *d) -{ - if ((unsigned long)irq_data_get_irq_chip_data(d) != IS_HW_CLEARED) - clear_irqs(1UL << d->irq); -} - -/* - * For per-cpu interrupts, we need to avoid unmasking any interrupts - * that we disabled via disable_percpu_irq(). - */ -static void tile_irq_chip_eoi(struct irq_data *d) -{ - if (!(__this_cpu_read(irq_disable_mask) & (1UL << d->irq))) - unmask_irqs(1UL << d->irq); -} - -static struct irq_chip tile_irq_chip = { - .name = "tile_irq_chip", - .irq_enable = tile_irq_chip_enable, - .irq_disable = tile_irq_chip_disable, - .irq_ack = tile_irq_chip_ack, - .irq_eoi = tile_irq_chip_eoi, - .irq_mask = tile_irq_chip_mask, - .irq_unmask = tile_irq_chip_unmask, -}; - -void __init init_IRQ(void) -{ - ipi_init(); -} - -void setup_irq_regs(void) -{ - /* Enable interrupt delivery. */ - unmask_irqs(~0UL); -#if CHIP_HAS_IPI() - arch_local_irq_unmask(INT_IPI_K); -#endif -} - -void tile_irq_activate(unsigned int irq, int tile_irq_type) -{ - /* - * We use handle_level_irq() by default because the pending - * interrupt vector (whether modeled by the HV on - * TILEPro or implemented in hardware on TILE-Gx) has - * level-style semantics for each bit. An interrupt fires - * whenever a bit is high, not just at edges. - */ - irq_flow_handler_t handle = handle_level_irq; - if (tile_irq_type == TILE_IRQ_PERCPU) - handle = handle_percpu_irq; - irq_set_chip_and_handler(irq, &tile_irq_chip, handle); - - /* - * Flag interrupts that are hardware-cleared so that ack() - * won't clear them. - */ - if (tile_irq_type == TILE_IRQ_HW_CLEAR) - irq_set_chip_data(irq, (void *)IS_HW_CLEARED); -} -EXPORT_SYMBOL(tile_irq_activate); - - -void ack_bad_irq(unsigned int irq) -{ - pr_err("unexpected IRQ trap at vector %02x\n", irq); -} - -/* - * /proc/interrupts printing: - */ -int arch_show_interrupts(struct seq_file *p, int prec) -{ -#ifdef CONFIG_PERF_EVENTS - int i; - - seq_printf(p, "%*s: ", prec, "PMI"); - - for_each_online_cpu(i) - seq_printf(p, "%10llu ", per_cpu(perf_irqs, i)); - seq_puts(p, " perf_events\n"); -#endif - return 0; -} - -#if CHIP_HAS_IPI() -int arch_setup_hwirq(unsigned int irq, int node) -{ - return irq >= NR_IRQS ? -EINVAL : 0; -} - -void arch_teardown_hwirq(unsigned int irq) { } -#endif diff --git a/arch/tile/kernel/jump_label.c b/arch/tile/kernel/jump_label.c deleted file mode 100644 index 93931a46625b..000000000000 --- a/arch/tile/kernel/jump_label.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * jump label TILE-Gx support - */ - -#include -#include -#include -#include -#include - -#include -#include - -#ifdef HAVE_JUMP_LABEL - -static void __jump_label_transform(struct jump_entry *e, - enum jump_label_type type) -{ - tilegx_bundle_bits opcode; - /* Operate on writable kernel text mapping. */ - unsigned long pc_wr = ktext_writable_addr(e->code); - - if (type == JUMP_LABEL_JMP) - opcode = tilegx_gen_branch(e->code, e->target, false); - else - opcode = NOP(); - - *(tilegx_bundle_bits *)pc_wr = opcode; - /* Make sure that above mem writes were issued towards the memory. */ - smp_wmb(); -} - -void arch_jump_label_transform(struct jump_entry *e, - enum jump_label_type type) -{ - mutex_lock(&text_mutex); - - __jump_label_transform(e, type); - flush_icache_range(e->code, e->code + sizeof(tilegx_bundle_bits)); - - mutex_unlock(&text_mutex); -} - -__init_or_module void arch_jump_label_transform_static(struct jump_entry *e, - enum jump_label_type type) -{ - __jump_label_transform(e, type); -} - -#endif /* HAVE_JUMP_LABEL */ diff --git a/arch/tile/kernel/kgdb.c b/arch/tile/kernel/kgdb.c deleted file mode 100644 index d4eb5fb2df9d..000000000000 --- a/arch/tile/kernel/kgdb.c +++ /dev/null @@ -1,497 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * TILE-Gx KGDB support. - */ - -#include -#include -#include -#include -#include -#include - -#include - -static tile_bundle_bits singlestep_insn = TILEGX_BPT_BUNDLE | DIE_SSTEPBP; -static unsigned long stepped_addr; -static tile_bundle_bits stepped_instr; - -struct dbg_reg_def_t dbg_reg_def[DBG_MAX_REG_NUM] = { - { "r0", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[0])}, - { "r1", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[1])}, - { "r2", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[2])}, - { "r3", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[3])}, - { "r4", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[4])}, - { "r5", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[5])}, - { "r6", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[6])}, - { "r7", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[7])}, - { "r8", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[8])}, - { "r9", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[9])}, - { "r10", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[10])}, - { "r11", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[11])}, - { "r12", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[12])}, - { "r13", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[13])}, - { "r14", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[14])}, - { "r15", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[15])}, - { "r16", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[16])}, - { "r17", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[17])}, - { "r18", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[18])}, - { "r19", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[19])}, - { "r20", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[20])}, - { "r21", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[21])}, - { "r22", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[22])}, - { "r23", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[23])}, - { "r24", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[24])}, - { "r25", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[25])}, - { "r26", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[26])}, - { "r27", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[27])}, - { "r28", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[28])}, - { "r29", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[29])}, - { "r30", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[30])}, - { "r31", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[31])}, - { "r32", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[32])}, - { "r33", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[33])}, - { "r34", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[34])}, - { "r35", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[35])}, - { "r36", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[36])}, - { "r37", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[37])}, - { "r38", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[38])}, - { "r39", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[39])}, - { "r40", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[40])}, - { "r41", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[41])}, - { "r42", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[42])}, - { "r43", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[43])}, - { "r44", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[44])}, - { "r45", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[45])}, - { "r46", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[46])}, - { "r47", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[47])}, - { "r48", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[48])}, - { "r49", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[49])}, - { "r50", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[50])}, - { "r51", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[51])}, - { "r52", GDB_SIZEOF_REG, offsetof(struct pt_regs, regs[52])}, - { "tp", GDB_SIZEOF_REG, offsetof(struct pt_regs, tp)}, - { "sp", GDB_SIZEOF_REG, offsetof(struct pt_regs, sp)}, - { "lr", GDB_SIZEOF_REG, offsetof(struct pt_regs, lr)}, - { "sn", GDB_SIZEOF_REG, -1}, - { "idn0", GDB_SIZEOF_REG, -1}, - { "idn1", GDB_SIZEOF_REG, -1}, - { "udn0", GDB_SIZEOF_REG, -1}, - { "udn1", GDB_SIZEOF_REG, -1}, - { "udn2", GDB_SIZEOF_REG, -1}, - { "udn3", GDB_SIZEOF_REG, -1}, - { "zero", GDB_SIZEOF_REG, -1}, - { "pc", GDB_SIZEOF_REG, offsetof(struct pt_regs, pc)}, - { "faultnum", GDB_SIZEOF_REG, offsetof(struct pt_regs, faultnum)}, -}; - -char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs) -{ - if (regno >= DBG_MAX_REG_NUM || regno < 0) - return NULL; - - if (dbg_reg_def[regno].offset != -1) - memcpy(mem, (void *)regs + dbg_reg_def[regno].offset, - dbg_reg_def[regno].size); - else - memset(mem, 0, dbg_reg_def[regno].size); - return dbg_reg_def[regno].name; -} - -int dbg_set_reg(int regno, void *mem, struct pt_regs *regs) -{ - if (regno >= DBG_MAX_REG_NUM || regno < 0) - return -EINVAL; - - if (dbg_reg_def[regno].offset != -1) - memcpy((void *)regs + dbg_reg_def[regno].offset, mem, - dbg_reg_def[regno].size); - return 0; -} - -/* - * Similar to pt_regs_to_gdb_regs() except that process is sleeping and so - * we may not be able to get all the info. - */ -void -sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *task) -{ - struct pt_regs *thread_regs; - const int NGPRS = TREG_LAST_GPR + 1; - - if (task == NULL) - return; - - thread_regs = task_pt_regs(task); - memcpy(gdb_regs, thread_regs, NGPRS * sizeof(unsigned long)); - memset(&gdb_regs[NGPRS], 0, - (TILEGX_PC_REGNUM - NGPRS) * sizeof(unsigned long)); - gdb_regs[TILEGX_PC_REGNUM] = thread_regs->pc; - gdb_regs[TILEGX_FAULTNUM_REGNUM] = thread_regs->faultnum; -} - -void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc) -{ - regs->pc = pc; -} - -static void kgdb_call_nmi_hook(void *ignored) -{ - kgdb_nmicallback(raw_smp_processor_id(), NULL); -} - -void kgdb_roundup_cpus(unsigned long flags) -{ - local_irq_enable(); - smp_call_function(kgdb_call_nmi_hook, NULL, 0); - local_irq_disable(); -} - -/* - * Convert a kernel address to the writable kernel text mapping. - */ -static unsigned long writable_address(unsigned long addr) -{ - unsigned long ret = 0; - - if (core_kernel_text(addr)) - ret = ktext_writable_addr(addr); - else if (is_module_text_address(addr)) - ret = addr; - else - pr_err("Unknown virtual address 0x%lx\n", addr); - - return ret; -} - -/* - * Calculate the new address for after a step. - */ -static unsigned long get_step_address(struct pt_regs *regs) -{ - int src_reg; - int jump_off; - int br_off; - unsigned long addr; - unsigned int opcode; - tile_bundle_bits bundle; - - /* Move to the next instruction by default. */ - addr = regs->pc + TILEGX_BUNDLE_SIZE_IN_BYTES; - bundle = *(unsigned long *)instruction_pointer(regs); - - /* 0: X mode, Otherwise: Y mode. */ - if (bundle & TILEGX_BUNDLE_MODE_MASK) { - if (get_Opcode_Y1(bundle) == RRR_1_OPCODE_Y1 && - get_RRROpcodeExtension_Y1(bundle) == - UNARY_RRR_1_OPCODE_Y1) { - opcode = get_UnaryOpcodeExtension_Y1(bundle); - - switch (opcode) { - case JALR_UNARY_OPCODE_Y1: - case JALRP_UNARY_OPCODE_Y1: - case JR_UNARY_OPCODE_Y1: - case JRP_UNARY_OPCODE_Y1: - src_reg = get_SrcA_Y1(bundle); - dbg_get_reg(src_reg, &addr, regs); - break; - } - } - } else if (get_Opcode_X1(bundle) == RRR_0_OPCODE_X1) { - if (get_RRROpcodeExtension_X1(bundle) == - UNARY_RRR_0_OPCODE_X1) { - opcode = get_UnaryOpcodeExtension_X1(bundle); - - switch (opcode) { - case JALR_UNARY_OPCODE_X1: - case JALRP_UNARY_OPCODE_X1: - case JR_UNARY_OPCODE_X1: - case JRP_UNARY_OPCODE_X1: - src_reg = get_SrcA_X1(bundle); - dbg_get_reg(src_reg, &addr, regs); - break; - } - } - } else if (get_Opcode_X1(bundle) == JUMP_OPCODE_X1) { - opcode = get_JumpOpcodeExtension_X1(bundle); - - switch (opcode) { - case JAL_JUMP_OPCODE_X1: - case J_JUMP_OPCODE_X1: - jump_off = sign_extend(get_JumpOff_X1(bundle), 27); - addr = regs->pc + - (jump_off << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES); - break; - } - } else if (get_Opcode_X1(bundle) == BRANCH_OPCODE_X1) { - br_off = 0; - opcode = get_BrType_X1(bundle); - - switch (opcode) { - case BEQZT_BRANCH_OPCODE_X1: - case BEQZ_BRANCH_OPCODE_X1: - if (get_SrcA_X1(bundle) == 0) - br_off = get_BrOff_X1(bundle); - break; - case BGEZT_BRANCH_OPCODE_X1: - case BGEZ_BRANCH_OPCODE_X1: - if (get_SrcA_X1(bundle) >= 0) - br_off = get_BrOff_X1(bundle); - break; - case BGTZT_BRANCH_OPCODE_X1: - case BGTZ_BRANCH_OPCODE_X1: - if (get_SrcA_X1(bundle) > 0) - br_off = get_BrOff_X1(bundle); - break; - case BLBCT_BRANCH_OPCODE_X1: - case BLBC_BRANCH_OPCODE_X1: - if (!(get_SrcA_X1(bundle) & 1)) - br_off = get_BrOff_X1(bundle); - break; - case BLBST_BRANCH_OPCODE_X1: - case BLBS_BRANCH_OPCODE_X1: - if (get_SrcA_X1(bundle) & 1) - br_off = get_BrOff_X1(bundle); - break; - case BLEZT_BRANCH_OPCODE_X1: - case BLEZ_BRANCH_OPCODE_X1: - if (get_SrcA_X1(bundle) <= 0) - br_off = get_BrOff_X1(bundle); - break; - case BLTZT_BRANCH_OPCODE_X1: - case BLTZ_BRANCH_OPCODE_X1: - if (get_SrcA_X1(bundle) < 0) - br_off = get_BrOff_X1(bundle); - break; - case BNEZT_BRANCH_OPCODE_X1: - case BNEZ_BRANCH_OPCODE_X1: - if (get_SrcA_X1(bundle) != 0) - br_off = get_BrOff_X1(bundle); - break; - } - - if (br_off != 0) { - br_off = sign_extend(br_off, 17); - addr = regs->pc + - (br_off << TILEGX_LOG2_BUNDLE_SIZE_IN_BYTES); - } - } - - return addr; -} - -/* - * Replace the next instruction after the current instruction with a - * breakpoint instruction. - */ -static void do_single_step(struct pt_regs *regs) -{ - unsigned long addr_wr; - - /* Determine where the target instruction will send us to. */ - stepped_addr = get_step_address(regs); - probe_kernel_read((char *)&stepped_instr, (char *)stepped_addr, - BREAK_INSTR_SIZE); - - addr_wr = writable_address(stepped_addr); - probe_kernel_write((char *)addr_wr, (char *)&singlestep_insn, - BREAK_INSTR_SIZE); - smp_wmb(); - flush_icache_range(stepped_addr, stepped_addr + BREAK_INSTR_SIZE); -} - -static void undo_single_step(struct pt_regs *regs) -{ - unsigned long addr_wr; - - if (stepped_instr == 0) - return; - - addr_wr = writable_address(stepped_addr); - probe_kernel_write((char *)addr_wr, (char *)&stepped_instr, - BREAK_INSTR_SIZE); - stepped_instr = 0; - smp_wmb(); - flush_icache_range(stepped_addr, stepped_addr + BREAK_INSTR_SIZE); -} - -/* - * Calls linux_debug_hook before the kernel dies. If KGDB is enabled, - * then try to fall into the debugger. - */ -static int -kgdb_notify(struct notifier_block *self, unsigned long cmd, void *ptr) -{ - int ret; - unsigned long flags; - struct die_args *args = (struct die_args *)ptr; - struct pt_regs *regs = args->regs; - -#ifdef CONFIG_KPROBES - /* - * Return immediately if the kprobes fault notifier has set - * DIE_PAGE_FAULT. - */ - if (cmd == DIE_PAGE_FAULT) - return NOTIFY_DONE; -#endif /* CONFIG_KPROBES */ - - switch (cmd) { - case DIE_BREAK: - case DIE_COMPILED_BPT: - break; - case DIE_SSTEPBP: - local_irq_save(flags); - kgdb_handle_exception(0, SIGTRAP, 0, regs); - local_irq_restore(flags); - return NOTIFY_STOP; - default: - /* Userspace events, ignore. */ - if (user_mode(regs)) - return NOTIFY_DONE; - } - - local_irq_save(flags); - ret = kgdb_handle_exception(args->trapnr, args->signr, args->err, regs); - local_irq_restore(flags); - if (ret) - return NOTIFY_DONE; - - return NOTIFY_STOP; -} - -static struct notifier_block kgdb_notifier = { - .notifier_call = kgdb_notify, -}; - -/* - * kgdb_arch_handle_exception - Handle architecture specific GDB packets. - * @vector: The error vector of the exception that happened. - * @signo: The signal number of the exception that happened. - * @err_code: The error code of the exception that happened. - * @remcom_in_buffer: The buffer of the packet we have read. - * @remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into. - * @regs: The &struct pt_regs of the current process. - * - * This function MUST handle the 'c' and 's' command packets, - * as well packets to set / remove a hardware breakpoint, if used. - * If there are additional packets which the hardware needs to handle, - * they are handled here. The code should return -1 if it wants to - * process more packets, and a %0 or %1 if it wants to exit from the - * kgdb callback. - */ -int kgdb_arch_handle_exception(int vector, int signo, int err_code, - char *remcom_in_buffer, char *remcom_out_buffer, - struct pt_regs *regs) -{ - char *ptr; - unsigned long address; - - /* Undo any stepping we may have done. */ - undo_single_step(regs); - - switch (remcom_in_buffer[0]) { - case 'c': - case 's': - case 'D': - case 'k': - /* - * Try to read optional parameter, pc unchanged if no parm. - * If this was a compiled-in breakpoint, we need to move - * to the next instruction or we will just breakpoint - * over and over again. - */ - ptr = &remcom_in_buffer[1]; - if (kgdb_hex2long(&ptr, &address)) - regs->pc = address; - else if (*(unsigned long *)regs->pc == compiled_bpt) - regs->pc += BREAK_INSTR_SIZE; - - if (remcom_in_buffer[0] == 's') { - do_single_step(regs); - kgdb_single_step = 1; - atomic_set(&kgdb_cpu_doing_single_step, - raw_smp_processor_id()); - } else - atomic_set(&kgdb_cpu_doing_single_step, -1); - - return 0; - } - - return -1; /* this means that we do not want to exit from the handler */ -} - -struct kgdb_arch arch_kgdb_ops; - -/* - * kgdb_arch_init - Perform any architecture specific initialization. - * - * This function will handle the initialization of any architecture - * specific callbacks. - */ -int kgdb_arch_init(void) -{ - tile_bundle_bits bundle = TILEGX_BPT_BUNDLE; - - memcpy(arch_kgdb_ops.gdb_bpt_instr, &bundle, BREAK_INSTR_SIZE); - return register_die_notifier(&kgdb_notifier); -} - -/* - * kgdb_arch_exit - Perform any architecture specific uninitialization. - * - * This function will handle the uninitialization of any architecture - * specific callbacks, for dynamic registration and unregistration. - */ -void kgdb_arch_exit(void) -{ - unregister_die_notifier(&kgdb_notifier); -} - -int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt) -{ - int err; - unsigned long addr_wr = writable_address(bpt->bpt_addr); - - if (addr_wr == 0) - return -1; - - err = probe_kernel_read(bpt->saved_instr, (char *)bpt->bpt_addr, - BREAK_INSTR_SIZE); - if (err) - return err; - - err = probe_kernel_write((char *)addr_wr, arch_kgdb_ops.gdb_bpt_instr, - BREAK_INSTR_SIZE); - smp_wmb(); - flush_icache_range((unsigned long)bpt->bpt_addr, - (unsigned long)bpt->bpt_addr + BREAK_INSTR_SIZE); - return err; -} - -int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt) -{ - int err; - unsigned long addr_wr = writable_address(bpt->bpt_addr); - - if (addr_wr == 0) - return -1; - - err = probe_kernel_write((char *)addr_wr, (char *)bpt->saved_instr, - BREAK_INSTR_SIZE); - smp_wmb(); - flush_icache_range((unsigned long)bpt->bpt_addr, - (unsigned long)bpt->bpt_addr + BREAK_INSTR_SIZE); - return err; -} diff --git a/arch/tile/kernel/kprobes.c b/arch/tile/kernel/kprobes.c deleted file mode 100644 index c68694bb1ad2..000000000000 --- a/arch/tile/kernel/kprobes.c +++ /dev/null @@ -1,527 +0,0 @@ -/* - * arch/tile/kernel/kprobes.c - * Kprobes on TILE-Gx - * - * Some portions copied from the MIPS version. - * - * Copyright (C) IBM Corporation, 2002, 2004 - * Copyright 2006 Sony Corp. - * Copyright 2010 Cavium Networks - * - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include - -#include - -DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; -DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); - -tile_bundle_bits breakpoint_insn = TILEGX_BPT_BUNDLE; -tile_bundle_bits breakpoint2_insn = TILEGX_BPT_BUNDLE | DIE_SSTEPBP; - -/* - * Check whether instruction is branch or jump, or if executing it - * has different results depending on where it is executed (e.g. lnk). - */ -static int __kprobes insn_has_control(kprobe_opcode_t insn) -{ - if (get_Mode(insn) != 0) { /* Y-format bundle */ - if (get_Opcode_Y1(insn) != RRR_1_OPCODE_Y1 || - get_RRROpcodeExtension_Y1(insn) != UNARY_RRR_1_OPCODE_Y1) - return 0; - - switch (get_UnaryOpcodeExtension_Y1(insn)) { - case JALRP_UNARY_OPCODE_Y1: - case JALR_UNARY_OPCODE_Y1: - case JRP_UNARY_OPCODE_Y1: - case JR_UNARY_OPCODE_Y1: - case LNK_UNARY_OPCODE_Y1: - return 1; - default: - return 0; - } - } - - switch (get_Opcode_X1(insn)) { - case BRANCH_OPCODE_X1: /* branch instructions */ - case JUMP_OPCODE_X1: /* jump instructions: j and jal */ - return 1; - - case RRR_0_OPCODE_X1: /* other jump instructions */ - if (get_RRROpcodeExtension_X1(insn) != UNARY_RRR_0_OPCODE_X1) - return 0; - switch (get_UnaryOpcodeExtension_X1(insn)) { - case JALRP_UNARY_OPCODE_X1: - case JALR_UNARY_OPCODE_X1: - case JRP_UNARY_OPCODE_X1: - case JR_UNARY_OPCODE_X1: - case LNK_UNARY_OPCODE_X1: - return 1; - default: - return 0; - } - default: - return 0; - } -} - -int __kprobes arch_prepare_kprobe(struct kprobe *p) -{ - unsigned long addr = (unsigned long)p->addr; - - if (addr & (sizeof(kprobe_opcode_t) - 1)) - return -EINVAL; - - if (insn_has_control(*p->addr)) { - pr_notice("Kprobes for control instructions are not supported\n"); - return -EINVAL; - } - - /* insn: must be on special executable page on tile. */ - p->ainsn.insn = get_insn_slot(); - if (!p->ainsn.insn) - return -ENOMEM; - - /* - * In the kprobe->ainsn.insn[] array we store the original - * instruction at index zero and a break trap instruction at - * index one. - */ - memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t)); - p->ainsn.insn[1] = breakpoint2_insn; - p->opcode = *p->addr; - - return 0; -} - -void __kprobes arch_arm_kprobe(struct kprobe *p) -{ - unsigned long addr_wr; - - /* Operate on writable kernel text mapping. */ - addr_wr = ktext_writable_addr(p->addr); - - if (probe_kernel_write((void *)addr_wr, &breakpoint_insn, - sizeof(breakpoint_insn))) - pr_err("%s: failed to enable kprobe\n", __func__); - - smp_wmb(); - flush_insn_slot(p); -} - -void __kprobes arch_disarm_kprobe(struct kprobe *kp) -{ - unsigned long addr_wr; - - /* Operate on writable kernel text mapping. */ - addr_wr = ktext_writable_addr(kp->addr); - - if (probe_kernel_write((void *)addr_wr, &kp->opcode, - sizeof(kp->opcode))) - pr_err("%s: failed to enable kprobe\n", __func__); - - smp_wmb(); - flush_insn_slot(kp); -} - -void __kprobes arch_remove_kprobe(struct kprobe *p) -{ - if (p->ainsn.insn) { - free_insn_slot(p->ainsn.insn, 0); - p->ainsn.insn = NULL; - } -} - -static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) -{ - kcb->prev_kprobe.kp = kprobe_running(); - kcb->prev_kprobe.status = kcb->kprobe_status; - kcb->prev_kprobe.saved_pc = kcb->kprobe_saved_pc; -} - -static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) -{ - __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); - kcb->kprobe_status = kcb->prev_kprobe.status; - kcb->kprobe_saved_pc = kcb->prev_kprobe.saved_pc; -} - -static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, - struct kprobe_ctlblk *kcb) -{ - __this_cpu_write(current_kprobe, p); - kcb->kprobe_saved_pc = regs->pc; -} - -static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) -{ - /* Single step inline if the instruction is a break. */ - if (p->opcode == breakpoint_insn || - p->opcode == breakpoint2_insn) - regs->pc = (unsigned long)p->addr; - else - regs->pc = (unsigned long)&p->ainsn.insn[0]; -} - -static int __kprobes kprobe_handler(struct pt_regs *regs) -{ - struct kprobe *p; - int ret = 0; - kprobe_opcode_t *addr; - struct kprobe_ctlblk *kcb; - - addr = (kprobe_opcode_t *)regs->pc; - - /* - * We don't want to be preempted for the entire - * duration of kprobe processing. - */ - preempt_disable(); - kcb = get_kprobe_ctlblk(); - - /* Check we're not actually recursing. */ - if (kprobe_running()) { - p = get_kprobe(addr); - if (p) { - if (kcb->kprobe_status == KPROBE_HIT_SS && - p->ainsn.insn[0] == breakpoint_insn) { - goto no_kprobe; - } - /* - * We have reentered the kprobe_handler(), since - * another probe was hit while within the handler. - * We here save the original kprobes variables and - * just single step on the instruction of the new probe - * without calling any user handlers. - */ - save_previous_kprobe(kcb); - set_current_kprobe(p, regs, kcb); - kprobes_inc_nmissed_count(p); - prepare_singlestep(p, regs); - kcb->kprobe_status = KPROBE_REENTER; - return 1; - } else { - if (*addr != breakpoint_insn) { - /* - * The breakpoint instruction was removed by - * another cpu right after we hit, no further - * handling of this interrupt is appropriate. - */ - ret = 1; - goto no_kprobe; - } - p = __this_cpu_read(current_kprobe); - if (p->break_handler && p->break_handler(p, regs)) - goto ss_probe; - } - goto no_kprobe; - } - - p = get_kprobe(addr); - if (!p) { - if (*addr != breakpoint_insn) { - /* - * The breakpoint instruction was removed right - * after we hit it. Another cpu has removed - * either a probepoint or a debugger breakpoint - * at this address. In either case, no further - * handling of this interrupt is appropriate. - */ - ret = 1; - } - /* Not one of ours: let kernel handle it. */ - goto no_kprobe; - } - - set_current_kprobe(p, regs, kcb); - kcb->kprobe_status = KPROBE_HIT_ACTIVE; - - if (p->pre_handler && p->pre_handler(p, regs)) { - /* Handler has already set things up, so skip ss setup. */ - return 1; - } - -ss_probe: - prepare_singlestep(p, regs); - kcb->kprobe_status = KPROBE_HIT_SS; - return 1; - -no_kprobe: - preempt_enable_no_resched(); - return ret; -} - -/* - * Called after single-stepping. p->addr is the address of the - * instruction that has been replaced by the breakpoint. To avoid the - * SMP problems that can occur when we temporarily put back the - * original opcode to single-step, we single-stepped a copy of the - * instruction. The address of this copy is p->ainsn.insn. - * - * This function prepares to return from the post-single-step - * breakpoint trap. - */ -static void __kprobes resume_execution(struct kprobe *p, - struct pt_regs *regs, - struct kprobe_ctlblk *kcb) -{ - unsigned long orig_pc = kcb->kprobe_saved_pc; - regs->pc = orig_pc + 8; -} - -static inline int post_kprobe_handler(struct pt_regs *regs) -{ - struct kprobe *cur = kprobe_running(); - struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - - if (!cur) - return 0; - - if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { - kcb->kprobe_status = KPROBE_HIT_SSDONE; - cur->post_handler(cur, regs, 0); - } - - resume_execution(cur, regs, kcb); - - /* Restore back the original saved kprobes variables and continue. */ - if (kcb->kprobe_status == KPROBE_REENTER) { - restore_previous_kprobe(kcb); - goto out; - } - reset_current_kprobe(); -out: - preempt_enable_no_resched(); - - return 1; -} - -static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) -{ - struct kprobe *cur = kprobe_running(); - struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - - if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) - return 1; - - if (kcb->kprobe_status & KPROBE_HIT_SS) { - /* - * We are here because the instruction being single - * stepped caused a page fault. We reset the current - * kprobe and the ip points back to the probe address - * and allow the page fault handler to continue as a - * normal page fault. - */ - resume_execution(cur, regs, kcb); - reset_current_kprobe(); - preempt_enable_no_resched(); - } - return 0; -} - -/* - * Wrapper routine for handling exceptions. - */ -int __kprobes kprobe_exceptions_notify(struct notifier_block *self, - unsigned long val, void *data) -{ - struct die_args *args = (struct die_args *)data; - int ret = NOTIFY_DONE; - - switch (val) { - case DIE_BREAK: - if (kprobe_handler(args->regs)) - ret = NOTIFY_STOP; - break; - case DIE_SSTEPBP: - if (post_kprobe_handler(args->regs)) - ret = NOTIFY_STOP; - break; - case DIE_PAGE_FAULT: - /* kprobe_running() needs smp_processor_id(). */ - preempt_disable(); - - if (kprobe_running() - && kprobe_fault_handler(args->regs, args->trapnr)) - ret = NOTIFY_STOP; - preempt_enable(); - break; - default: - break; - } - return ret; -} - -int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) -{ - struct jprobe *jp = container_of(p, struct jprobe, kp); - struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - - kcb->jprobe_saved_regs = *regs; - kcb->jprobe_saved_sp = regs->sp; - - memcpy(kcb->jprobes_stack, (void *)kcb->jprobe_saved_sp, - MIN_JPROBES_STACK_SIZE(kcb->jprobe_saved_sp)); - - regs->pc = (unsigned long)(jp->entry); - - return 1; -} - -/* Defined in the inline asm below. */ -void jprobe_return_end(void); - -void __kprobes jprobe_return(void) -{ - asm volatile( - "bpt\n\t" - ".globl jprobe_return_end\n" - "jprobe_return_end:\n"); -} - -int __kprobes longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) -{ - struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); - - if (regs->pc >= (unsigned long)jprobe_return && - regs->pc <= (unsigned long)jprobe_return_end) { - *regs = kcb->jprobe_saved_regs; - memcpy((void *)kcb->jprobe_saved_sp, kcb->jprobes_stack, - MIN_JPROBES_STACK_SIZE(kcb->jprobe_saved_sp)); - preempt_enable_no_resched(); - - return 1; - } - return 0; -} - -/* - * Function return probe trampoline: - * - init_kprobes() establishes a probepoint here - * - When the probed function returns, this probe causes the - * handlers to fire - */ -static void __used kretprobe_trampoline_holder(void) -{ - asm volatile( - "nop\n\t" - ".global kretprobe_trampoline\n" - "kretprobe_trampoline:\n\t" - "nop\n\t" - : : : "memory"); -} - -void kretprobe_trampoline(void); - -void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, - struct pt_regs *regs) -{ - ri->ret_addr = (kprobe_opcode_t *) regs->lr; - - /* Replace the return addr with trampoline addr */ - regs->lr = (unsigned long)kretprobe_trampoline; -} - -/* - * Called when the probe at kretprobe trampoline is hit. - */ -static int __kprobes trampoline_probe_handler(struct kprobe *p, - struct pt_regs *regs) -{ - struct kretprobe_instance *ri = NULL; - struct hlist_head *head, empty_rp; - struct hlist_node *tmp; - unsigned long flags, orig_ret_address = 0; - unsigned long trampoline_address = (unsigned long)kretprobe_trampoline; - - INIT_HLIST_HEAD(&empty_rp); - kretprobe_hash_lock(current, &head, &flags); - - /* - * It is possible to have multiple instances associated with a given - * task either because multiple functions in the call path have - * a return probe installed on them, and/or more than one return - * return probe was registered for a target function. - * - * We can handle this because: - * - instances are always inserted at the head of the list - * - when multiple return probes are registered for the same - * function, the first instance's ret_addr will point to the - * real return address, and all the rest will point to - * kretprobe_trampoline - */ - hlist_for_each_entry_safe(ri, tmp, head, hlist) { - if (ri->task != current) - /* another task is sharing our hash bucket */ - continue; - - if (ri->rp && ri->rp->handler) - ri->rp->handler(ri, regs); - - orig_ret_address = (unsigned long)ri->ret_addr; - recycle_rp_inst(ri, &empty_rp); - - if (orig_ret_address != trampoline_address) { - /* - * This is the real return address. Any other - * instances associated with this task are for - * other calls deeper on the call stack - */ - break; - } - } - - kretprobe_assert(ri, orig_ret_address, trampoline_address); - instruction_pointer(regs) = orig_ret_address; - - reset_current_kprobe(); - kretprobe_hash_unlock(current, &flags); - preempt_enable_no_resched(); - - hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { - hlist_del(&ri->hlist); - kfree(ri); - } - /* - * By returning a non-zero value, we are telling - * kprobe_handler() that we don't want the post_handler - * to run (and have re-enabled preemption) - */ - return 1; -} - -int __kprobes arch_trampoline_kprobe(struct kprobe *p) -{ - if (p->addr == (kprobe_opcode_t *)kretprobe_trampoline) - return 1; - - return 0; -} - -static struct kprobe trampoline_p = { - .addr = (kprobe_opcode_t *)kretprobe_trampoline, - .pre_handler = trampoline_probe_handler -}; - -int __init arch_init_kprobes(void) -{ - register_kprobe(&trampoline_p); - return 0; -} diff --git a/arch/tile/kernel/machine_kexec.c b/arch/tile/kernel/machine_kexec.c deleted file mode 100644 index 008aa2faef55..000000000000 --- a/arch/tile/kernel/machine_kexec.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * based on machine_kexec.c from other architectures in linux-2.6.18 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * This stuff is not in elf.h and is not in any other kernel include. - * This stuff is needed below in the little boot notes parser to - * extract the command line so we can pass it to the hypervisor. - */ -struct Elf32_Bhdr { - Elf32_Word b_signature; - Elf32_Word b_size; - Elf32_Half b_checksum; - Elf32_Half b_records; -}; -#define ELF_BOOT_MAGIC 0x0E1FB007 -#define EBN_COMMAND_LINE 0x00000004 -#define roundupsz(X) (((X) + 3) & ~3) - -/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - -void machine_shutdown(void) -{ - /* - * Normally we would stop all the other processors here, but - * the check in machine_kexec_prepare below ensures we'll only - * get this far if we've been booted with "nosmp" on the - * command line or without CONFIG_SMP so there's nothing to do - * here (for now). - */ -} - -void machine_crash_shutdown(struct pt_regs *regs) -{ - /* - * Cannot happen. This type of kexec is disabled on this - * architecture (and enforced in machine_kexec_prepare below). - */ -} - - -int machine_kexec_prepare(struct kimage *image) -{ - if (num_online_cpus() > 1) { - pr_warn("%s: detected attempt to kexec with num_online_cpus() > 1\n", - __func__); - return -ENOSYS; - } - if (image->type != KEXEC_TYPE_DEFAULT) { - pr_warn("%s: detected attempt to kexec with unsupported type: %d\n", - __func__, image->type); - return -ENOSYS; - } - return 0; -} - -void machine_kexec_cleanup(struct kimage *image) -{ - /* - * We did nothing in machine_kexec_prepare, - * so we have nothing to do here. - */ -} - -/* - * If we can find elf boot notes on this page, return the command - * line. Otherwise, silently return null. Somewhat kludgy, but no - * good way to do this without significantly rearchitecting the - * architecture-independent kexec code. - */ - -static unsigned char *kexec_bn2cl(void *pg) -{ - struct Elf32_Bhdr *bhdrp; - Elf32_Nhdr *nhdrp; - unsigned char *desc; - unsigned char *command_line; - __sum16 csum; - - bhdrp = (struct Elf32_Bhdr *) pg; - - /* - * This routine is invoked for every source page, so make - * sure to quietly ignore every impossible page. - */ - if (bhdrp->b_signature != ELF_BOOT_MAGIC || - bhdrp->b_size > PAGE_SIZE) - return 0; - - /* - * If we get a checksum mismatch, warn with the checksum - * so we can diagnose better. - */ - csum = ip_compute_csum(pg, bhdrp->b_size); - if (csum != 0) { - pr_warn("%s: bad checksum %#x (size %d)\n", - __func__, csum, bhdrp->b_size); - return 0; - } - - nhdrp = (Elf32_Nhdr *) (bhdrp + 1); - - while (nhdrp->n_type != EBN_COMMAND_LINE) { - - desc = (unsigned char *) (nhdrp + 1); - desc += roundupsz(nhdrp->n_descsz); - - nhdrp = (Elf32_Nhdr *) desc; - - /* still in bounds? */ - if ((unsigned char *) (nhdrp + 1) > - ((unsigned char *) pg) + bhdrp->b_size) { - - pr_info("%s: out of bounds\n", __func__); - return 0; - } - } - - command_line = (unsigned char *) (nhdrp + 1); - desc = command_line; - - while (*desc != '\0') { - desc++; - if (((unsigned long)desc & PAGE_MASK) != (unsigned long)pg) { - pr_info("%s: ran off end of page\n", __func__); - return 0; - } - } - - return command_line; -} - -static void kexec_find_and_set_command_line(struct kimage *image) -{ - kimage_entry_t *ptr, entry; - - unsigned char *command_line = 0; - unsigned char *r; - HV_Errno hverr; - - for (ptr = &image->head; - (entry = *ptr) && !(entry & IND_DONE); - ptr = (entry & IND_INDIRECTION) ? - phys_to_virt((entry & PAGE_MASK)) : ptr + 1) { - - if ((entry & IND_SOURCE)) { - void *va = - kmap_atomic_pfn(entry >> PAGE_SHIFT); - r = kexec_bn2cl(va); - if (r) { - command_line = r; - break; - } - kunmap_atomic(va); - } - } - - if (command_line != 0) { - pr_info("setting new command line to \"%s\"\n", command_line); - - hverr = hv_set_command_line( - (HV_VirtAddr) command_line, strlen(command_line)); - kunmap_atomic(command_line); - } else { - pr_info("%s: no command line found; making empty\n", __func__); - hverr = hv_set_command_line((HV_VirtAddr) command_line, 0); - } - if (hverr) - pr_warn("%s: hv_set_command_line returned error: %d\n", - __func__, hverr); -} - -/* - * The kexec code range-checks all its PAs, so to avoid having it run - * amok and allocate memory and then sequester it from every other - * controller, we force it to come from controller zero. We also - * disable the oom-killer since if we do end up running out of memory, - * that almost certainly won't help. - */ -struct page *kimage_alloc_pages_arch(gfp_t gfp_mask, unsigned int order) -{ - gfp_mask |= __GFP_THISNODE | __GFP_NORETRY; - return alloc_pages_node(0, gfp_mask, order); -} - -/* - * Address range in which pa=va mapping is set in setup_quasi_va_is_pa(). - * For tilepro, PAGE_OFFSET is used since this is the largest possbile value - * for tilepro, while for tilegx, we limit it to entire middle level page - * table which we assume has been allocated and is undoubtedly large enough. - */ -#ifndef __tilegx__ -#define QUASI_VA_IS_PA_ADDR_RANGE PAGE_OFFSET -#else -#define QUASI_VA_IS_PA_ADDR_RANGE PGDIR_SIZE -#endif - -static void setup_quasi_va_is_pa(void) -{ - HV_PTE pte; - unsigned long i; - - /* - * Flush our TLB to prevent conflicts between the previous contents - * and the new stuff we're about to add. - */ - local_flush_tlb_all(); - - /* - * setup VA is PA, at least up to QUASI_VA_IS_PA_ADDR_RANGE. - * Note here we assume that level-1 page table is defined by - * HPAGE_SIZE. - */ - pte = hv_pte(_PAGE_KERNEL | _PAGE_HUGE_PAGE); - pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3); - for (i = 0; i < (QUASI_VA_IS_PA_ADDR_RANGE >> HPAGE_SHIFT); i++) { - unsigned long vaddr = i << HPAGE_SHIFT; - pgd_t *pgd = pgd_offset(current->mm, vaddr); - pud_t *pud = pud_offset(pgd, vaddr); - pte_t *ptep = (pte_t *) pmd_offset(pud, vaddr); - unsigned long pfn = i << (HPAGE_SHIFT - PAGE_SHIFT); - - if (pfn_valid(pfn)) - __set_pte(ptep, pfn_pte(pfn, pte)); - } -} - - -void machine_kexec(struct kimage *image) -{ - void *reboot_code_buffer; - pte_t *ptep; - void (*rnk)(unsigned long, void *, unsigned long) - __noreturn; - - /* Mask all interrupts before starting to reboot. */ - interrupt_mask_set_mask(~0ULL); - - kexec_find_and_set_command_line(image); - - /* - * Adjust the home caching of the control page to be cached on - * this cpu, and copy the assembly helper into the control - * code page, which we map in the vmalloc area. - */ - homecache_change_page_home(image->control_code_page, 0, - smp_processor_id()); - reboot_code_buffer = page_address(image->control_code_page); - BUG_ON(reboot_code_buffer == NULL); - ptep = virt_to_pte(NULL, (unsigned long)reboot_code_buffer); - __set_pte(ptep, pte_mkexec(*ptep)); - memcpy(reboot_code_buffer, relocate_new_kernel, - relocate_new_kernel_size); - __flush_icache_range( - (unsigned long) reboot_code_buffer, - (unsigned long) reboot_code_buffer + relocate_new_kernel_size); - - setup_quasi_va_is_pa(); - - /* now call it */ - rnk = reboot_code_buffer; - (*rnk)(image->head, reboot_code_buffer, image->start); -} diff --git a/arch/tile/kernel/mcount_64.S b/arch/tile/kernel/mcount_64.S deleted file mode 100644 index 6c6702451962..000000000000 --- a/arch/tile/kernel/mcount_64.S +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * TILE-Gx specific __mcount support - */ - -#include -#include - -#define REGSIZE 8 - - .text - .global __mcount - - .macro MCOUNT_SAVE_REGS - addli sp, sp, -REGSIZE - { - st sp, lr - addli r29, sp, - (12 * REGSIZE) - } - { - addli sp, sp, - (13 * REGSIZE) - st r29, sp - } - addli r29, r29, REGSIZE - { st r29, r0; addli r29, r29, REGSIZE } - { st r29, r1; addli r29, r29, REGSIZE } - { st r29, r2; addli r29, r29, REGSIZE } - { st r29, r3; addli r29, r29, REGSIZE } - { st r29, r4; addli r29, r29, REGSIZE } - { st r29, r5; addli r29, r29, REGSIZE } - { st r29, r6; addli r29, r29, REGSIZE } - { st r29, r7; addli r29, r29, REGSIZE } - { st r29, r8; addli r29, r29, REGSIZE } - { st r29, r9; addli r29, r29, REGSIZE } - { st r29, r10; addli r29, r29, REGSIZE } - .endm - - .macro MCOUNT_RESTORE_REGS - addli r29, sp, (2 * REGSIZE) - { ld r0, r29; addli r29, r29, REGSIZE } - { ld r1, r29; addli r29, r29, REGSIZE } - { ld r2, r29; addli r29, r29, REGSIZE } - { ld r3, r29; addli r29, r29, REGSIZE } - { ld r4, r29; addli r29, r29, REGSIZE } - { ld r5, r29; addli r29, r29, REGSIZE } - { ld r6, r29; addli r29, r29, REGSIZE } - { ld r7, r29; addli r29, r29, REGSIZE } - { ld r8, r29; addli r29, r29, REGSIZE } - { ld r9, r29; addli r29, r29, REGSIZE } - { ld r10, r29; addli lr, sp, (13 * REGSIZE) } - { ld lr, lr; addli sp, sp, (14 * REGSIZE) } - .endm - - .macro RETURN_BACK - { move r12, lr; move lr, r10 } - jrp r12 - .endm - -#ifdef CONFIG_DYNAMIC_FTRACE - - .align 64 -STD_ENTRY(__mcount) -__mcount: - j ftrace_stub -STD_ENDPROC(__mcount) - - .align 64 -STD_ENTRY(ftrace_caller) - MCOUNT_SAVE_REGS - - /* arg1: self return address */ - /* arg2: parent's return address */ - /* arg3: ftrace_ops */ - /* arg4: regs (but make it NULL) */ - { move r0, lr; moveli r2, hw2_last(function_trace_op) } - { move r1, r10; shl16insli r2, r2, hw1(function_trace_op) } - { movei r3, 0; shl16insli r2, r2, hw0(function_trace_op) } - ld r2,r2 - - .global ftrace_call -ftrace_call: - /* - * a placeholder for the call to a real tracing function, i.e. - * ftrace_trace_function() - */ - nop - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - .global ftrace_graph_call -ftrace_graph_call: - /* - * a placeholder for the call to a real tracing function, i.e. - * ftrace_graph_caller() - */ - nop -#endif - MCOUNT_RESTORE_REGS - .global ftrace_stub -ftrace_stub: - RETURN_BACK -STD_ENDPROC(ftrace_caller) - -#else /* ! CONFIG_DYNAMIC_FTRACE */ - - .align 64 -STD_ENTRY(__mcount) - { - moveli r11, hw2_last(ftrace_trace_function) - moveli r13, hw2_last(ftrace_stub) - } - { - shl16insli r11, r11, hw1(ftrace_trace_function) - shl16insli r13, r13, hw1(ftrace_stub) - } - { - shl16insli r11, r11, hw0(ftrace_trace_function) - shl16insli r13, r13, hw0(ftrace_stub) - } - - ld r11, r11 - sub r14, r13, r11 - bnez r14, static_trace - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - moveli r15, hw2_last(ftrace_graph_return) - shl16insli r15, r15, hw1(ftrace_graph_return) - shl16insli r15, r15, hw0(ftrace_graph_return) - ld r15, r15 - sub r15, r15, r13 - bnez r15, ftrace_graph_caller - - { - moveli r16, hw2_last(ftrace_graph_entry) - moveli r17, hw2_last(ftrace_graph_entry_stub) - } - { - shl16insli r16, r16, hw1(ftrace_graph_entry) - shl16insli r17, r17, hw1(ftrace_graph_entry_stub) - } - { - shl16insli r16, r16, hw0(ftrace_graph_entry) - shl16insli r17, r17, hw0(ftrace_graph_entry_stub) - } - ld r16, r16 - sub r17, r16, r17 - bnez r17, ftrace_graph_caller - -#endif - RETURN_BACK - -static_trace: - MCOUNT_SAVE_REGS - - /* arg1: self return address */ - /* arg2: parent's return address */ - { move r0, lr; move r1, r10 } - - /* call ftrace_trace_function() */ - jalr r11 - - MCOUNT_RESTORE_REGS - - .global ftrace_stub -ftrace_stub: - RETURN_BACK -STD_ENDPROC(__mcount) - -#endif /* ! CONFIG_DYNAMIC_FTRACE */ - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - -STD_ENTRY(ftrace_graph_caller) -ftrace_graph_caller: -#ifndef CONFIG_DYNAMIC_FTRACE - MCOUNT_SAVE_REGS -#endif - - /* arg1: Get the location of the parent's return address */ - addi r0, sp, 12 * REGSIZE - /* arg2: Get self return address */ - move r1, lr - - jal prepare_ftrace_return - - MCOUNT_RESTORE_REGS - RETURN_BACK -STD_ENDPROC(ftrace_graph_caller) - - .global return_to_handler -return_to_handler: - MCOUNT_SAVE_REGS - - jal ftrace_return_to_handler - /* restore the real parent address */ - move r11, r0 - - MCOUNT_RESTORE_REGS - jr r11 - -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ diff --git a/arch/tile/kernel/messaging.c b/arch/tile/kernel/messaging.c deleted file mode 100644 index 7475af3aacec..000000000000 --- a/arch/tile/kernel/messaging.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* All messages are stored here */ -static DEFINE_PER_CPU(HV_MsgState, msg_state); - -void init_messaging(void) -{ - /* Allocate storage for messages in kernel space */ - HV_MsgState *state = this_cpu_ptr(&msg_state); - int rc = hv_register_message_state(state); - if (rc != HV_OK) - panic("hv_register_message_state: error %d", rc); - - /* Make sure downcall interrupts will be enabled. */ - arch_local_irq_unmask(INT_INTCTRL_K); -} - -void hv_message_intr(struct pt_regs *regs, int intnum) -{ - /* - * We enter with interrupts disabled and leave them disabled, - * to match expectations of called functions (e.g. - * do_ccupdate_local() in mm/slab.c). This is also consistent - * with normal call entry for device interrupts. - */ - - int message[HV_MAX_MESSAGE_SIZE/sizeof(int)]; - HV_RcvMsgInfo rmi; - int nmsgs = 0; - - /* Track time spent here in an interrupt context */ - struct pt_regs *old_regs = set_irq_regs(regs); - irq_enter(); - -#ifdef CONFIG_DEBUG_STACKOVERFLOW - /* Debugging check for stack overflow: less than 1/8th stack free? */ - { - long sp = stack_pointer - (long) current_thread_info(); - if (unlikely(sp < (sizeof(struct thread_info) + STACK_WARN))) { - pr_emerg("%s: stack overflow: %ld\n", - __func__, sp - sizeof(struct thread_info)); - dump_stack(); - } - } -#endif - - while (1) { - HV_MsgState *state = this_cpu_ptr(&msg_state); - rmi = hv_receive_message(*state, (HV_VirtAddr) message, - sizeof(message)); - if (rmi.msglen == 0) - break; - - if (rmi.msglen < 0) - panic("hv_receive_message failed: %d", rmi.msglen); - - ++nmsgs; - - if (rmi.source == HV_MSG_TILE) { - int tag; - - /* we just send tags for now */ - BUG_ON(rmi.msglen != sizeof(int)); - - tag = message[0]; -#ifdef CONFIG_SMP - evaluate_message(message[0]); -#else - panic("Received IPI message %d in UP mode", tag); -#endif - } else if (rmi.source == HV_MSG_INTR) { - HV_IntrMsg *him = (HV_IntrMsg *)message; - struct hv_driver_cb *cb = - (struct hv_driver_cb *)him->intarg; - cb->callback(cb, him->intdata); - __this_cpu_inc(irq_stat.irq_hv_msg_count); - } - } - - /* - * We shouldn't have gotten a message downcall with no - * messages available. - */ - if (nmsgs == 0) - panic("Message downcall invoked with no messages!"); - - /* - * Track time spent against the current process again and - * process any softirqs if they are waiting. - */ - irq_exit(); - set_irq_regs(old_regs); -} diff --git a/arch/tile/kernel/module.c b/arch/tile/kernel/module.c deleted file mode 100644 index 09233fbe7801..000000000000 --- a/arch/tile/kernel/module.c +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Based on i386 version, copyright (C) 2001 Rusty Russell. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef MODULE_DEBUG -#define DEBUGP printk -#else -#define DEBUGP(fmt...) -#endif - -/* - * Allocate some address space in the range MEM_MODULE_START to - * MEM_MODULE_END and populate it with memory. - */ -void *module_alloc(unsigned long size) -{ - struct page **pages; - pgprot_t prot_rwx = __pgprot(_PAGE_KERNEL | _PAGE_KERNEL_EXEC); - struct vm_struct *area; - int i = 0; - int npages; - - npages = (size + PAGE_SIZE - 1) / PAGE_SIZE; - pages = kmalloc_array(npages, sizeof(*pages), GFP_KERNEL); - if (pages == NULL) - return NULL; - for (; i < npages; ++i) { - pages[i] = alloc_page(GFP_KERNEL | __GFP_HIGHMEM); - if (!pages[i]) - goto free_pages; - } - - area = __get_vm_area(size, VM_ALLOC, MEM_MODULE_START, MEM_MODULE_END); - if (!area) - goto free_pages; - area->nr_pages = npages; - area->pages = pages; - - if (map_vm_area(area, prot_rwx, pages)) { - vunmap(area->addr); - goto free_pages; - } - - return area->addr; - free_pages: - while (--i >= 0) - __free_page(pages[i]); - kfree(pages); - return NULL; -} - - -/* Free memory returned from module_alloc */ -void module_memfree(void *module_region) -{ - vfree(module_region); - - /* Globally flush the L1 icache. */ - flush_remote(0, HV_FLUSH_EVICT_L1I, cpu_online_mask, - 0, 0, 0, NULL, NULL, 0); - - /* - * FIXME: Add module_arch_freeing_init to trim exception - * table entries. - */ -} - -#ifdef __tilegx__ -/* - * Validate that the high 16 bits of "value" is just the sign-extension of - * the low 48 bits. - */ -static int validate_hw2_last(long value, struct module *me) -{ - if (((value << 16) >> 16) != value) { - pr_warn("module %s: Out of range HW2_LAST value %#lx\n", - me->name, value); - return 0; - } - return 1; -} - -/* - * Validate that "value" isn't too big to hold in a JumpOff relocation. - */ -static int validate_jumpoff(long value) -{ - /* Determine size of jump offset. */ - int shift = __builtin_clzl(get_JumpOff_X1(create_JumpOff_X1(-1))); - - /* Check to see if it fits into the relocation slot. */ - long f = get_JumpOff_X1(create_JumpOff_X1(value)); - f = (f << shift) >> shift; - - return f == value; -} -#endif - -int apply_relocate_add(Elf_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - unsigned int i; - Elf_Rela *rel = (void *)sechdrs[relsec].sh_addr; - Elf_Sym *sym; - u64 *location; - unsigned long value; - - DEBUGP("Applying relocate section %u to %u\n", relsec, - sechdrs[relsec].sh_info); - for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { - /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rel[i].r_offset; - /* - * This is the symbol it is referring to. - * Note that all undefined symbols have been resolved. - */ - sym = (Elf_Sym *)sechdrs[symindex].sh_addr - + ELF_R_SYM(rel[i].r_info); - value = sym->st_value + rel[i].r_addend; - - switch (ELF_R_TYPE(rel[i].r_info)) { - -#ifdef __LITTLE_ENDIAN -# define MUNGE(func) \ - (*location = ((*location & ~func(-1)) | func(value))) -#else -/* - * Instructions are always little-endian, so when we read them as data, - * we have to swap them around before and after modifying them. - */ -# define MUNGE(func) \ - (*location = swab64((swab64(*location) & ~func(-1)) | func(value))) -#endif - -#ifndef __tilegx__ - case R_TILE_32: - *(uint32_t *)location = value; - break; - case R_TILE_IMM16_X0_HA: - value = (value + 0x8000) >> 16; - /*FALLTHROUGH*/ - case R_TILE_IMM16_X0_LO: - MUNGE(create_Imm16_X0); - break; - case R_TILE_IMM16_X1_HA: - value = (value + 0x8000) >> 16; - /*FALLTHROUGH*/ - case R_TILE_IMM16_X1_LO: - MUNGE(create_Imm16_X1); - break; - case R_TILE_JOFFLONG_X1: - value -= (unsigned long) location; /* pc-relative */ - value = (long) value >> 3; /* count by instrs */ - MUNGE(create_JOffLong_X1); - break; -#else - case R_TILEGX_64: - *location = value; - break; - case R_TILEGX_IMM16_X0_HW2_LAST: - if (!validate_hw2_last(value, me)) - return -ENOEXEC; - value >>= 16; - /*FALLTHROUGH*/ - case R_TILEGX_IMM16_X0_HW1: - value >>= 16; - /*FALLTHROUGH*/ - case R_TILEGX_IMM16_X0_HW0: - MUNGE(create_Imm16_X0); - break; - case R_TILEGX_IMM16_X1_HW2_LAST: - if (!validate_hw2_last(value, me)) - return -ENOEXEC; - value >>= 16; - /*FALLTHROUGH*/ - case R_TILEGX_IMM16_X1_HW1: - value >>= 16; - /*FALLTHROUGH*/ - case R_TILEGX_IMM16_X1_HW0: - MUNGE(create_Imm16_X1); - break; - case R_TILEGX_JUMPOFF_X1: - value -= (unsigned long) location; /* pc-relative */ - value = (long) value >> 3; /* count by instrs */ - if (!validate_jumpoff(value)) { - pr_warn("module %s: Out of range jump to %#llx at %#llx (%p)\n", - me->name, - sym->st_value + rel[i].r_addend, - rel[i].r_offset, location); - return -ENOEXEC; - } - MUNGE(create_JumpOff_X1); - break; -#endif - -#undef MUNGE - - default: - pr_err("module %s: Unknown relocation: %d\n", - me->name, (int) ELF_R_TYPE(rel[i].r_info)); - return -ENOEXEC; - } - } - return 0; -} diff --git a/arch/tile/kernel/pci-dma.c b/arch/tile/kernel/pci-dma.c deleted file mode 100644 index 6a1efe5543fa..000000000000 --- a/arch/tile/kernel/pci-dma.c +++ /dev/null @@ -1,607 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* Generic DMA mapping functions: */ - -/* - * Allocate what Linux calls "coherent" memory. On TILEPro this is - * uncached memory; on TILE-Gx it is hash-for-home memory. - */ -#ifdef __tilepro__ -#define PAGE_HOME_DMA PAGE_HOME_UNCACHED -#else -#define PAGE_HOME_DMA PAGE_HOME_HASH -#endif - -static void *tile_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - unsigned long attrs) -{ - u64 dma_mask = (dev && dev->coherent_dma_mask) ? - dev->coherent_dma_mask : DMA_BIT_MASK(32); - int node = dev ? dev_to_node(dev) : 0; - int order = get_order(size); - struct page *pg; - dma_addr_t addr; - - gfp |= __GFP_ZERO; - - /* - * If the mask specifies that the memory be in the first 4 GB, then - * we force the allocation to come from the DMA zone. We also - * force the node to 0 since that's the only node where the DMA - * zone isn't empty. If the mask size is smaller than 32 bits, we - * may still not be able to guarantee a suitable memory address, in - * which case we will return NULL. But such devices are uncommon. - */ - if (dma_mask <= DMA_BIT_MASK(32)) { - gfp |= GFP_DMA32; - node = 0; - } - - pg = homecache_alloc_pages_node(node, gfp, order, PAGE_HOME_DMA); - if (pg == NULL) - return NULL; - - addr = page_to_phys(pg); - if (addr + size > dma_mask) { - __homecache_free_pages(pg, order); - return NULL; - } - - *dma_handle = addr; - - return page_address(pg); -} - -/* - * Free memory that was allocated with tile_dma_alloc_coherent. - */ -static void tile_dma_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - unsigned long attrs) -{ - homecache_free_pages((unsigned long)vaddr, get_order(size)); -} - -/* - * The map routines "map" the specified address range for DMA - * accesses. The memory belongs to the device after this call is - * issued, until it is unmapped with dma_unmap_single. - * - * We don't need to do any mapping, we just flush the address range - * out of the cache and return a DMA address. - * - * The unmap routines do whatever is necessary before the processor - * accesses the memory again, and must be called before the driver - * touches the memory. We can get away with a cache invalidate if we - * can count on nothing having been touched. - */ - -/* Set up a single page for DMA access. */ -static void __dma_prep_page(struct page *page, unsigned long offset, - size_t size, enum dma_data_direction direction) -{ - /* - * Flush the page from cache if necessary. - * On tilegx, data is delivered to hash-for-home L3; on tilepro, - * data is delivered direct to memory. - * - * NOTE: If we were just doing DMA_TO_DEVICE we could optimize - * this to be a "flush" not a "finv" and keep some of the - * state in cache across the DMA operation, but it doesn't seem - * worth creating the necessary flush_buffer_xxx() infrastructure. - */ - int home = page_home(page); - switch (home) { - case PAGE_HOME_HASH: -#ifdef __tilegx__ - return; -#endif - break; - case PAGE_HOME_UNCACHED: -#ifdef __tilepro__ - return; -#endif - break; - case PAGE_HOME_IMMUTABLE: - /* Should be going to the device only. */ - BUG_ON(direction == DMA_FROM_DEVICE || - direction == DMA_BIDIRECTIONAL); - return; - case PAGE_HOME_INCOHERENT: - /* Incoherent anyway, so no need to work hard here. */ - return; - default: - BUG_ON(home < 0 || home >= NR_CPUS); - break; - } - homecache_finv_page(page); - -#ifdef DEBUG_ALIGNMENT - /* Warn if the region isn't cacheline aligned. */ - if (offset & (L2_CACHE_BYTES - 1) || (size & (L2_CACHE_BYTES - 1))) - pr_warn("Unaligned DMA to non-hfh memory: PA %#llx/%#lx\n", - PFN_PHYS(page_to_pfn(page)) + offset, size); -#endif -} - -/* Make the page ready to be read by the core. */ -static void __dma_complete_page(struct page *page, unsigned long offset, - size_t size, enum dma_data_direction direction) -{ -#ifdef __tilegx__ - switch (page_home(page)) { - case PAGE_HOME_HASH: - /* I/O device delivered data the way the cpu wanted it. */ - break; - case PAGE_HOME_INCOHERENT: - /* Incoherent anyway, so no need to work hard here. */ - break; - case PAGE_HOME_IMMUTABLE: - /* Extra read-only copies are not a problem. */ - break; - default: - /* Flush the bogus hash-for-home I/O entries to memory. */ - homecache_finv_map_page(page, PAGE_HOME_HASH); - break; - } -#endif -} - -static void __dma_prep_pa_range(dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - struct page *page = pfn_to_page(PFN_DOWN(dma_addr)); - unsigned long offset = dma_addr & (PAGE_SIZE - 1); - size_t bytes = min(size, (size_t)(PAGE_SIZE - offset)); - - while (size != 0) { - __dma_prep_page(page, offset, bytes, direction); - size -= bytes; - ++page; - offset = 0; - bytes = min((size_t)PAGE_SIZE, size); - } -} - -static void __dma_complete_pa_range(dma_addr_t dma_addr, size_t size, - enum dma_data_direction direction) -{ - struct page *page = pfn_to_page(PFN_DOWN(dma_addr)); - unsigned long offset = dma_addr & (PAGE_SIZE - 1); - size_t bytes = min(size, (size_t)(PAGE_SIZE - offset)); - - while (size != 0) { - __dma_complete_page(page, offset, bytes, direction); - size -= bytes; - ++page; - offset = 0; - bytes = min((size_t)PAGE_SIZE, size); - } -} - -static int tile_dma_map_sg(struct device *dev, struct scatterlist *sglist, - int nents, enum dma_data_direction direction, - unsigned long attrs) -{ - struct scatterlist *sg; - int i; - - BUG_ON(!valid_dma_direction(direction)); - - WARN_ON(nents == 0 || sglist->length == 0); - - for_each_sg(sglist, sg, nents, i) { - sg->dma_address = sg_phys(sg); -#ifdef CONFIG_NEED_SG_DMA_LENGTH - sg->dma_length = sg->length; -#endif - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) - continue; - __dma_prep_pa_range(sg->dma_address, sg->length, direction); - } - - return nents; -} - -static void tile_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, - int nents, enum dma_data_direction direction, - unsigned long attrs) -{ - struct scatterlist *sg; - int i; - - BUG_ON(!valid_dma_direction(direction)); - for_each_sg(sglist, sg, nents, i) { - sg->dma_address = sg_phys(sg); - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) - continue; - __dma_complete_pa_range(sg->dma_address, sg->length, - direction); - } -} - -static dma_addr_t tile_dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction, - unsigned long attrs) -{ - BUG_ON(!valid_dma_direction(direction)); - - BUG_ON(offset + size > PAGE_SIZE); - if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC)) - __dma_prep_page(page, offset, size, direction); - - return page_to_pa(page) + offset; -} - -static void tile_dma_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, enum dma_data_direction direction, - unsigned long attrs) -{ - BUG_ON(!valid_dma_direction(direction)); - - if (attrs & DMA_ATTR_SKIP_CPU_SYNC) - return; - - __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)), - dma_address & (PAGE_SIZE - 1), size, direction); -} - -static void tile_dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, - size_t size, - enum dma_data_direction direction) -{ - BUG_ON(!valid_dma_direction(direction)); - - __dma_complete_pa_range(dma_handle, size, direction); -} - -static void tile_dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction direction) -{ - __dma_prep_pa_range(dma_handle, size, direction); -} - -static void tile_dma_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sglist, int nelems, - enum dma_data_direction direction) -{ - struct scatterlist *sg; - int i; - - BUG_ON(!valid_dma_direction(direction)); - WARN_ON(nelems == 0 || sglist->length == 0); - - for_each_sg(sglist, sg, nelems, i) { - dma_sync_single_for_cpu(dev, sg->dma_address, - sg_dma_len(sg), direction); - } -} - -static void tile_dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sglist, int nelems, - enum dma_data_direction direction) -{ - struct scatterlist *sg; - int i; - - BUG_ON(!valid_dma_direction(direction)); - WARN_ON(nelems == 0 || sglist->length == 0); - - for_each_sg(sglist, sg, nelems, i) { - dma_sync_single_for_device(dev, sg->dma_address, - sg_dma_len(sg), direction); - } -} - -static const struct dma_map_ops tile_default_dma_map_ops = { - .alloc = tile_dma_alloc_coherent, - .free = tile_dma_free_coherent, - .map_page = tile_dma_map_page, - .unmap_page = tile_dma_unmap_page, - .map_sg = tile_dma_map_sg, - .unmap_sg = tile_dma_unmap_sg, - .sync_single_for_cpu = tile_dma_sync_single_for_cpu, - .sync_single_for_device = tile_dma_sync_single_for_device, - .sync_sg_for_cpu = tile_dma_sync_sg_for_cpu, - .sync_sg_for_device = tile_dma_sync_sg_for_device, -}; - -const struct dma_map_ops *tile_dma_map_ops = &tile_default_dma_map_ops; -EXPORT_SYMBOL(tile_dma_map_ops); - -/* Generic PCI DMA mapping functions */ - -static void *tile_pci_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - unsigned long attrs) -{ - int node = dev_to_node(dev); - int order = get_order(size); - struct page *pg; - dma_addr_t addr; - - gfp |= __GFP_ZERO; - - pg = homecache_alloc_pages_node(node, gfp, order, PAGE_HOME_DMA); - if (pg == NULL) - return NULL; - - addr = page_to_phys(pg); - - *dma_handle = addr + get_dma_offset(dev); - - return page_address(pg); -} - -/* - * Free memory that was allocated with tile_pci_dma_alloc_coherent. - */ -static void tile_pci_dma_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - unsigned long attrs) -{ - homecache_free_pages((unsigned long)vaddr, get_order(size)); -} - -static int tile_pci_dma_map_sg(struct device *dev, struct scatterlist *sglist, - int nents, enum dma_data_direction direction, - unsigned long attrs) -{ - struct scatterlist *sg; - int i; - - BUG_ON(!valid_dma_direction(direction)); - - WARN_ON(nents == 0 || sglist->length == 0); - - for_each_sg(sglist, sg, nents, i) { - sg->dma_address = sg_phys(sg); - __dma_prep_pa_range(sg->dma_address, sg->length, direction); - - sg->dma_address = sg->dma_address + get_dma_offset(dev); -#ifdef CONFIG_NEED_SG_DMA_LENGTH - sg->dma_length = sg->length; -#endif - } - - return nents; -} - -static void tile_pci_dma_unmap_sg(struct device *dev, - struct scatterlist *sglist, int nents, - enum dma_data_direction direction, - unsigned long attrs) -{ - struct scatterlist *sg; - int i; - - BUG_ON(!valid_dma_direction(direction)); - for_each_sg(sglist, sg, nents, i) { - sg->dma_address = sg_phys(sg); - __dma_complete_pa_range(sg->dma_address, sg->length, - direction); - } -} - -static dma_addr_t tile_pci_dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction direction, - unsigned long attrs) -{ - BUG_ON(!valid_dma_direction(direction)); - - BUG_ON(offset + size > PAGE_SIZE); - __dma_prep_page(page, offset, size, direction); - - return page_to_pa(page) + offset + get_dma_offset(dev); -} - -static void tile_pci_dma_unmap_page(struct device *dev, dma_addr_t dma_address, - size_t size, - enum dma_data_direction direction, - unsigned long attrs) -{ - BUG_ON(!valid_dma_direction(direction)); - - dma_address -= get_dma_offset(dev); - - __dma_complete_page(pfn_to_page(PFN_DOWN(dma_address)), - dma_address & (PAGE_SIZE - 1), size, direction); -} - -static void tile_pci_dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, - size_t size, - enum dma_data_direction direction) -{ - BUG_ON(!valid_dma_direction(direction)); - - dma_handle -= get_dma_offset(dev); - - __dma_complete_pa_range(dma_handle, size, direction); -} - -static void tile_pci_dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, - size_t size, - enum dma_data_direction - direction) -{ - dma_handle -= get_dma_offset(dev); - - __dma_prep_pa_range(dma_handle, size, direction); -} - -static void tile_pci_dma_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sglist, - int nelems, - enum dma_data_direction direction) -{ - struct scatterlist *sg; - int i; - - BUG_ON(!valid_dma_direction(direction)); - WARN_ON(nelems == 0 || sglist->length == 0); - - for_each_sg(sglist, sg, nelems, i) { - dma_sync_single_for_cpu(dev, sg->dma_address, - sg_dma_len(sg), direction); - } -} - -static void tile_pci_dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sglist, - int nelems, - enum dma_data_direction direction) -{ - struct scatterlist *sg; - int i; - - BUG_ON(!valid_dma_direction(direction)); - WARN_ON(nelems == 0 || sglist->length == 0); - - for_each_sg(sglist, sg, nelems, i) { - dma_sync_single_for_device(dev, sg->dma_address, - sg_dma_len(sg), direction); - } -} - -static const struct dma_map_ops tile_pci_default_dma_map_ops = { - .alloc = tile_pci_dma_alloc_coherent, - .free = tile_pci_dma_free_coherent, - .map_page = tile_pci_dma_map_page, - .unmap_page = tile_pci_dma_unmap_page, - .map_sg = tile_pci_dma_map_sg, - .unmap_sg = tile_pci_dma_unmap_sg, - .sync_single_for_cpu = tile_pci_dma_sync_single_for_cpu, - .sync_single_for_device = tile_pci_dma_sync_single_for_device, - .sync_sg_for_cpu = tile_pci_dma_sync_sg_for_cpu, - .sync_sg_for_device = tile_pci_dma_sync_sg_for_device, -}; - -const struct dma_map_ops *gx_pci_dma_map_ops = &tile_pci_default_dma_map_ops; -EXPORT_SYMBOL(gx_pci_dma_map_ops); - -/* PCI DMA mapping functions for legacy PCI devices */ - -#ifdef CONFIG_SWIOTLB -static const struct dma_map_ops pci_hybrid_dma_ops = { - .alloc = swiotlb_alloc, - .free = swiotlb_free, - .map_page = tile_pci_dma_map_page, - .unmap_page = tile_pci_dma_unmap_page, - .map_sg = tile_pci_dma_map_sg, - .unmap_sg = tile_pci_dma_unmap_sg, - .sync_single_for_cpu = tile_pci_dma_sync_single_for_cpu, - .sync_single_for_device = tile_pci_dma_sync_single_for_device, - .sync_sg_for_cpu = tile_pci_dma_sync_sg_for_cpu, - .sync_sg_for_device = tile_pci_dma_sync_sg_for_device, -}; - -const struct dma_map_ops *gx_legacy_pci_dma_map_ops = &swiotlb_dma_ops; -const struct dma_map_ops *gx_hybrid_pci_dma_map_ops = &pci_hybrid_dma_ops; -#else -const struct dma_map_ops *gx_legacy_pci_dma_map_ops; -const struct dma_map_ops *gx_hybrid_pci_dma_map_ops; -#endif -EXPORT_SYMBOL(gx_legacy_pci_dma_map_ops); -EXPORT_SYMBOL(gx_hybrid_pci_dma_map_ops); - -int dma_set_mask(struct device *dev, u64 mask) -{ - const struct dma_map_ops *dma_ops = get_dma_ops(dev); - - /* - * For PCI devices with 64-bit DMA addressing capability, promote - * the dma_ops to hybrid, with the consistent memory DMA space limited - * to 32-bit. For 32-bit capable devices, limit the streaming DMA - * address range to max_direct_dma_addr. - */ - if (dma_ops == gx_pci_dma_map_ops || - dma_ops == gx_hybrid_pci_dma_map_ops || - dma_ops == gx_legacy_pci_dma_map_ops) { - if (mask == DMA_BIT_MASK(64) && - dma_ops == gx_legacy_pci_dma_map_ops) - set_dma_ops(dev, gx_hybrid_pci_dma_map_ops); - else if (mask > dev->archdata.max_direct_dma_addr) - mask = dev->archdata.max_direct_dma_addr; - } - - if (!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - - *dev->dma_mask = mask; - - return 0; -} -EXPORT_SYMBOL(dma_set_mask); - -#ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK -int dma_set_coherent_mask(struct device *dev, u64 mask) -{ - const struct dma_map_ops *dma_ops = get_dma_ops(dev); - - /* - * For PCI devices with 64-bit DMA addressing capability, promote - * the dma_ops to full capability for both streams and consistent - * memory access. For 32-bit capable devices, limit the consistent - * memory DMA range to max_direct_dma_addr. - */ - if (dma_ops == gx_pci_dma_map_ops || - dma_ops == gx_hybrid_pci_dma_map_ops || - dma_ops == gx_legacy_pci_dma_map_ops) { - if (mask == DMA_BIT_MASK(64)) - set_dma_ops(dev, gx_pci_dma_map_ops); - else if (mask > dev->archdata.max_direct_dma_addr) - mask = dev->archdata.max_direct_dma_addr; - } - - if (!dma_supported(dev, mask)) - return -EIO; - dev->coherent_dma_mask = mask; - return 0; -} -EXPORT_SYMBOL(dma_set_coherent_mask); -#endif - -#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK -/* - * The generic dma_get_required_mask() uses the highest physical address - * (max_pfn) to provide the hint to the PCI drivers regarding 32-bit or - * 64-bit DMA configuration. Since TILEGx has I/O TLB/MMU, allowing the - * DMAs to use the full 64-bit PCI address space and not limited by - * the physical memory space, we always let the PCI devices use - * 64-bit DMA if they have that capability, by returning the 64-bit - * DMA mask here. The device driver has the option to use 32-bit DMA if - * the device is not capable of 64-bit DMA. - */ -u64 dma_get_required_mask(struct device *dev) -{ - return DMA_BIT_MASK(64); -} -EXPORT_SYMBOL_GPL(dma_get_required_mask); -#endif diff --git a/arch/tile/kernel/pci.c b/arch/tile/kernel/pci.c deleted file mode 100644 index bbf81579b1f8..000000000000 --- a/arch/tile/kernel/pci.c +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - - -/* - * Initialization flow and process - * ------------------------------- - * - * This files contains the routines to search for PCI buses, - * enumerate the buses, and configure any attached devices. - * - * There are two entry points here: - * 1) tile_pci_init - * This sets up the pci_controller structs, and opens the - * FDs to the hypervisor. This is called from setup_arch() early - * in the boot process. - * 2) pcibios_init - * This probes the PCI bus(es) for any attached hardware. It's - * called by subsys_initcall. All of the real work is done by the - * generic Linux PCI layer. - * - */ - -static int pci_probe = 1; - -/* - * This flag tells if the platform is TILEmpower that needs - * special configuration for the PLX switch chip. - */ -int __ro_after_init tile_plx_gen1; - -static struct pci_controller controllers[TILE_NUM_PCIE]; -static int num_controllers; -static int pci_scan_flags[TILE_NUM_PCIE]; - -static struct pci_ops tile_cfg_ops; - - -/* - * Open a FD to the hypervisor PCI device. - * - * controller_id is the controller number, config type is 0 or 1 for - * config0 or config1 operations. - */ -static int tile_pcie_open(int controller_id, int config_type) -{ - char filename[32]; - int fd; - - sprintf(filename, "pcie/%d/config%d", controller_id, config_type); - - fd = hv_dev_open((HV_VirtAddr)filename, 0); - - return fd; -} - - -/* - * Get the IRQ numbers from the HV and set up the handlers for them. - */ -static int tile_init_irqs(int controller_id, struct pci_controller *controller) -{ - char filename[32]; - int fd; - int ret; - int x; - struct pcie_rc_config rc_config; - - sprintf(filename, "pcie/%d/ctl", controller_id); - fd = hv_dev_open((HV_VirtAddr)filename, 0); - if (fd < 0) { - pr_err("PCI: hv_dev_open(%s) failed\n", filename); - return -1; - } - ret = hv_dev_pread(fd, 0, (HV_VirtAddr)(&rc_config), - sizeof(rc_config), PCIE_RC_CONFIG_MASK_OFF); - hv_dev_close(fd); - if (ret != sizeof(rc_config)) { - pr_err("PCI: wanted %zd bytes, got %d\n", - sizeof(rc_config), ret); - return -1; - } - /* Record irq_base so that we can map INTx to IRQ # later. */ - controller->irq_base = rc_config.intr; - - for (x = 0; x < 4; x++) - tile_irq_activate(rc_config.intr + x, - TILE_IRQ_HW_CLEAR); - - if (rc_config.plx_gen1) - controller->plx_gen1 = 1; - - return 0; -} - -/* - * First initialization entry point, called from setup_arch(). - * - * Find valid controllers and fill in pci_controller structs for each - * of them. - * - * Returns the number of controllers discovered. - */ -int __init tile_pci_init(void) -{ - int i; - - if (!pci_probe) { - pr_info("PCI: disabled by boot argument\n"); - return 0; - } - - pr_info("PCI: Searching for controllers...\n"); - - /* Re-init number of PCIe controllers to support hot-plug feature. */ - num_controllers = 0; - - /* Do any configuration we need before using the PCIe */ - - for (i = 0; i < TILE_NUM_PCIE; i++) { - /* - * To see whether we need a real config op based on - * the results of pcibios_init(), to support PCIe hot-plug. - */ - if (pci_scan_flags[i] == 0) { - int hv_cfg_fd0 = -1; - int hv_cfg_fd1 = -1; - int hv_mem_fd = -1; - char name[32]; - struct pci_controller *controller; - - /* - * Open the fd to the HV. If it fails then this - * device doesn't exist. - */ - hv_cfg_fd0 = tile_pcie_open(i, 0); - if (hv_cfg_fd0 < 0) - continue; - hv_cfg_fd1 = tile_pcie_open(i, 1); - if (hv_cfg_fd1 < 0) { - pr_err("PCI: Couldn't open config fd to HV for controller %d\n", - i); - goto err_cont; - } - - sprintf(name, "pcie/%d/mem", i); - hv_mem_fd = hv_dev_open((HV_VirtAddr)name, 0); - if (hv_mem_fd < 0) { - pr_err("PCI: Could not open mem fd to HV!\n"); - goto err_cont; - } - - pr_info("PCI: Found PCI controller #%d\n", i); - - controller = &controllers[i]; - - controller->index = i; - controller->hv_cfg_fd[0] = hv_cfg_fd0; - controller->hv_cfg_fd[1] = hv_cfg_fd1; - controller->hv_mem_fd = hv_mem_fd; - controller->last_busno = 0xff; - controller->ops = &tile_cfg_ops; - - num_controllers++; - continue; - -err_cont: - if (hv_cfg_fd0 >= 0) - hv_dev_close(hv_cfg_fd0); - if (hv_cfg_fd1 >= 0) - hv_dev_close(hv_cfg_fd1); - if (hv_mem_fd >= 0) - hv_dev_close(hv_mem_fd); - continue; - } - } - - /* - * Before using the PCIe, see if we need to do any platform-specific - * configuration, such as the PLX switch Gen 1 issue on TILEmpower. - */ - for (i = 0; i < num_controllers; i++) { - struct pci_controller *controller = &controllers[i]; - - if (controller->plx_gen1) - tile_plx_gen1 = 1; - } - - return num_controllers; -} - -/* - * (pin - 1) converts from the PCI standard's [1:4] convention to - * a normal [0:3] range. - */ -static int tile_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) -{ - struct pci_controller *controller = - (struct pci_controller *)dev->sysdata; - return (pin - 1) + controller->irq_base; -} - - -static void fixup_read_and_payload_sizes(void) -{ - struct pci_dev *dev = NULL; - int smallest_max_payload = 0x1; /* Tile maxes out at 256 bytes. */ - int max_read_size = PCI_EXP_DEVCTL_READRQ_512B; - u16 new_values; - - /* Scan for the smallest maximum payload size. */ - for_each_pci_dev(dev) { - if (!pci_is_pcie(dev)) - continue; - - if (dev->pcie_mpss < smallest_max_payload) - smallest_max_payload = dev->pcie_mpss; - } - - /* Now, set the max_payload_size for all devices to that value. */ - new_values = max_read_size | (smallest_max_payload << 5); - for_each_pci_dev(dev) - pcie_capability_clear_and_set_word(dev, PCI_EXP_DEVCTL, - PCI_EXP_DEVCTL_PAYLOAD | PCI_EXP_DEVCTL_READRQ, - new_values); -} - - -/* - * Second PCI initialization entry point, called by subsys_initcall. - * - * The controllers have been set up by the time we get here, by a call to - * tile_pci_init. - */ -int __init pcibios_init(void) -{ - struct pci_host_bridge *bridge; - int i; - - pr_info("PCI: Probing PCI hardware\n"); - - /* - * Delay a bit in case devices aren't ready. Some devices are - * known to require at least 20ms here, but we use a more - * conservative value. - */ - msleep(250); - - /* Scan all of the recorded PCI controllers. */ - for (i = 0; i < TILE_NUM_PCIE; i++) { - /* - * Do real pcibios init ops if the controller is initialized - * by tile_pci_init() successfully and not initialized by - * pcibios_init() yet to support PCIe hot-plug. - */ - if (pci_scan_flags[i] == 0 && controllers[i].ops != NULL) { - struct pci_controller *controller = &controllers[i]; - struct pci_bus *bus; - LIST_HEAD(resources); - - if (tile_init_irqs(i, controller)) { - pr_err("PCI: Could not initialize IRQs\n"); - continue; - } - - pr_info("PCI: initializing controller #%d\n", i); - - pci_add_resource(&resources, &ioport_resource); - pci_add_resource(&resources, &iomem_resource); - - bridge = pci_alloc_host_bridge(0); - if (!bridge) - break; - - list_splice_init(&resources, &bridge->windows); - bridge->dev.parent = NULL; - bridge->sysdata = controller; - bridge->busnr = 0; - bridge->ops = controller->ops; - bridge->swizzle_irq = pci_common_swizzle; - bridge->map_irq = tile_map_irq; - - pci_scan_root_bus_bridge(bridge); - bus = bridge->bus; - controller->root_bus = bus; - controller->last_busno = bus->busn_res.end; - } - } - - /* - * This comes from the generic Linux PCI driver. - * - * It allocates all of the resources (I/O memory, etc) - * associated with the devices read in above. - */ - pci_assign_unassigned_resources(); - - /* Configure the max_read_size and max_payload_size values. */ - fixup_read_and_payload_sizes(); - - /* Record the I/O resources in the PCI controller structure. */ - for (i = 0; i < TILE_NUM_PCIE; i++) { - /* - * Do real pcibios init ops if the controller is initialized - * by tile_pci_init() successfully and not initialized by - * pcibios_init() yet to support PCIe hot-plug. - */ - if (pci_scan_flags[i] == 0 && controllers[i].ops != NULL) { - struct pci_bus *root_bus = controllers[i].root_bus; - struct pci_bus *next_bus; - struct pci_dev *dev; - - pci_bus_add_devices(root_bus); - - list_for_each_entry(dev, &root_bus->devices, bus_list) { - /* - * Find the PCI host controller, ie. the 1st - * bridge. - */ - if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && - (PCI_SLOT(dev->devfn) == 0)) { - next_bus = dev->subordinate; - controllers[i].mem_resources[0] = - *next_bus->resource[0]; - controllers[i].mem_resources[1] = - *next_bus->resource[1]; - controllers[i].mem_resources[2] = - *next_bus->resource[2]; - - /* Setup flags. */ - pci_scan_flags[i] = 1; - - break; - } - } - } - } - - return 0; -} -subsys_initcall(pcibios_init); - -void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling. */ -} - -/* Process any "pci=" kernel boot arguments. */ -char *__init pcibios_setup(char *str) -{ - if (!strcmp(str, "off")) { - pci_probe = 0; - return NULL; - } - return str; -} - -/* - * Enable memory and/or address decoding, as appropriate, for the - * device described by the 'dev' struct. - * - * This is called from the generic PCI layer, and can be called - * for bridges or endpoints. - */ -int pcibios_enable_device(struct pci_dev *dev, int mask) -{ - u16 cmd, old_cmd; - u8 header_type; - int i; - struct resource *r; - - pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type); - - pci_read_config_word(dev, PCI_COMMAND, &cmd); - old_cmd = cmd; - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - /* - * For bridges, we enable both memory and I/O decoding - * in call cases. - */ - cmd |= PCI_COMMAND_IO; - cmd |= PCI_COMMAND_MEMORY; - } else { - /* - * For endpoints, we enable memory and/or I/O decoding - * only if they have a memory resource of that type. - */ - for (i = 0; i < 6; i++) { - r = &dev->resource[i]; - if (r->flags & IORESOURCE_UNSET) { - pr_err("PCI: Device %s not available because of resource collisions\n", - pci_name(dev)); - return -EINVAL; - } - if (r->flags & IORESOURCE_IO) - cmd |= PCI_COMMAND_IO; - if (r->flags & IORESOURCE_MEM) - cmd |= PCI_COMMAND_MEMORY; - } - } - - /* - * We only write the command if it changed. - */ - if (cmd != old_cmd) - pci_write_config_word(dev, PCI_COMMAND, cmd); - return 0; -} - -/**************************************************************** - * - * Tile PCI config space read/write routines - * - ****************************************************************/ - -/* - * These are the normal read and write ops - * These are expanded with macros from pci_bus_read_config_byte() etc. - * - * devfn is the combined PCI slot & function. - * - * offset is in bytes, from the start of config space for the - * specified bus & slot. - */ - -static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset, - int size, u32 *val) -{ - struct pci_controller *controller = bus->sysdata; - int busnum = bus->number & 0xff; - int slot = (devfn >> 3) & 0x1f; - int function = devfn & 0x7; - u32 addr; - int config_mode = 1; - - /* - * There is no bridge between the Tile and bus 0, so we - * use config0 to talk to bus 0. - * - * If we're talking to a bus other than zero then we - * must have found a bridge. - */ - if (busnum == 0) { - /* - * We fake an empty slot for (busnum == 0) && (slot > 0), - * since there is only one slot on bus 0. - */ - if (slot) { - *val = 0xFFFFFFFF; - return 0; - } - config_mode = 0; - } - - addr = busnum << 20; /* Bus in 27:20 */ - addr |= slot << 15; /* Slot (device) in 19:15 */ - addr |= function << 12; /* Function is in 14:12 */ - addr |= (offset & 0xFFF); /* byte address in 0:11 */ - - return hv_dev_pread(controller->hv_cfg_fd[config_mode], 0, - (HV_VirtAddr)(val), size, addr); -} - - -/* - * See tile_cfg_read() for relevant comments. - * Note that "val" is the value to write, not a pointer to that value. - */ -static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset, - int size, u32 val) -{ - struct pci_controller *controller = bus->sysdata; - int busnum = bus->number & 0xff; - int slot = (devfn >> 3) & 0x1f; - int function = devfn & 0x7; - u32 addr; - int config_mode = 1; - HV_VirtAddr valp = (HV_VirtAddr)&val; - - /* - * For bus 0 slot 0 we use config 0 accesses. - */ - if (busnum == 0) { - /* - * We fake an empty slot for (busnum == 0) && (slot > 0), - * since there is only one slot on bus 0. - */ - if (slot) - return 0; - config_mode = 0; - } - - addr = busnum << 20; /* Bus in 27:20 */ - addr |= slot << 15; /* Slot (device) in 19:15 */ - addr |= function << 12; /* Function is in 14:12 */ - addr |= (offset & 0xFFF); /* byte address in 0:11 */ - -#ifdef __BIG_ENDIAN - /* Point to the correct part of the 32-bit "val". */ - valp += 4 - size; -#endif - - return hv_dev_pwrite(controller->hv_cfg_fd[config_mode], 0, - valp, size, addr); -} - - -static struct pci_ops tile_cfg_ops = { - .read = tile_cfg_read, - .write = tile_cfg_write, -}; - - -/* - * In the following, each PCI controller's mem_resources[1] - * represents its (non-prefetchable) PCI memory resource. - * mem_resources[0] and mem_resources[2] refer to its PCI I/O and - * prefetchable PCI memory resources, respectively. - * For more details, see pci_setup_bridge() in setup-bus.c. - * By comparing the target PCI memory address against the - * end address of controller 0, we can determine the controller - * that should accept the PCI memory access. - */ -#define TILE_READ(size, type) \ -type _tile_read##size(unsigned long addr) \ -{ \ - type val; \ - int idx = 0; \ - if (addr > controllers[0].mem_resources[1].end && \ - addr > controllers[0].mem_resources[2].end) \ - idx = 1; \ - if (hv_dev_pread(controllers[idx].hv_mem_fd, 0, \ - (HV_VirtAddr)(&val), sizeof(type), addr)) \ - pr_err("PCI: read %zd bytes at 0x%lX failed\n", \ - sizeof(type), addr); \ - return val; \ -} \ -EXPORT_SYMBOL(_tile_read##size) - -TILE_READ(b, u8); -TILE_READ(w, u16); -TILE_READ(l, u32); -TILE_READ(q, u64); - -#define TILE_WRITE(size, type) \ -void _tile_write##size(type val, unsigned long addr) \ -{ \ - int idx = 0; \ - if (addr > controllers[0].mem_resources[1].end && \ - addr > controllers[0].mem_resources[2].end) \ - idx = 1; \ - if (hv_dev_pwrite(controllers[idx].hv_mem_fd, 0, \ - (HV_VirtAddr)(&val), sizeof(type), addr)) \ - pr_err("PCI: write %zd bytes at 0x%lX failed\n", \ - sizeof(type), addr); \ -} \ -EXPORT_SYMBOL(_tile_write##size) - -TILE_WRITE(b, u8); -TILE_WRITE(w, u16); -TILE_WRITE(l, u32); -TILE_WRITE(q, u64); diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c deleted file mode 100644 index 9aa238ac7b35..000000000000 --- a/arch/tile/kernel/pci_gx.c +++ /dev/null @@ -1,1592 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -/* - * This file contains the routines to search for PCI buses, - * enumerate the buses, and configure any attached devices. - */ - -#define DEBUG_PCI_CFG 0 - -#if DEBUG_PCI_CFG -#define TRACE_CFG_WR(size, val, bus, dev, func, offset) \ - pr_info("CFG WR %d-byte VAL %#x to bus %d dev %d func %d addr %u\n", \ - size, val, bus, dev, func, offset & 0xFFF); -#define TRACE_CFG_RD(size, val, bus, dev, func, offset) \ - pr_info("CFG RD %d-byte VAL %#x from bus %d dev %d func %d addr %u\n", \ - size, val, bus, dev, func, offset & 0xFFF); -#else -#define TRACE_CFG_WR(...) -#define TRACE_CFG_RD(...) -#endif - -static int pci_probe = 1; - -/* Information on the PCIe RC ports configuration. */ -static int pcie_rc[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES]; - -/* - * On some platforms with one or more Gx endpoint ports, we need to - * delay the PCIe RC port probe for a few seconds to work around - * a HW PCIe link-training bug. The exact delay is specified with - * a kernel boot argument in the form of "pcie_rc_delay=T,P,S", - * where T is the TRIO instance number, P is the port number and S is - * the delay in seconds. If the argument is specified, but the delay is - * not provided, the value will be DEFAULT_RC_DELAY. - */ -static int rc_delay[TILEGX_NUM_TRIO][TILEGX_TRIO_PCIES]; - -/* Default number of seconds that the PCIe RC port probe can be delayed. */ -#define DEFAULT_RC_DELAY 10 - -/* The PCI I/O space size in each PCI domain. */ -#define IO_SPACE_SIZE 0x10000 - -/* Provide shorter versions of some very long constant names. */ -#define AUTO_CONFIG_RC \ - TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC -#define AUTO_CONFIG_RC_G1 \ - TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_RC_G1 -#define AUTO_CONFIG_EP \ - TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT -#define AUTO_CONFIG_EP_G1 \ - TRIO_PCIE_INTFC_PORT_CONFIG__STRAP_STATE_VAL_AUTO_CONFIG_ENDPOINT_G1 - -/* Array of the PCIe ports configuration info obtained from the BIB. */ -struct pcie_trio_ports_property pcie_ports[TILEGX_NUM_TRIO]; - -/* Number of configured TRIO instances. */ -int num_trio_shims; - -/* All drivers share the TRIO contexts defined here. */ -gxio_trio_context_t trio_contexts[TILEGX_NUM_TRIO]; - -/* Pointer to an array of PCIe RC controllers. */ -struct pci_controller pci_controllers[TILEGX_NUM_TRIO * TILEGX_TRIO_PCIES]; -int num_rc_controllers; - -static struct pci_ops tile_cfg_ops; - -/* Mask of CPUs that should receive PCIe interrupts. */ -static struct cpumask intr_cpus_map; - -/* - * Pick a CPU to receive and handle the PCIe interrupts, based on the IRQ #. - * For now, we simply send interrupts to non-dataplane CPUs. - * We may implement methods to allow user to specify the target CPUs, - * e.g. via boot arguments. - */ -static int tile_irq_cpu(int irq) -{ - unsigned int count; - int i = 0; - int cpu; - - count = cpumask_weight(&intr_cpus_map); - if (unlikely(count == 0)) { - pr_warn("intr_cpus_map empty, interrupts will be delivered to dataplane tiles\n"); - return irq % (smp_height * smp_width); - } - - count = irq % count; - for_each_cpu(cpu, &intr_cpus_map) { - if (i++ == count) - break; - } - return cpu; -} - -/* Open a file descriptor to the TRIO shim. */ -static int tile_pcie_open(int trio_index) -{ - gxio_trio_context_t *context = &trio_contexts[trio_index]; - int ret; - int mac; - - /* This opens a file descriptor to the TRIO shim. */ - ret = gxio_trio_init(context, trio_index); - if (ret < 0) - goto gxio_trio_init_failure; - - /* Allocate an ASID for the kernel. */ - ret = gxio_trio_alloc_asids(context, 1, 0, 0); - if (ret < 0) { - pr_err("PCI: ASID alloc failure on TRIO %d, give up\n", - trio_index); - goto asid_alloc_failure; - } - - context->asid = ret; - -#ifdef USE_SHARED_PCIE_CONFIG_REGION - /* - * Alloc a PIO region for config access, shared by all MACs per TRIO. - * This shouldn't fail since the kernel is supposed to the first - * client of the TRIO's PIO regions. - */ - ret = gxio_trio_alloc_pio_regions(context, 1, 0, 0); - if (ret < 0) { - pr_err("PCI: CFG PIO alloc failure on TRIO %d, give up\n", - trio_index); - goto pio_alloc_failure; - } - - context->pio_cfg_index = ret; - - /* - * For PIO CFG, the bus_address_hi parameter is 0. The mac parameter - * is also 0 because it is specified in PIO_REGION_SETUP_CFG_ADDR. - */ - ret = gxio_trio_init_pio_region_aux(context, context->pio_cfg_index, - 0, 0, HV_TRIO_PIO_FLAG_CONFIG_SPACE); - if (ret < 0) { - pr_err("PCI: CFG PIO init failure on TRIO %d, give up\n", - trio_index); - goto pio_alloc_failure; - } -#endif - - /* Get the properties of the PCIe ports on this TRIO instance. */ - ret = gxio_trio_get_port_property(context, &pcie_ports[trio_index]); - if (ret < 0) { - pr_err("PCI: PCIE_GET_PORT_PROPERTY failure, error %d, on TRIO %d\n", - ret, trio_index); - goto get_port_property_failure; - } - - context->mmio_base_mac = - iorpc_ioremap(context->fd, 0, HV_TRIO_CONFIG_IOREMAP_SIZE); - if (context->mmio_base_mac == NULL) { - pr_err("PCI: TRIO config space mapping failure, error %d, on TRIO %d\n", - ret, trio_index); - ret = -ENOMEM; - - goto trio_mmio_mapping_failure; - } - - /* Check the port strap state which will override the BIB setting. */ - for (mac = 0; mac < TILEGX_TRIO_PCIES; mac++) { - TRIO_PCIE_INTFC_PORT_CONFIG_t port_config; - unsigned int reg_offset; - - /* Ignore ports that are not specified in the BIB. */ - if (!pcie_ports[trio_index].ports[mac].allow_rc && - !pcie_ports[trio_index].ports[mac].allow_ep) - continue; - - reg_offset = - (TRIO_PCIE_INTFC_PORT_CONFIG << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE << - TRIO_CFG_REGION_ADDR__INTFC_SHIFT) | - (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - - port_config.word = - __gxio_mmio_read(context->mmio_base_mac + reg_offset); - - if (port_config.strap_state != AUTO_CONFIG_RC && - port_config.strap_state != AUTO_CONFIG_RC_G1) { - /* - * If this is really intended to be an EP port, record - * it so that the endpoint driver will know about it. - */ - if (port_config.strap_state == AUTO_CONFIG_EP || - port_config.strap_state == AUTO_CONFIG_EP_G1) - pcie_ports[trio_index].ports[mac].allow_ep = 1; - } - } - - return ret; - -trio_mmio_mapping_failure: -get_port_property_failure: -asid_alloc_failure: -#ifdef USE_SHARED_PCIE_CONFIG_REGION -pio_alloc_failure: -#endif - hv_dev_close(context->fd); -gxio_trio_init_failure: - context->fd = -1; - - return ret; -} - -static int __init tile_trio_init(void) -{ - int i; - - /* We loop over all the TRIO shims. */ - for (i = 0; i < TILEGX_NUM_TRIO; i++) { - if (tile_pcie_open(i) < 0) - continue; - num_trio_shims++; - } - - return 0; -} -postcore_initcall(tile_trio_init); - -static void tilegx_legacy_irq_ack(struct irq_data *d) -{ - __insn_mtspr(SPR_IPI_EVENT_RESET_K, 1UL << d->irq); -} - -static void tilegx_legacy_irq_mask(struct irq_data *d) -{ - __insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq); -} - -static void tilegx_legacy_irq_unmask(struct irq_data *d) -{ - __insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq); -} - -static struct irq_chip tilegx_legacy_irq_chip = { - .name = "tilegx_legacy_irq", - .irq_ack = tilegx_legacy_irq_ack, - .irq_mask = tilegx_legacy_irq_mask, - .irq_unmask = tilegx_legacy_irq_unmask, - - /* TBD: support set_affinity. */ -}; - -/* - * This is a wrapper function of the kernel level-trigger interrupt - * handler handle_level_irq() for PCI legacy interrupts. The TRIO - * is configured such that only INTx Assert interrupts are proxied - * to Linux which just calls handle_level_irq() after clearing the - * MAC INTx Assert status bit associated with this interrupt. - */ -static void trio_handle_level_irq(struct irq_desc *desc) -{ - struct pci_controller *controller = irq_desc_get_handler_data(desc); - gxio_trio_context_t *trio_context = controller->trio; - uint64_t intx = (uint64_t)irq_desc_get_chip_data(desc); - int mac = controller->mac; - unsigned int reg_offset; - uint64_t level_mask; - - handle_level_irq(desc); - - /* - * Clear the INTx Level status, otherwise future interrupts are - * not sent. - */ - reg_offset = (TRIO_PCIE_INTFC_MAC_INT_STS << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE << - TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | - (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - - level_mask = TRIO_PCIE_INTFC_MAC_INT_STS__INT_LEVEL_MASK << intx; - - __gxio_mmio_write(trio_context->mmio_base_mac + reg_offset, level_mask); -} - -/* - * Create kernel irqs and set up the handlers for the legacy interrupts. - * Also some minimum initialization for the MSI support. - */ -static int tile_init_irqs(struct pci_controller *controller) -{ - int i; - int j; - int irq; - int result; - - cpumask_copy(&intr_cpus_map, cpu_online_mask); - - - for (i = 0; i < 4; i++) { - gxio_trio_context_t *context = controller->trio; - int cpu; - - /* Ask the kernel to allocate an IRQ. */ - irq = irq_alloc_hwirq(-1); - if (!irq) { - pr_err("PCI: no free irq vectors, failed for %d\n", i); - goto free_irqs; - } - controller->irq_intx_table[i] = irq; - - /* Distribute the 4 IRQs to different tiles. */ - cpu = tile_irq_cpu(irq); - - /* Configure the TRIO intr binding for this IRQ. */ - result = gxio_trio_config_legacy_intr(context, cpu_x(cpu), - cpu_y(cpu), KERNEL_PL, - irq, controller->mac, i); - if (result < 0) { - pr_err("PCI: MAC intx config failed for %d\n", i); - - goto free_irqs; - } - - /* Register the IRQ handler with the kernel. */ - irq_set_chip_and_handler(irq, &tilegx_legacy_irq_chip, - trio_handle_level_irq); - irq_set_chip_data(irq, (void *)(uint64_t)i); - irq_set_handler_data(irq, controller); - } - - return 0; - -free_irqs: - for (j = 0; j < i; j++) - irq_free_hwirq(controller->irq_intx_table[j]); - - return -1; -} - -/* - * Return 1 if the port is strapped to operate in RC mode. - */ -static int -strapped_for_rc(gxio_trio_context_t *trio_context, int mac) -{ - TRIO_PCIE_INTFC_PORT_CONFIG_t port_config; - unsigned int reg_offset; - - /* Check the port configuration. */ - reg_offset = - (TRIO_PCIE_INTFC_PORT_CONFIG << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE << - TRIO_CFG_REGION_ADDR__INTFC_SHIFT) | - (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - port_config.word = - __gxio_mmio_read(trio_context->mmio_base_mac + reg_offset); - - if (port_config.strap_state == AUTO_CONFIG_RC || - port_config.strap_state == AUTO_CONFIG_RC_G1) - return 1; - else - return 0; -} - -/* - * Find valid controllers and fill in pci_controller structs for each - * of them. - * - * Return the number of controllers discovered. - */ -int __init tile_pci_init(void) -{ - int ctl_index = 0; - int i, j; - - if (!pci_probe) { - pr_info("PCI: disabled by boot argument\n"); - return 0; - } - - pr_info("PCI: Searching for controllers...\n"); - - if (num_trio_shims == 0 || sim_is_simulator()) - return 0; - - /* - * Now determine which PCIe ports are configured to operate in RC - * mode. There is a difference in the port configuration capability - * between the Gx36 and Gx72 devices. - * - * The Gx36 has configuration capability for each of the 3 PCIe - * interfaces (disable, auto endpoint, auto RC, etc.). - * On the Gx72, you can only select one of the 3 PCIe interfaces per - * TRIO to train automatically. Further, the allowable training modes - * are reduced to four options (auto endpoint, auto RC, stream x1, - * stream x4). - * - * For Gx36 ports, it must be allowed to be in RC mode by the - * Board Information Block, and the hardware strapping pins must be - * set to RC mode. - * - * For Gx72 ports, the port will operate in RC mode if either of the - * following is true: - * 1. It is allowed to be in RC mode by the Board Information Block, - * and the BIB doesn't allow the EP mode. - * 2. It is allowed to be in either the RC or the EP mode by the BIB, - * and the hardware strapping pin is set to RC mode. - */ - for (i = 0; i < TILEGX_NUM_TRIO; i++) { - gxio_trio_context_t *context = &trio_contexts[i]; - - if (context->fd < 0) - continue; - - for (j = 0; j < TILEGX_TRIO_PCIES; j++) { - int is_rc = 0; - - if (pcie_ports[i].is_gx72 && - pcie_ports[i].ports[j].allow_rc) { - if (!pcie_ports[i].ports[j].allow_ep || - strapped_for_rc(context, j)) - is_rc = 1; - } else if (pcie_ports[i].ports[j].allow_rc && - strapped_for_rc(context, j)) { - is_rc = 1; - } - if (is_rc) { - pcie_rc[i][j] = 1; - num_rc_controllers++; - } - } - } - - /* Return if no PCIe ports are configured to operate in RC mode. */ - if (num_rc_controllers == 0) - return 0; - - /* Set the TRIO pointer and MAC index for each PCIe RC port. */ - for (i = 0; i < TILEGX_NUM_TRIO; i++) { - for (j = 0; j < TILEGX_TRIO_PCIES; j++) { - if (pcie_rc[i][j]) { - pci_controllers[ctl_index].trio = - &trio_contexts[i]; - pci_controllers[ctl_index].mac = j; - pci_controllers[ctl_index].trio_index = i; - ctl_index++; - if (ctl_index == num_rc_controllers) - goto out; - } - } - } - -out: - /* Configure each PCIe RC port. */ - for (i = 0; i < num_rc_controllers; i++) { - - /* Configure the PCIe MAC to run in RC mode. */ - struct pci_controller *controller = &pci_controllers[i]; - - controller->index = i; - controller->ops = &tile_cfg_ops; - - controller->io_space.start = PCIBIOS_MIN_IO + - (i * IO_SPACE_SIZE); - controller->io_space.end = controller->io_space.start + - IO_SPACE_SIZE - 1; - BUG_ON(controller->io_space.end > IO_SPACE_LIMIT); - controller->io_space.flags = IORESOURCE_IO; - snprintf(controller->io_space_name, - sizeof(controller->io_space_name), - "PCI I/O domain %d", i); - controller->io_space.name = controller->io_space_name; - - /* - * The PCI memory resource is located above the PA space. - * For every host bridge, the BAR window or the MMIO aperture - * is in range [3GB, 4GB - 1] of a 4GB space beyond the - * PA space. - */ - controller->mem_offset = TILE_PCI_MEM_START + - (i * TILE_PCI_BAR_WINDOW_TOP); - controller->mem_space.start = controller->mem_offset + - TILE_PCI_BAR_WINDOW_TOP - TILE_PCI_BAR_WINDOW_SIZE; - controller->mem_space.end = controller->mem_offset + - TILE_PCI_BAR_WINDOW_TOP - 1; - controller->mem_space.flags = IORESOURCE_MEM; - snprintf(controller->mem_space_name, - sizeof(controller->mem_space_name), - "PCI mem domain %d", i); - controller->mem_space.name = controller->mem_space_name; - } - - return num_rc_controllers; -} - -/* - * (pin - 1) converts from the PCI standard's [1:4] convention to - * a normal [0:3] range. - */ -static int tile_map_irq(const struct pci_dev *dev, u8 device, u8 pin) -{ - struct pci_controller *controller = - (struct pci_controller *)dev->sysdata; - return controller->irq_intx_table[pin - 1]; -} - -static void fixup_read_and_payload_sizes(struct pci_controller *controller) -{ - gxio_trio_context_t *trio_context = controller->trio; - struct pci_bus *root_bus = controller->root_bus; - TRIO_PCIE_RC_DEVICE_CONTROL_t dev_control; - TRIO_PCIE_RC_DEVICE_CAP_t rc_dev_cap; - unsigned int reg_offset; - struct pci_bus *child; - int mac; - int err; - - mac = controller->mac; - - /* Set our max read request size to be 4KB. */ - reg_offset = - (TRIO_PCIE_RC_DEVICE_CONTROL << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD << - TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | - (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - - dev_control.word = __gxio_mmio_read32(trio_context->mmio_base_mac + - reg_offset); - dev_control.max_read_req_sz = 5; - __gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset, - dev_control.word); - - /* - * Set the max payload size supported by this Gx PCIe MAC. - * Though Gx PCIe supports Max Payload Size of up to 1024 bytes, - * experiments have shown that setting MPS to 256 yields the - * best performance. - */ - reg_offset = - (TRIO_PCIE_RC_DEVICE_CAP << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD << - TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | - (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - - rc_dev_cap.word = __gxio_mmio_read32(trio_context->mmio_base_mac + - reg_offset); - rc_dev_cap.mps_sup = 1; - __gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset, - rc_dev_cap.word); - - /* Configure PCI Express MPS setting. */ - list_for_each_entry(child, &root_bus->children, node) - pcie_bus_configure_settings(child); - - /* - * Set the mac_config register in trio based on the MPS/MRS of the link. - */ - reg_offset = - (TRIO_PCIE_RC_DEVICE_CONTROL << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD << - TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | - (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - - dev_control.word = __gxio_mmio_read32(trio_context->mmio_base_mac + - reg_offset); - - err = gxio_trio_set_mps_mrs(trio_context, - dev_control.max_payload_size, - dev_control.max_read_req_sz, - mac); - if (err < 0) { - pr_err("PCI: PCIE_CONFIGURE_MAC_MPS_MRS failure, MAC %d on TRIO %d\n", - mac, controller->trio_index); - } -} - -static int setup_pcie_rc_delay(char *str) -{ - unsigned long delay = 0; - unsigned long trio_index; - unsigned long mac; - - if (str == NULL || !isdigit(*str)) - return -EINVAL; - trio_index = simple_strtoul(str, (char **)&str, 10); - if (trio_index >= TILEGX_NUM_TRIO) - return -EINVAL; - - if (*str != ',') - return -EINVAL; - - str++; - if (!isdigit(*str)) - return -EINVAL; - mac = simple_strtoul(str, (char **)&str, 10); - if (mac >= TILEGX_TRIO_PCIES) - return -EINVAL; - - if (*str != '\0') { - if (*str != ',') - return -EINVAL; - - str++; - if (!isdigit(*str)) - return -EINVAL; - delay = simple_strtoul(str, (char **)&str, 10); - } - - rc_delay[trio_index][mac] = delay ? : DEFAULT_RC_DELAY; - return 0; -} -early_param("pcie_rc_delay", setup_pcie_rc_delay); - -/* PCI initialization entry point, called by subsys_initcall. */ -int __init pcibios_init(void) -{ - resource_size_t offset; - LIST_HEAD(resources); - int next_busno; - struct pci_host_bridge *bridge; - int i; - - tile_pci_init(); - - if (num_rc_controllers == 0) - return 0; - - /* - * Delay a bit in case devices aren't ready. Some devices are - * known to require at least 20ms here, but we use a more - * conservative value. - */ - msleep(250); - - /* Scan all of the recorded PCI controllers. */ - for (next_busno = 0, i = 0; i < num_rc_controllers; i++) { - struct pci_controller *controller = &pci_controllers[i]; - gxio_trio_context_t *trio_context = controller->trio; - TRIO_PCIE_INTFC_PORT_STATUS_t port_status; - TRIO_PCIE_INTFC_TX_FIFO_CTL_t tx_fifo_ctl; - struct pci_bus *bus; - unsigned int reg_offset; - unsigned int class_code_revision; - int trio_index; - int mac; - int ret; - - if (trio_context->fd < 0) - continue; - - trio_index = controller->trio_index; - mac = controller->mac; - - /* - * Check for PCIe link-up status to decide if we need - * to force the link to come up. - */ - reg_offset = - (TRIO_PCIE_INTFC_PORT_STATUS << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE << - TRIO_CFG_REGION_ADDR__INTFC_SHIFT) | - (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - - port_status.word = - __gxio_mmio_read(trio_context->mmio_base_mac + - reg_offset); - if (!port_status.dl_up) { - if (rc_delay[trio_index][mac]) { - pr_info("Delaying PCIe RC TRIO init %d sec on MAC %d on TRIO %d\n", - rc_delay[trio_index][mac], mac, - trio_index); - msleep(rc_delay[trio_index][mac] * 1000); - } - ret = gxio_trio_force_rc_link_up(trio_context, mac); - if (ret < 0) - pr_err("PCI: PCIE_FORCE_LINK_UP failure, MAC %d on TRIO %d\n", - mac, trio_index); - } - - pr_info("PCI: Found PCI controller #%d on TRIO %d MAC %d\n", - i, trio_index, controller->mac); - - /* Delay the bus probe if needed. */ - if (rc_delay[trio_index][mac]) { - pr_info("Delaying PCIe RC bus enumerating %d sec on MAC %d on TRIO %d\n", - rc_delay[trio_index][mac], mac, trio_index); - msleep(rc_delay[trio_index][mac] * 1000); - } else { - /* - * Wait a bit here because some EP devices - * take longer to come up. - */ - msleep(1000); - } - - /* Check for PCIe link-up status again. */ - port_status.word = - __gxio_mmio_read(trio_context->mmio_base_mac + - reg_offset); - if (!port_status.dl_up) { - if (pcie_ports[trio_index].ports[mac].removable) { - pr_info("PCI: link is down, MAC %d on TRIO %d\n", - mac, trio_index); - pr_info("This is expected if no PCIe card is connected to this link\n"); - } else - pr_err("PCI: link is down, MAC %d on TRIO %d\n", - mac, trio_index); - continue; - } - - /* - * Ensure that the link can come out of L1 power down state. - * Strictly speaking, this is needed only in the case of - * heavy RC-initiated DMAs. - */ - reg_offset = - (TRIO_PCIE_INTFC_TX_FIFO_CTL << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_INTERFACE << - TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | - (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - tx_fifo_ctl.word = - __gxio_mmio_read(trio_context->mmio_base_mac + - reg_offset); - tx_fifo_ctl.min_p_credits = 0; - __gxio_mmio_write(trio_context->mmio_base_mac + reg_offset, - tx_fifo_ctl.word); - - /* - * Change the device ID so that Linux bus crawl doesn't confuse - * the internal bridge with any Tilera endpoints. - */ - reg_offset = - (TRIO_PCIE_RC_DEVICE_ID_VEN_ID << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD << - TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | - (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - - __gxio_mmio_write32(trio_context->mmio_base_mac + reg_offset, - (TILERA_GX36_RC_DEV_ID << - TRIO_PCIE_RC_DEVICE_ID_VEN_ID__DEV_ID_SHIFT) | - TILERA_VENDOR_ID); - - /* Set the internal P2P bridge class code. */ - reg_offset = - (TRIO_PCIE_RC_REVISION_ID << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_STANDARD << - TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | - (mac << TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - - class_code_revision = - __gxio_mmio_read32(trio_context->mmio_base_mac + - reg_offset); - class_code_revision = (class_code_revision & 0xff) | - (PCI_CLASS_BRIDGE_PCI << 16); - - __gxio_mmio_write32(trio_context->mmio_base_mac + - reg_offset, class_code_revision); - -#ifdef USE_SHARED_PCIE_CONFIG_REGION - - /* Map in the MMIO space for the PIO region. */ - offset = HV_TRIO_PIO_OFFSET(trio_context->pio_cfg_index) | - (((unsigned long long)mac) << - TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT); - -#else - - /* Alloc a PIO region for PCI config access per MAC. */ - ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0); - if (ret < 0) { - pr_err("PCI: PCI CFG PIO alloc failure for mac %d on TRIO %d, give up\n", - mac, trio_index); - - continue; - } - - trio_context->pio_cfg_index[mac] = ret; - - /* For PIO CFG, the bus_address_hi parameter is 0. */ - ret = gxio_trio_init_pio_region_aux(trio_context, - trio_context->pio_cfg_index[mac], - mac, 0, HV_TRIO_PIO_FLAG_CONFIG_SPACE); - if (ret < 0) { - pr_err("PCI: PCI CFG PIO init failure for mac %d on TRIO %d, give up\n", - mac, trio_index); - - continue; - } - - offset = HV_TRIO_PIO_OFFSET(trio_context->pio_cfg_index[mac]) | - (((unsigned long long)mac) << - TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT); - -#endif - - /* - * To save VMALLOC space, we take advantage of the fact that - * bit 29 in the PIO CFG address format is reserved 0. With - * TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT being 30, - * this cuts VMALLOC space usage from 1GB to 512MB per mac. - */ - trio_context->mmio_base_pio_cfg[mac] = - iorpc_ioremap(trio_context->fd, offset, (1UL << - (TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR__MAC_SHIFT - 1))); - if (trio_context->mmio_base_pio_cfg[mac] == NULL) { - pr_err("PCI: PIO map failure for mac %d on TRIO %d\n", - mac, trio_index); - - continue; - } - - /* Initialize the PCIe interrupts. */ - if (tile_init_irqs(controller)) { - pr_err("PCI: IRQs init failure for mac %d on TRIO %d\n", - mac, trio_index); - - continue; - } - - /* - * The PCI memory resource is located above the PA space. - * The memory range for the PCI root bus should not overlap - * with the physical RAM. - */ - pci_add_resource_offset(&resources, &controller->mem_space, - controller->mem_offset); - pci_add_resource(&resources, &controller->io_space); - controller->first_busno = next_busno; - - bridge = pci_alloc_host_bridge(0); - if (!bridge) - break; - - list_splice_init(&resources, &bridge->windows); - bridge->dev.parent = NULL; - bridge->sysdata = controller; - bridge->busnr = next_busno; - bridge->ops = controller->ops; - bridge->swizzle_irq = pci_common_swizzle; - bridge->map_irq = tile_map_irq; - - pci_scan_root_bus_bridge(bridge); - bus = bridge->bus; - controller->root_bus = bus; - next_busno = bus->busn_res.end + 1; - } - - /* - * This comes from the generic Linux PCI driver. - * - * It allocates all of the resources (I/O memory, etc) - * associated with the devices read in above. - */ - pci_assign_unassigned_resources(); - - /* Record the I/O resources in the PCI controller structure. */ - for (i = 0; i < num_rc_controllers; i++) { - struct pci_controller *controller = &pci_controllers[i]; - gxio_trio_context_t *trio_context = controller->trio; - struct pci_bus *root_bus = pci_controllers[i].root_bus; - int ret; - int j; - - /* - * Skip controllers that are not properly initialized or - * have down links. - */ - if (root_bus == NULL) - continue; - - /* Configure the max_payload_size values for this domain. */ - fixup_read_and_payload_sizes(controller); - - /* Alloc a PIO region for PCI memory access for each RC port. */ - ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0); - if (ret < 0) { - pr_err("PCI: MEM PIO alloc failure on TRIO %d mac %d, give up\n", - controller->trio_index, controller->mac); - - continue; - } - - controller->pio_mem_index = ret; - - /* - * For PIO MEM, the bus_address_hi parameter is hard-coded 0 - * because we always assign 32-bit PCI bus BAR ranges. - */ - ret = gxio_trio_init_pio_region_aux(trio_context, - controller->pio_mem_index, - controller->mac, - 0, - 0); - if (ret < 0) { - pr_err("PCI: MEM PIO init failure on TRIO %d mac %d, give up\n", - controller->trio_index, controller->mac); - - continue; - } - -#ifdef CONFIG_TILE_PCI_IO - /* - * Alloc a PIO region for PCI I/O space access for each RC port. - */ - ret = gxio_trio_alloc_pio_regions(trio_context, 1, 0, 0); - if (ret < 0) { - pr_err("PCI: I/O PIO alloc failure on TRIO %d mac %d, give up\n", - controller->trio_index, controller->mac); - - continue; - } - - controller->pio_io_index = ret; - - /* - * For PIO IO, the bus_address_hi parameter is hard-coded 0 - * because PCI I/O address space is 32-bit. - */ - ret = gxio_trio_init_pio_region_aux(trio_context, - controller->pio_io_index, - controller->mac, - 0, - HV_TRIO_PIO_FLAG_IO_SPACE); - if (ret < 0) { - pr_err("PCI: I/O PIO init failure on TRIO %d mac %d, give up\n", - controller->trio_index, controller->mac); - - continue; - } -#endif - - /* - * Configure a Mem-Map region for each memory controller so - * that Linux can map all of its PA space to the PCI bus. - * Use the IOMMU to handle hash-for-home memory. - */ - for_each_online_node(j) { - unsigned long start_pfn = node_start_pfn[j]; - unsigned long end_pfn = node_end_pfn[j]; - unsigned long nr_pages = end_pfn - start_pfn; - - ret = gxio_trio_alloc_memory_maps(trio_context, 1, 0, - 0); - if (ret < 0) { - pr_err("PCI: Mem-Map alloc failure on TRIO %d mac %d for MC %d, give up\n", - controller->trio_index, controller->mac, - j); - - goto alloc_mem_map_failed; - } - - controller->mem_maps[j] = ret; - - /* - * Initialize the Mem-Map and the I/O MMU so that all - * the physical memory can be accessed by the endpoint - * devices. The base bus address is set to the base CPA - * of this memory controller plus an offset (see pci.h). - * The region's base VA is set to the base CPA. The - * I/O MMU table essentially translates the CPA to - * the real PA. Implicitly, for node 0, we create - * a separate Mem-Map region that serves as the inbound - * window for legacy 32-bit devices. This is a direct - * map of the low 4GB CPA space. - */ - ret = gxio_trio_init_memory_map_mmu_aux(trio_context, - controller->mem_maps[j], - start_pfn << PAGE_SHIFT, - nr_pages << PAGE_SHIFT, - trio_context->asid, - controller->mac, - (start_pfn << PAGE_SHIFT) + - TILE_PCI_MEM_MAP_BASE_OFFSET, - j, - GXIO_TRIO_ORDER_MODE_UNORDERED); - if (ret < 0) { - pr_err("PCI: Mem-Map init failure on TRIO %d mac %d for MC %d, give up\n", - controller->trio_index, controller->mac, - j); - - goto alloc_mem_map_failed; - } - continue; - -alloc_mem_map_failed: - break; - } - - pci_bus_add_devices(root_bus); - } - - return 0; -} -subsys_initcall(pcibios_init); - -/* Process any "pci=" kernel boot arguments. */ -char *__init pcibios_setup(char *str) -{ - if (!strcmp(str, "off")) { - pci_probe = 0; - return NULL; - } - return str; -} - -/* - * Called for each device after PCI setup is done. - * We initialize the PCI device capabilities conservatively, assuming that - * all devices can only address the 32-bit DMA space. The exception here is - * that the device dma_offset is set to the value that matches the 64-bit - * capable devices. This is OK because dma_offset is not used by legacy - * dma_ops, nor by the hybrid dma_ops's streaming DMAs, which are 64-bit ops. - * This implementation matches the kernel design of setting PCI devices' - * coherent_dma_mask to 0xffffffffull by default, allowing the device drivers - * to skip calling pci_set_consistent_dma_mask(DMA_BIT_MASK(32)). - */ -static void pcibios_fixup_final(struct pci_dev *pdev) -{ - set_dma_ops(&pdev->dev, gx_legacy_pci_dma_map_ops); - set_dma_offset(&pdev->dev, TILE_PCI_MEM_MAP_BASE_OFFSET); - pdev->dev.archdata.max_direct_dma_addr = - TILE_PCI_MAX_DIRECT_DMA_ADDRESS; - pdev->dev.coherent_dma_mask = TILE_PCI_MAX_DIRECT_DMA_ADDRESS; -} -DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_final); - -/* Map a PCI MMIO bus address into VA space. */ -void __iomem *ioremap(resource_size_t phys_addr, unsigned long size) -{ - struct pci_controller *controller = NULL; - resource_size_t bar_start; - resource_size_t bar_end; - resource_size_t offset; - resource_size_t start; - resource_size_t end; - int trio_fd; - int i; - - start = phys_addr; - end = phys_addr + size - 1; - - /* - * By searching phys_addr in each controller's mem_space, we can - * determine the controller that should accept the PCI memory access. - */ - for (i = 0; i < num_rc_controllers; i++) { - /* - * Skip controllers that are not properly initialized or - * have down links. - */ - if (pci_controllers[i].root_bus == NULL) - continue; - - bar_start = pci_controllers[i].mem_space.start; - bar_end = pci_controllers[i].mem_space.end; - - if ((start >= bar_start) && (end <= bar_end)) { - controller = &pci_controllers[i]; - break; - } - } - - if (controller == NULL) - return NULL; - - trio_fd = controller->trio->fd; - - /* Convert the resource start to the bus address offset. */ - start = phys_addr - controller->mem_offset; - - offset = HV_TRIO_PIO_OFFSET(controller->pio_mem_index) + start; - - /* We need to keep the PCI bus address's in-page offset in the VA. */ - return iorpc_ioremap(trio_fd, offset, size) + - (start & (PAGE_SIZE - 1)); -} -EXPORT_SYMBOL(ioremap); - -#ifdef CONFIG_TILE_PCI_IO -/* Map a PCI I/O address into VA space. */ -void __iomem *ioport_map(unsigned long port, unsigned int size) -{ - struct pci_controller *controller = NULL; - resource_size_t bar_start; - resource_size_t bar_end; - resource_size_t offset; - resource_size_t start; - resource_size_t end; - int trio_fd; - int i; - - start = port; - end = port + size - 1; - - /* - * By searching the port in each controller's io_space, we can - * determine the controller that should accept the PCI I/O access. - */ - for (i = 0; i < num_rc_controllers; i++) { - /* - * Skip controllers that are not properly initialized or - * have down links. - */ - if (pci_controllers[i].root_bus == NULL) - continue; - - bar_start = pci_controllers[i].io_space.start; - bar_end = pci_controllers[i].io_space.end; - - if ((start >= bar_start) && (end <= bar_end)) { - controller = &pci_controllers[i]; - break; - } - } - - if (controller == NULL) - return NULL; - - trio_fd = controller->trio->fd; - - /* Convert the resource start to the bus address offset. */ - port -= controller->io_space.start; - - offset = HV_TRIO_PIO_OFFSET(controller->pio_io_index) + port; - - /* We need to keep the PCI bus address's in-page offset in the VA. */ - return iorpc_ioremap(trio_fd, offset, size) + (port & (PAGE_SIZE - 1)); -} -EXPORT_SYMBOL(ioport_map); - -void ioport_unmap(void __iomem *addr) -{ - iounmap(addr); -} -EXPORT_SYMBOL(ioport_unmap); -#endif - -void pci_iounmap(struct pci_dev *dev, void __iomem *addr) -{ - iounmap(addr); -} -EXPORT_SYMBOL(pci_iounmap); - -/**************************************************************** - * - * Tile PCI config space read/write routines - * - ****************************************************************/ - -/* - * These are the normal read and write ops - * These are expanded with macros from pci_bus_read_config_byte() etc. - * - * devfn is the combined PCI device & function. - * - * offset is in bytes, from the start of config space for the - * specified bus & device. - */ -static int tile_cfg_read(struct pci_bus *bus, unsigned int devfn, int offset, - int size, u32 *val) -{ - struct pci_controller *controller = bus->sysdata; - gxio_trio_context_t *trio_context = controller->trio; - int busnum = bus->number & 0xff; - int device = PCI_SLOT(devfn); - int function = PCI_FUNC(devfn); - int config_type = 1; - TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR_t cfg_addr; - void *mmio_addr; - - /* - * Map all accesses to the local device on root bus into the - * MMIO space of the MAC. Accesses to the downstream devices - * go to the PIO space. - */ - if (pci_is_root_bus(bus)) { - if (device == 0) { - /* - * This is the internal downstream P2P bridge, - * access directly. - */ - unsigned int reg_offset; - - reg_offset = ((offset & 0xFFF) << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_PROTECTED - << TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | - (controller->mac << - TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - - mmio_addr = trio_context->mmio_base_mac + reg_offset; - - goto valid_device; - - } else { - /* - * We fake an empty device for (device > 0), - * since there is only one device on bus 0. - */ - goto invalid_device; - } - } - - /* - * Accesses to the directly attached device have to be - * sent as type-0 configs. - */ - if (busnum == (controller->first_busno + 1)) { - /* - * There is only one device off of our built-in P2P bridge. - */ - if (device != 0) - goto invalid_device; - - config_type = 0; - } - - cfg_addr.word = 0; - cfg_addr.reg_addr = (offset & 0xFFF); - cfg_addr.fn = function; - cfg_addr.dev = device; - cfg_addr.bus = busnum; - cfg_addr.type = config_type; - - /* - * Note that we don't set the mac field in cfg_addr because the - * mapping is per port. - */ - mmio_addr = trio_context->mmio_base_pio_cfg[controller->mac] + - cfg_addr.word; - -valid_device: - - switch (size) { - case 4: - *val = __gxio_mmio_read32(mmio_addr); - break; - - case 2: - *val = __gxio_mmio_read16(mmio_addr); - break; - - case 1: - *val = __gxio_mmio_read8(mmio_addr); - break; - - default: - return PCIBIOS_FUNC_NOT_SUPPORTED; - } - - TRACE_CFG_RD(size, *val, busnum, device, function, offset); - - return 0; - -invalid_device: - - switch (size) { - case 4: - *val = 0xFFFFFFFF; - break; - - case 2: - *val = 0xFFFF; - break; - - case 1: - *val = 0xFF; - break; - - default: - return PCIBIOS_FUNC_NOT_SUPPORTED; - } - - return 0; -} - - -/* - * See tile_cfg_read() for relevant comments. - * Note that "val" is the value to write, not a pointer to that value. - */ -static int tile_cfg_write(struct pci_bus *bus, unsigned int devfn, int offset, - int size, u32 val) -{ - struct pci_controller *controller = bus->sysdata; - gxio_trio_context_t *trio_context = controller->trio; - int busnum = bus->number & 0xff; - int device = PCI_SLOT(devfn); - int function = PCI_FUNC(devfn); - int config_type = 1; - TRIO_TILE_PIO_REGION_SETUP_CFG_ADDR_t cfg_addr; - void *mmio_addr; - u32 val_32 = (u32)val; - u16 val_16 = (u16)val; - u8 val_8 = (u8)val; - - /* - * Map all accesses to the local device on root bus into the - * MMIO space of the MAC. Accesses to the downstream devices - * go to the PIO space. - */ - if (pci_is_root_bus(bus)) { - if (device == 0) { - /* - * This is the internal downstream P2P bridge, - * access directly. - */ - unsigned int reg_offset; - - reg_offset = ((offset & 0xFFF) << - TRIO_CFG_REGION_ADDR__REG_SHIFT) | - (TRIO_CFG_REGION_ADDR__INTFC_VAL_MAC_PROTECTED - << TRIO_CFG_REGION_ADDR__INTFC_SHIFT ) | - (controller->mac << - TRIO_CFG_REGION_ADDR__MAC_SEL_SHIFT); - - mmio_addr = trio_context->mmio_base_mac + reg_offset; - - goto valid_device; - - } else { - /* - * We fake an empty device for (device > 0), - * since there is only one device on bus 0. - */ - goto invalid_device; - } - } - - /* - * Accesses to the directly attached device have to be - * sent as type-0 configs. - */ - if (busnum == (controller->first_busno + 1)) { - /* - * There is only one device off of our built-in P2P bridge. - */ - if (device != 0) - goto invalid_device; - - config_type = 0; - } - - cfg_addr.word = 0; - cfg_addr.reg_addr = (offset & 0xFFF); - cfg_addr.fn = function; - cfg_addr.dev = device; - cfg_addr.bus = busnum; - cfg_addr.type = config_type; - - /* - * Note that we don't set the mac field in cfg_addr because the - * mapping is per port. - */ - mmio_addr = trio_context->mmio_base_pio_cfg[controller->mac] + - cfg_addr.word; - -valid_device: - - switch (size) { - case 4: - __gxio_mmio_write32(mmio_addr, val_32); - TRACE_CFG_WR(size, val_32, busnum, device, function, offset); - break; - - case 2: - __gxio_mmio_write16(mmio_addr, val_16); - TRACE_CFG_WR(size, val_16, busnum, device, function, offset); - break; - - case 1: - __gxio_mmio_write8(mmio_addr, val_8); - TRACE_CFG_WR(size, val_8, busnum, device, function, offset); - break; - - default: - return PCIBIOS_FUNC_NOT_SUPPORTED; - } - -invalid_device: - - return 0; -} - - -static struct pci_ops tile_cfg_ops = { - .read = tile_cfg_read, - .write = tile_cfg_write, -}; - - -/* MSI support starts here. */ -static unsigned int tilegx_msi_startup(struct irq_data *d) -{ - if (irq_data_get_msi_desc(d)) - pci_msi_unmask_irq(d); - - return 0; -} - -static void tilegx_msi_ack(struct irq_data *d) -{ - __insn_mtspr(SPR_IPI_EVENT_RESET_K, 1UL << d->irq); -} - -static void tilegx_msi_mask(struct irq_data *d) -{ - pci_msi_mask_irq(d); - __insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq); -} - -static void tilegx_msi_unmask(struct irq_data *d) -{ - __insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq); - pci_msi_unmask_irq(d); -} - -static struct irq_chip tilegx_msi_chip = { - .name = "tilegx_msi", - .irq_startup = tilegx_msi_startup, - .irq_ack = tilegx_msi_ack, - .irq_mask = tilegx_msi_mask, - .irq_unmask = tilegx_msi_unmask, - - /* TBD: support set_affinity. */ -}; - -int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc) -{ - struct pci_controller *controller; - gxio_trio_context_t *trio_context; - struct msi_msg msg; - int default_irq; - uint64_t mem_map_base; - uint64_t mem_map_limit; - u64 msi_addr; - int mem_map; - int cpu; - int irq; - int ret; - - irq = irq_alloc_hwirq(-1); - if (!irq) - return -ENOSPC; - - /* - * Since we use a 64-bit Mem-Map to accept the MSI write, we fail - * devices that are not capable of generating a 64-bit message address. - * These devices will fall back to using the legacy interrupts. - * Most PCIe endpoint devices do support 64-bit message addressing. - */ - if (desc->msi_attrib.is_64 == 0) { - dev_info(&pdev->dev, "64-bit MSI message address not supported, falling back to legacy interrupts\n"); - - ret = -ENOMEM; - goto is_64_failure; - } - - default_irq = desc->msi_attrib.default_irq; - controller = irq_get_handler_data(default_irq); - - BUG_ON(!controller); - - trio_context = controller->trio; - - /* - * Allocate a scatter-queue that will accept the MSI write and - * trigger the TILE-side interrupts. We use the scatter-queue regions - * before the mem map regions, because the latter are needed by more - * applications. - */ - mem_map = gxio_trio_alloc_scatter_queues(trio_context, 1, 0, 0); - if (mem_map >= 0) { - TRIO_MAP_SQ_DOORBELL_FMT_t doorbell_template = {{ - .pop = 0, - .doorbell = 1, - }}; - - mem_map += TRIO_NUM_MAP_MEM_REGIONS; - mem_map_base = MEM_MAP_INTR_REGIONS_BASE + - mem_map * MEM_MAP_INTR_REGION_SIZE; - mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1; - - msi_addr = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 8; - msg.data = (unsigned int)doorbell_template.word; - } else { - /* SQ regions are out, allocate from map mem regions. */ - mem_map = gxio_trio_alloc_memory_maps(trio_context, 1, 0, 0); - if (mem_map < 0) { - dev_info(&pdev->dev, "%s Mem-Map alloc failure - failed to initialize MSI interrupts - falling back to legacy interrupts\n", - desc->msi_attrib.is_msix ? "MSI-X" : "MSI"); - ret = -ENOMEM; - goto msi_mem_map_alloc_failure; - } - - mem_map_base = MEM_MAP_INTR_REGIONS_BASE + - mem_map * MEM_MAP_INTR_REGION_SIZE; - mem_map_limit = mem_map_base + MEM_MAP_INTR_REGION_SIZE - 1; - - msi_addr = mem_map_base + TRIO_MAP_MEM_REG_INT3 - - TRIO_MAP_MEM_REG_INT0; - - msg.data = mem_map; - } - - /* We try to distribute different IRQs to different tiles. */ - cpu = tile_irq_cpu(irq); - - /* - * Now call up to the HV to configure the MSI interrupt and - * set up the IPI binding. - */ - ret = gxio_trio_config_msi_intr(trio_context, cpu_x(cpu), cpu_y(cpu), - KERNEL_PL, irq, controller->mac, - mem_map, mem_map_base, mem_map_limit, - trio_context->asid); - if (ret < 0) { - dev_info(&pdev->dev, "HV MSI config failed\n"); - - goto hv_msi_config_failure; - } - - irq_set_msi_desc(irq, desc); - - msg.address_hi = msi_addr >> 32; - msg.address_lo = msi_addr & 0xffffffff; - - pci_write_msi_msg(irq, &msg); - irq_set_chip_and_handler(irq, &tilegx_msi_chip, handle_level_irq); - irq_set_handler_data(irq, controller); - - return 0; - -hv_msi_config_failure: - /* Free mem-map */ -msi_mem_map_alloc_failure: -is_64_failure: - irq_free_hwirq(irq); - return ret; -} - -void arch_teardown_msi_irq(unsigned int irq) -{ - irq_free_hwirq(irq); -} diff --git a/arch/tile/kernel/perf_event.c b/arch/tile/kernel/perf_event.c deleted file mode 100644 index 6394c1ccb68e..000000000000 --- a/arch/tile/kernel/perf_event.c +++ /dev/null @@ -1,1005 +0,0 @@ -/* - * Copyright 2014 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * - * Perf_events support for Tile processor. - * - * This code is based upon the x86 perf event - * code, which is: - * - * Copyright (C) 2008 Thomas Gleixner - * Copyright (C) 2008-2009 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2009 Jaswinder Singh Rajput - * Copyright (C) 2009 Advanced Micro Devices, Inc., Robert Richter - * Copyright (C) 2008-2009 Red Hat, Inc., Peter Zijlstra - * Copyright (C) 2009 Intel Corporation, - * Copyright (C) 2009 Google, Inc., Stephane Eranian - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TILE_MAX_COUNTERS 4 - -#define PERF_COUNT_0_IDX 0 -#define PERF_COUNT_1_IDX 1 -#define AUX_PERF_COUNT_0_IDX 2 -#define AUX_PERF_COUNT_1_IDX 3 - -struct cpu_hw_events { - int n_events; - struct perf_event *events[TILE_MAX_COUNTERS]; /* counter order */ - struct perf_event *event_list[TILE_MAX_COUNTERS]; /* enabled - order */ - int assign[TILE_MAX_COUNTERS]; - unsigned long active_mask[BITS_TO_LONGS(TILE_MAX_COUNTERS)]; - unsigned long used_mask; -}; - -/* TILE arch specific performance monitor unit */ -struct tile_pmu { - const char *name; - int version; - const int *hw_events; /* generic hw events table */ - /* generic hw cache events table */ - const int (*cache_events)[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX]; - int (*map_hw_event)(u64); /*method used to map - hw events */ - int (*map_cache_event)(u64); /*method used to map - cache events */ - - u64 max_period; /* max sampling period */ - u64 cntval_mask; /* counter width mask */ - int cntval_bits; /* counter width */ - int max_events; /* max generic hw events - in map */ - int num_counters; /* number base + aux counters */ - int num_base_counters; /* number base counters */ -}; - -DEFINE_PER_CPU(u64, perf_irqs); -static DEFINE_PER_CPU(struct cpu_hw_events, cpu_hw_events); - -#define TILE_OP_UNSUPP (-1) - -#ifndef __tilegx__ -/* TILEPro hardware events map */ -static const int tile_hw_event_map[] = { - [PERF_COUNT_HW_CPU_CYCLES] = 0x01, /* ONE */ - [PERF_COUNT_HW_INSTRUCTIONS] = 0x06, /* MP_BUNDLE_RETIRED */ - [PERF_COUNT_HW_CACHE_REFERENCES] = TILE_OP_UNSUPP, - [PERF_COUNT_HW_CACHE_MISSES] = TILE_OP_UNSUPP, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0x16, /* - MP_CONDITIONAL_BRANCH_ISSUED */ - [PERF_COUNT_HW_BRANCH_MISSES] = 0x14, /* - MP_CONDITIONAL_BRANCH_MISSPREDICT */ - [PERF_COUNT_HW_BUS_CYCLES] = TILE_OP_UNSUPP, -}; -#else -/* TILEGx hardware events map */ -static const int tile_hw_event_map[] = { - [PERF_COUNT_HW_CPU_CYCLES] = 0x181, /* ONE */ - [PERF_COUNT_HW_INSTRUCTIONS] = 0xdb, /* INSTRUCTION_BUNDLE */ - [PERF_COUNT_HW_CACHE_REFERENCES] = TILE_OP_UNSUPP, - [PERF_COUNT_HW_CACHE_MISSES] = TILE_OP_UNSUPP, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = 0xd9, /* - COND_BRANCH_PRED_CORRECT */ - [PERF_COUNT_HW_BRANCH_MISSES] = 0xda, /* - COND_BRANCH_PRED_INCORRECT */ - [PERF_COUNT_HW_BUS_CYCLES] = TILE_OP_UNSUPP, -}; -#endif - -#define C(x) PERF_COUNT_HW_CACHE_##x - -/* - * Generalized hw caching related hw_event table, filled - * in on a per model basis. A value of -1 means - * 'not supported', any other value means the - * raw hw_event ID. - */ -#ifndef __tilegx__ -/* TILEPro hardware cache event map */ -static const int tile_cache_event_map[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX] = { -[C(L1D)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = 0x21, /* RD_MISS */ - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = 0x22, /* WR_MISS */ - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -[C(L1I)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = 0x12, /* MP_ICACHE_HIT_ISSUED */ - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -[C(LL)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -[C(DTLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = 0x1d, /* TLB_CNT */ - [C(RESULT_MISS)] = 0x20, /* TLB_EXCEPTION */ - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -[C(ITLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = 0x13, /* MP_ITLB_HIT_ISSUED */ - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -[C(BPU)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -}; -#else -/* TILEGx hardware events map */ -static const int tile_cache_event_map[PERF_COUNT_HW_CACHE_MAX] - [PERF_COUNT_HW_CACHE_OP_MAX] - [PERF_COUNT_HW_CACHE_RESULT_MAX] = { -[C(L1D)] = { - /* - * Like some other architectures (e.g. ARM), the performance - * counters don't differentiate between read and write - * accesses/misses, so this isn't strictly correct, but it's the - * best we can do. Writes and reads get combined. - */ - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = 0x44, /* RD_MISS */ - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = 0x45, /* WR_MISS */ - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -[C(L1I)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -[C(LL)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -[C(DTLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = 0x40, /* TLB_CNT */ - [C(RESULT_MISS)] = 0x43, /* TLB_EXCEPTION */ - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = 0x40, /* TLB_CNT */ - [C(RESULT_MISS)] = 0x43, /* TLB_EXCEPTION */ - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -[C(ITLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = 0xd4, /* ITLB_MISS_INT */ - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = 0xd4, /* ITLB_MISS_INT */ - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -[C(BPU)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = TILE_OP_UNSUPP, - [C(RESULT_MISS)] = TILE_OP_UNSUPP, - }, -}, -}; -#endif - -static atomic_t tile_active_events; -static DEFINE_MUTEX(perf_intr_reserve_mutex); - -static int tile_map_hw_event(u64 config); -static int tile_map_cache_event(u64 config); - -static int tile_pmu_handle_irq(struct pt_regs *regs, int fault); - -/* - * To avoid new_raw_count getting larger then pre_raw_count - * in tile_perf_event_update(), we limit the value of max_period to 2^31 - 1. - */ -static const struct tile_pmu tilepmu = { -#ifndef __tilegx__ - .name = "tilepro", -#else - .name = "tilegx", -#endif - .max_events = ARRAY_SIZE(tile_hw_event_map), - .map_hw_event = tile_map_hw_event, - .hw_events = tile_hw_event_map, - .map_cache_event = tile_map_cache_event, - .cache_events = &tile_cache_event_map, - .cntval_bits = 32, - .cntval_mask = (1ULL << 32) - 1, - .max_period = (1ULL << 31) - 1, - .num_counters = TILE_MAX_COUNTERS, - .num_base_counters = TILE_BASE_COUNTERS, -}; - -static const struct tile_pmu *tile_pmu __read_mostly; - -/* - * Check whether perf event is enabled. - */ -int tile_perf_enabled(void) -{ - return atomic_read(&tile_active_events) != 0; -} - -/* - * Read Performance Counters. - */ -static inline u64 read_counter(int idx) -{ - u64 val = 0; - - /* __insn_mfspr() only takes an immediate argument */ - switch (idx) { - case PERF_COUNT_0_IDX: - val = __insn_mfspr(SPR_PERF_COUNT_0); - break; - case PERF_COUNT_1_IDX: - val = __insn_mfspr(SPR_PERF_COUNT_1); - break; - case AUX_PERF_COUNT_0_IDX: - val = __insn_mfspr(SPR_AUX_PERF_COUNT_0); - break; - case AUX_PERF_COUNT_1_IDX: - val = __insn_mfspr(SPR_AUX_PERF_COUNT_1); - break; - default: - WARN_ON_ONCE(idx > AUX_PERF_COUNT_1_IDX || - idx < PERF_COUNT_0_IDX); - } - - return val; -} - -/* - * Write Performance Counters. - */ -static inline void write_counter(int idx, u64 value) -{ - /* __insn_mtspr() only takes an immediate argument */ - switch (idx) { - case PERF_COUNT_0_IDX: - __insn_mtspr(SPR_PERF_COUNT_0, value); - break; - case PERF_COUNT_1_IDX: - __insn_mtspr(SPR_PERF_COUNT_1, value); - break; - case AUX_PERF_COUNT_0_IDX: - __insn_mtspr(SPR_AUX_PERF_COUNT_0, value); - break; - case AUX_PERF_COUNT_1_IDX: - __insn_mtspr(SPR_AUX_PERF_COUNT_1, value); - break; - default: - WARN_ON_ONCE(idx > AUX_PERF_COUNT_1_IDX || - idx < PERF_COUNT_0_IDX); - } -} - -/* - * Enable performance event by setting - * Performance Counter Control registers. - */ -static inline void tile_pmu_enable_event(struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - unsigned long cfg, mask; - int shift, idx = hwc->idx; - - /* - * prevent early activation from tile_pmu_start() in hw_perf_enable - */ - - if (WARN_ON_ONCE(idx == -1)) - return; - - if (idx < tile_pmu->num_base_counters) - cfg = __insn_mfspr(SPR_PERF_COUNT_CTL); - else - cfg = __insn_mfspr(SPR_AUX_PERF_COUNT_CTL); - - switch (idx) { - case PERF_COUNT_0_IDX: - case AUX_PERF_COUNT_0_IDX: - mask = TILE_EVENT_MASK; - shift = 0; - break; - case PERF_COUNT_1_IDX: - case AUX_PERF_COUNT_1_IDX: - mask = TILE_EVENT_MASK << 16; - shift = 16; - break; - default: - WARN_ON_ONCE(idx < PERF_COUNT_0_IDX || - idx > AUX_PERF_COUNT_1_IDX); - return; - } - - /* Clear mask bits to enable the event. */ - cfg &= ~mask; - cfg |= hwc->config << shift; - - if (idx < tile_pmu->num_base_counters) - __insn_mtspr(SPR_PERF_COUNT_CTL, cfg); - else - __insn_mtspr(SPR_AUX_PERF_COUNT_CTL, cfg); -} - -/* - * Disable performance event by clearing - * Performance Counter Control registers. - */ -static inline void tile_pmu_disable_event(struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - unsigned long cfg, mask; - int idx = hwc->idx; - - if (idx == -1) - return; - - if (idx < tile_pmu->num_base_counters) - cfg = __insn_mfspr(SPR_PERF_COUNT_CTL); - else - cfg = __insn_mfspr(SPR_AUX_PERF_COUNT_CTL); - - switch (idx) { - case PERF_COUNT_0_IDX: - case AUX_PERF_COUNT_0_IDX: - mask = TILE_PLM_MASK; - break; - case PERF_COUNT_1_IDX: - case AUX_PERF_COUNT_1_IDX: - mask = TILE_PLM_MASK << 16; - break; - default: - WARN_ON_ONCE(idx < PERF_COUNT_0_IDX || - idx > AUX_PERF_COUNT_1_IDX); - return; - } - - /* Set mask bits to disable the event. */ - cfg |= mask; - - if (idx < tile_pmu->num_base_counters) - __insn_mtspr(SPR_PERF_COUNT_CTL, cfg); - else - __insn_mtspr(SPR_AUX_PERF_COUNT_CTL, cfg); -} - -/* - * Propagate event elapsed time into the generic event. - * Can only be executed on the CPU where the event is active. - * Returns the delta events processed. - */ -static u64 tile_perf_event_update(struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - int shift = 64 - tile_pmu->cntval_bits; - u64 prev_raw_count, new_raw_count; - u64 oldval; - int idx = hwc->idx; - u64 delta; - - /* - * Careful: an NMI might modify the previous event value. - * - * Our tactic to handle this is to first atomically read and - * exchange a new raw count - then add that new-prev delta - * count to the generic event atomically: - */ -again: - prev_raw_count = local64_read(&hwc->prev_count); - new_raw_count = read_counter(idx); - - oldval = local64_cmpxchg(&hwc->prev_count, prev_raw_count, - new_raw_count); - if (oldval != prev_raw_count) - goto again; - - /* - * Now we have the new raw value and have updated the prev - * timestamp already. We can now calculate the elapsed delta - * (event-)time and add that to the generic event. - * - * Careful, not all hw sign-extends above the physical width - * of the count. - */ - delta = (new_raw_count << shift) - (prev_raw_count << shift); - delta >>= shift; - - local64_add(delta, &event->count); - local64_sub(delta, &hwc->period_left); - - return new_raw_count; -} - -/* - * Set the next IRQ period, based on the hwc->period_left value. - * To be called with the event disabled in hw: - */ -static int tile_event_set_period(struct perf_event *event) -{ - struct hw_perf_event *hwc = &event->hw; - int idx = hwc->idx; - s64 left = local64_read(&hwc->period_left); - s64 period = hwc->sample_period; - int ret = 0; - - /* - * If we are way outside a reasonable range then just skip forward: - */ - if (unlikely(left <= -period)) { - left = period; - local64_set(&hwc->period_left, left); - hwc->last_period = period; - ret = 1; - } - - if (unlikely(left <= 0)) { - left += period; - local64_set(&hwc->period_left, left); - hwc->last_period = period; - ret = 1; - } - if (left > tile_pmu->max_period) - left = tile_pmu->max_period; - - /* - * The hw event starts counting from this event offset, - * mark it to be able to extra future deltas: - */ - local64_set(&hwc->prev_count, (u64)-left); - - write_counter(idx, (u64)(-left) & tile_pmu->cntval_mask); - - perf_event_update_userpage(event); - - return ret; -} - -/* - * Stop the event but do not release the PMU counter - */ -static void tile_pmu_stop(struct perf_event *event, int flags) -{ - struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); - struct hw_perf_event *hwc = &event->hw; - int idx = hwc->idx; - - if (__test_and_clear_bit(idx, cpuc->active_mask)) { - tile_pmu_disable_event(event); - cpuc->events[hwc->idx] = NULL; - WARN_ON_ONCE(hwc->state & PERF_HES_STOPPED); - hwc->state |= PERF_HES_STOPPED; - } - - if ((flags & PERF_EF_UPDATE) && !(hwc->state & PERF_HES_UPTODATE)) { - /* - * Drain the remaining delta count out of a event - * that we are disabling: - */ - tile_perf_event_update(event); - hwc->state |= PERF_HES_UPTODATE; - } -} - -/* - * Start an event (without re-assigning counter) - */ -static void tile_pmu_start(struct perf_event *event, int flags) -{ - struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); - int idx = event->hw.idx; - - if (WARN_ON_ONCE(!(event->hw.state & PERF_HES_STOPPED))) - return; - - if (WARN_ON_ONCE(idx == -1)) - return; - - if (flags & PERF_EF_RELOAD) { - WARN_ON_ONCE(!(event->hw.state & PERF_HES_UPTODATE)); - tile_event_set_period(event); - } - - event->hw.state = 0; - - cpuc->events[idx] = event; - __set_bit(idx, cpuc->active_mask); - - unmask_pmc_interrupts(); - - tile_pmu_enable_event(event); - - perf_event_update_userpage(event); -} - -/* - * Add a single event to the PMU. - * - * The event is added to the group of enabled events - * but only if it can be scehduled with existing events. - */ -static int tile_pmu_add(struct perf_event *event, int flags) -{ - struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); - struct hw_perf_event *hwc; - unsigned long mask; - int b, max_cnt; - - hwc = &event->hw; - - /* - * We are full. - */ - if (cpuc->n_events == tile_pmu->num_counters) - return -ENOSPC; - - cpuc->event_list[cpuc->n_events] = event; - cpuc->n_events++; - - hwc->state = PERF_HES_UPTODATE | PERF_HES_STOPPED; - if (!(flags & PERF_EF_START)) - hwc->state |= PERF_HES_ARCH; - - /* - * Find first empty counter. - */ - max_cnt = tile_pmu->num_counters; - mask = ~cpuc->used_mask; - - /* Find next free counter. */ - b = find_next_bit(&mask, max_cnt, 0); - - /* Should not happen. */ - if (WARN_ON_ONCE(b == max_cnt)) - return -ENOSPC; - - /* - * Assign counter to event. - */ - event->hw.idx = b; - __set_bit(b, &cpuc->used_mask); - - /* - * Start if requested. - */ - if (flags & PERF_EF_START) - tile_pmu_start(event, PERF_EF_RELOAD); - - return 0; -} - -/* - * Delete a single event from the PMU. - * - * The event is deleted from the group of enabled events. - * If it is the last event, disable PMU interrupt. - */ -static void tile_pmu_del(struct perf_event *event, int flags) -{ - struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); - int i; - - /* - * Remove event from list, compact list if necessary. - */ - for (i = 0; i < cpuc->n_events; i++) { - if (cpuc->event_list[i] == event) { - while (++i < cpuc->n_events) - cpuc->event_list[i-1] = cpuc->event_list[i]; - --cpuc->n_events; - cpuc->events[event->hw.idx] = NULL; - __clear_bit(event->hw.idx, &cpuc->used_mask); - tile_pmu_stop(event, PERF_EF_UPDATE); - break; - } - } - /* - * If there are no events left, then mask PMU interrupt. - */ - if (cpuc->n_events == 0) - mask_pmc_interrupts(); - perf_event_update_userpage(event); -} - -/* - * Propagate event elapsed time into the event. - */ -static inline void tile_pmu_read(struct perf_event *event) -{ - tile_perf_event_update(event); -} - -/* - * Map generic events to Tile PMU. - */ -static int tile_map_hw_event(u64 config) -{ - if (config >= tile_pmu->max_events) - return -EINVAL; - return tile_pmu->hw_events[config]; -} - -/* - * Map generic hardware cache events to Tile PMU. - */ -static int tile_map_cache_event(u64 config) -{ - unsigned int cache_type, cache_op, cache_result; - int code; - - if (!tile_pmu->cache_events) - return -ENOENT; - - cache_type = (config >> 0) & 0xff; - if (cache_type >= PERF_COUNT_HW_CACHE_MAX) - return -EINVAL; - - cache_op = (config >> 8) & 0xff; - if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX) - return -EINVAL; - - cache_result = (config >> 16) & 0xff; - if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX) - return -EINVAL; - - code = (*tile_pmu->cache_events)[cache_type][cache_op][cache_result]; - if (code == TILE_OP_UNSUPP) - return -EINVAL; - - return code; -} - -static void tile_event_destroy(struct perf_event *event) -{ - if (atomic_dec_return(&tile_active_events) == 0) - release_pmc_hardware(); -} - -static int __tile_event_init(struct perf_event *event) -{ - struct perf_event_attr *attr = &event->attr; - struct hw_perf_event *hwc = &event->hw; - int code; - - switch (attr->type) { - case PERF_TYPE_HARDWARE: - code = tile_pmu->map_hw_event(attr->config); - break; - case PERF_TYPE_HW_CACHE: - code = tile_pmu->map_cache_event(attr->config); - break; - case PERF_TYPE_RAW: - code = attr->config & TILE_EVENT_MASK; - break; - default: - /* Should not happen. */ - return -EOPNOTSUPP; - } - - if (code < 0) - return code; - - hwc->config = code; - hwc->idx = -1; - - if (attr->exclude_user) - hwc->config |= TILE_CTL_EXCL_USER; - - if (attr->exclude_kernel) - hwc->config |= TILE_CTL_EXCL_KERNEL; - - if (attr->exclude_hv) - hwc->config |= TILE_CTL_EXCL_HV; - - if (!hwc->sample_period) { - hwc->sample_period = tile_pmu->max_period; - hwc->last_period = hwc->sample_period; - local64_set(&hwc->period_left, hwc->sample_period); - } - event->destroy = tile_event_destroy; - return 0; -} - -static int tile_event_init(struct perf_event *event) -{ - int err = 0; - perf_irq_t old_irq_handler = NULL; - - if (atomic_inc_return(&tile_active_events) == 1) - old_irq_handler = reserve_pmc_hardware(tile_pmu_handle_irq); - - if (old_irq_handler) { - pr_warn("PMC hardware busy (reserved by oprofile)\n"); - - atomic_dec(&tile_active_events); - return -EBUSY; - } - - switch (event->attr.type) { - case PERF_TYPE_RAW: - case PERF_TYPE_HARDWARE: - case PERF_TYPE_HW_CACHE: - break; - - default: - return -ENOENT; - } - - err = __tile_event_init(event); - if (err) { - if (event->destroy) - event->destroy(event); - } - return err; -} - -static struct pmu tilera_pmu = { - .event_init = tile_event_init, - .add = tile_pmu_add, - .del = tile_pmu_del, - - .start = tile_pmu_start, - .stop = tile_pmu_stop, - - .read = tile_pmu_read, -}; - -/* - * PMU's IRQ handler, PMU has 2 interrupts, they share the same handler. - */ -int tile_pmu_handle_irq(struct pt_regs *regs, int fault) -{ - struct perf_sample_data data; - struct cpu_hw_events *cpuc = this_cpu_ptr(&cpu_hw_events); - struct perf_event *event; - struct hw_perf_event *hwc; - u64 val; - unsigned long status; - int bit; - - __this_cpu_inc(perf_irqs); - - if (!atomic_read(&tile_active_events)) - return 0; - - status = pmc_get_overflow(); - pmc_ack_overflow(status); - - for_each_set_bit(bit, &status, tile_pmu->num_counters) { - - event = cpuc->events[bit]; - - if (!event) - continue; - - if (!test_bit(bit, cpuc->active_mask)) - continue; - - hwc = &event->hw; - - val = tile_perf_event_update(event); - if (val & (1ULL << (tile_pmu->cntval_bits - 1))) - continue; - - perf_sample_data_init(&data, 0, event->hw.last_period); - if (!tile_event_set_period(event)) - continue; - - if (perf_event_overflow(event, &data, regs)) - tile_pmu_stop(event, 0); - } - - return 0; -} - -static bool __init supported_pmu(void) -{ - tile_pmu = &tilepmu; - return true; -} - -int __init init_hw_perf_events(void) -{ - supported_pmu(); - perf_pmu_register(&tilera_pmu, "cpu", PERF_TYPE_RAW); - return 0; -} -arch_initcall(init_hw_perf_events); - -/* Callchain handling code. */ - -/* - * Tile specific backtracing code for perf_events. - */ -static inline void perf_callchain(struct perf_callchain_entry_ctx *entry, - struct pt_regs *regs) -{ - struct KBacktraceIterator kbt; - unsigned int i; - - /* - * Get the address just after the "jalr" instruction that - * jumps to the handler for a syscall. When we find this - * address in a backtrace, we silently ignore it, which gives - * us a one-step backtrace connection from the sys_xxx() - * function in the kernel to the xxx() function in libc. - * Otherwise, we lose the ability to properly attribute time - * from the libc calls to the kernel implementations, since - * oprofile only considers PCs from backtraces a pair at a time. - */ - unsigned long handle_syscall_pc = handle_syscall_link_address(); - - KBacktraceIterator_init(&kbt, NULL, regs); - kbt.profile = 1; - - /* - * The sample for the pc is already recorded. Now we are adding the - * address of the callsites on the stack. Our iterator starts - * with the frame of the (already sampled) call site. If our - * iterator contained a "return address" field, we could have just - * used it and wouldn't have needed to skip the first - * frame. That's in effect what the arm and x86 versions do. - * Instead we peel off the first iteration to get the equivalent - * behavior. - */ - - if (KBacktraceIterator_end(&kbt)) - return; - KBacktraceIterator_next(&kbt); - - /* - * Set stack depth to 16 for user and kernel space respectively, that - * is, total 32 stack frames. - */ - for (i = 0; i < 16; ++i) { - unsigned long pc; - if (KBacktraceIterator_end(&kbt)) - break; - pc = kbt.it.pc; - if (pc != handle_syscall_pc) - perf_callchain_store(entry, pc); - KBacktraceIterator_next(&kbt); - } -} - -void perf_callchain_user(struct perf_callchain_entry_ctx *entry, - struct pt_regs *regs) -{ - perf_callchain(entry, regs); -} - -void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, - struct pt_regs *regs) -{ - perf_callchain(entry, regs); -} diff --git a/arch/tile/kernel/pmc.c b/arch/tile/kernel/pmc.c deleted file mode 100644 index 81cf8743a3f3..000000000000 --- a/arch/tile/kernel/pmc.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright 2014 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include - -#include -#include - -perf_irq_t perf_irq = NULL; -int handle_perf_interrupt(struct pt_regs *regs, int fault) -{ - int retval; - - if (!perf_irq) - panic("Unexpected PERF_COUNT interrupt %d\n", fault); - - retval = perf_irq(regs, fault); - return retval; -} - -/* Reserve PMC hardware if it is available. */ -perf_irq_t reserve_pmc_hardware(perf_irq_t new_perf_irq) -{ - return cmpxchg(&perf_irq, NULL, new_perf_irq); -} -EXPORT_SYMBOL(reserve_pmc_hardware); - -/* Release PMC hardware. */ -void release_pmc_hardware(void) -{ - perf_irq = NULL; -} -EXPORT_SYMBOL(release_pmc_hardware); - - -/* - * Get current overflow status of each performance counter, - * and auxiliary performance counter. - */ -unsigned long -pmc_get_overflow(void) -{ - unsigned long status; - - /* - * merge base+aux into a single vector - */ - status = __insn_mfspr(SPR_PERF_COUNT_STS); - status |= __insn_mfspr(SPR_AUX_PERF_COUNT_STS) << TILE_BASE_COUNTERS; - return status; -} - -/* - * Clear the status bit for the corresponding counter, if written - * with a one. - */ -void -pmc_ack_overflow(unsigned long status) -{ - /* - * clear overflow status by writing ones - */ - __insn_mtspr(SPR_PERF_COUNT_STS, status); - __insn_mtspr(SPR_AUX_PERF_COUNT_STS, status >> TILE_BASE_COUNTERS); -} - -/* - * The perf count interrupts are masked and unmasked explicitly, - * and only here. The normal irq_enable() does not enable them, - * and irq_disable() does not disable them. That lets these - * routines drive the perf count interrupts orthogonally. - * - * We also mask the perf count interrupts on entry to the perf count - * interrupt handler in assembly code, and by default unmask them - * again (with interrupt critical section protection) just before - * returning from the interrupt. If the perf count handler returns - * a non-zero error code, then we don't re-enable them before returning. - * - * For Pro, we rely on both interrupts being in the same word to update - * them atomically so we never have one enabled and one disabled. - */ - -#if CHIP_HAS_SPLIT_INTR_MASK() -# if INT_PERF_COUNT < 32 || INT_AUX_PERF_COUNT < 32 -# error Fix assumptions about which word PERF_COUNT interrupts are in -# endif -#endif - -static inline unsigned long long pmc_mask(void) -{ - unsigned long long mask = 1ULL << INT_PERF_COUNT; - mask |= 1ULL << INT_AUX_PERF_COUNT; - return mask; -} - -void unmask_pmc_interrupts(void) -{ - interrupt_mask_reset_mask(pmc_mask()); -} - -void mask_pmc_interrupts(void) -{ - interrupt_mask_set_mask(pmc_mask()); -} diff --git a/arch/tile/kernel/proc.c b/arch/tile/kernel/proc.c deleted file mode 100644 index 7983e9868df6..000000000000 --- a/arch/tile/kernel/proc.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * Support /proc/cpuinfo - */ - -#define cpu_to_ptr(n) ((void *)((long)(n)+1)) -#define ptr_to_cpu(p) ((long)(p) - 1) - -static int show_cpuinfo(struct seq_file *m, void *v) -{ - int n = ptr_to_cpu(v); - - if (n == 0) { - seq_printf(m, "cpu count\t: %d\n", num_online_cpus()); - seq_printf(m, "cpu list\t: %*pbl\n", - cpumask_pr_args(cpu_online_mask)); - seq_printf(m, "model name\t: %s\n", chip_model); - seq_printf(m, "flags\t\t:\n"); /* nothing for now */ - seq_printf(m, "cpu MHz\t\t: %llu.%06llu\n", - get_clock_rate() / 1000000, - (get_clock_rate() % 1000000)); - seq_printf(m, "bogomips\t: %lu.%02lu\n\n", - loops_per_jiffy/(500000/HZ), - (loops_per_jiffy/(5000/HZ)) % 100); - } - -#ifdef CONFIG_SMP - if (!cpu_online(n)) - return 0; -#endif - - seq_printf(m, "processor\t: %d\n", n); - - /* Print only num_online_cpus() blank lines total. */ - if (cpumask_next(n, cpu_online_mask) < nr_cpu_ids) - seq_printf(m, "\n"); - - return 0; -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - return *pos < nr_cpu_ids ? cpu_to_ptr(*pos) : NULL; -} -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - ++*pos; - return c_start(m, pos); -} -static void c_stop(struct seq_file *m, void *v) -{ -} -const struct seq_operations cpuinfo_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = show_cpuinfo, -}; - -/* - * Support /proc/tile directory - */ - -static int __init proc_tile_init(void) -{ - struct proc_dir_entry *root = proc_mkdir("tile", NULL); - if (root == NULL) - return 0; - - proc_tile_hardwall_init(root); - - return 0; -} - -arch_initcall(proc_tile_init); - -/* - * Support /proc/sys/tile directory - */ - -static struct ctl_table unaligned_subtable[] = { - { - .procname = "enabled", - .data = &unaligned_fixup, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .procname = "printk", - .data = &unaligned_printk, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .procname = "count", - .data = &unaligned_fixup_count, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - {} -}; - -static struct ctl_table unaligned_table[] = { - { - .procname = "unaligned_fixup", - .mode = 0555, - .child = unaligned_subtable - }, - {} -}; - -static struct ctl_path tile_path[] = { - { .procname = "tile" }, - { } -}; - -static int __init proc_sys_tile_init(void) -{ - register_sysctl_paths(tile_path, unaligned_table); - return 0; -} - -arch_initcall(proc_sys_tile_init); diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c deleted file mode 100644 index f0a0e18e4dfb..000000000000 --- a/arch/tile/kernel/process.c +++ /dev/null @@ -1,659 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_HARDWALL -#include -#endif -#include -#include -#include - -/* - * Use the (x86) "idle=poll" option to prefer low latency when leaving the - * idle loop over low power while in the idle loop, e.g. if we have - * one thread per core and we want to get threads out of futex waits fast. - */ -static int __init idle_setup(char *str) -{ - if (!str) - return -EINVAL; - - if (!strcmp(str, "poll")) { - pr_info("using polling idle threads\n"); - cpu_idle_poll_ctrl(true); - return 0; - } else if (!strcmp(str, "halt")) { - return 0; - } - return -1; -} -early_param("idle", idle_setup); - -void arch_cpu_idle(void) -{ - __this_cpu_write(irq_stat.idle_timestamp, jiffies); - _cpu_idle(); -} - -/* - * Release a thread_info structure - */ -void arch_release_thread_stack(unsigned long *stack) -{ - struct thread_info *info = (void *)stack; - struct single_step_state *step_state = info->step_state; - - if (step_state) { - - /* - * FIXME: we don't munmap step_state->buffer - * because the mm_struct for this process (info->task->mm) - * has already been zeroed in exit_mm(). Keeping a - * reference to it here seems like a bad move, so this - * means we can't munmap() the buffer, and therefore if we - * ptrace multiple threads in a process, we will slowly - * leak user memory. (Note that as soon as the last - * thread in a process dies, we will reclaim all user - * memory including single-step buffers in the usual way.) - * We should either assign a kernel VA to this buffer - * somehow, or we should associate the buffer(s) with the - * mm itself so we can clean them up that way. - */ - kfree(step_state); - } -} - -static void save_arch_state(struct thread_struct *t); - -int copy_thread(unsigned long clone_flags, unsigned long sp, - unsigned long arg, struct task_struct *p) -{ - struct pt_regs *childregs = task_pt_regs(p); - unsigned long ksp; - unsigned long *callee_regs; - - /* - * Set up the stack and stack pointer appropriately for the - * new child to find itself woken up in __switch_to(). - * The callee-saved registers must be on the stack to be read; - * the new task will then jump to assembly support to handle - * calling schedule_tail(), etc., and (for userspace tasks) - * returning to the context set up in the pt_regs. - */ - ksp = (unsigned long) childregs; - ksp -= C_ABI_SAVE_AREA_SIZE; /* interrupt-entry save area */ - ((long *)ksp)[0] = ((long *)ksp)[1] = 0; - ksp -= CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long); - callee_regs = (unsigned long *)ksp; - ksp -= C_ABI_SAVE_AREA_SIZE; /* __switch_to() save area */ - ((long *)ksp)[0] = ((long *)ksp)[1] = 0; - p->thread.ksp = ksp; - - /* Record the pid of the task that created this one. */ - p->thread.creator_pid = current->pid; - - if (unlikely(p->flags & PF_KTHREAD)) { - /* kernel thread */ - memset(childregs, 0, sizeof(struct pt_regs)); - memset(&callee_regs[2], 0, - (CALLEE_SAVED_REGS_COUNT - 2) * sizeof(unsigned long)); - callee_regs[0] = sp; /* r30 = function */ - callee_regs[1] = arg; /* r31 = arg */ - p->thread.pc = (unsigned long) ret_from_kernel_thread; - return 0; - } - - /* - * Start new thread in ret_from_fork so it schedules properly - * and then return from interrupt like the parent. - */ - p->thread.pc = (unsigned long) ret_from_fork; - - /* - * Do not clone step state from the parent; each thread - * must make its own lazily. - */ - task_thread_info(p)->step_state = NULL; - -#ifdef __tilegx__ - /* - * Do not clone unalign jit fixup from the parent; each thread - * must allocate its own on demand. - */ - task_thread_info(p)->unalign_jit_base = NULL; -#endif - - /* - * Copy the registers onto the kernel stack so the - * return-from-interrupt code will reload it into registers. - */ - *childregs = *current_pt_regs(); - childregs->regs[0] = 0; /* return value is zero */ - if (sp) - childregs->sp = sp; /* override with new user stack pointer */ - memcpy(callee_regs, &childregs->regs[CALLEE_SAVED_FIRST_REG], - CALLEE_SAVED_REGS_COUNT * sizeof(unsigned long)); - - /* Save user stack top pointer so we can ID the stack vm area later. */ - p->thread.usp0 = childregs->sp; - - /* - * If CLONE_SETTLS is set, set "tp" in the new task to "r4", - * which is passed in as arg #5 to sys_clone(). - */ - if (clone_flags & CLONE_SETTLS) - childregs->tp = childregs->regs[4]; - - -#if CHIP_HAS_TILE_DMA() - /* - * No DMA in the new thread. We model this on the fact that - * fork() clears the pending signals, alarms, and aio for the child. - */ - memset(&p->thread.tile_dma_state, 0, sizeof(struct tile_dma_state)); - memset(&p->thread.dma_async_tlb, 0, sizeof(struct async_tlb)); -#endif - - /* New thread has its miscellaneous processor state bits clear. */ - p->thread.proc_status = 0; - -#ifdef CONFIG_HARDWALL - /* New thread does not own any networks. */ - memset(&p->thread.hardwall[0], 0, - sizeof(struct hardwall_task) * HARDWALL_TYPES); -#endif - - - /* - * Start the new thread with the current architecture state - * (user interrupt masks, etc.). - */ - save_arch_state(&p->thread); - - return 0; -} - -int set_unalign_ctl(struct task_struct *tsk, unsigned int val) -{ - task_thread_info(tsk)->align_ctl = val; - return 0; -} - -int get_unalign_ctl(struct task_struct *tsk, unsigned long adr) -{ - return put_user(task_thread_info(tsk)->align_ctl, - (unsigned int __user *)adr); -} - -static struct task_struct corrupt_current = { .comm = "" }; - -/* - * Return "current" if it looks plausible, or else a pointer to a dummy. - * This can be helpful if we are just trying to emit a clean panic. - */ -struct task_struct *validate_current(void) -{ - struct task_struct *tsk = current; - if (unlikely((unsigned long)tsk < PAGE_OFFSET || - (high_memory && (void *)tsk > high_memory) || - ((unsigned long)tsk & (__alignof__(*tsk) - 1)) != 0)) { - pr_err("Corrupt 'current' %p (sp %#lx)\n", tsk, stack_pointer); - tsk = &corrupt_current; - } - return tsk; -} - -/* Take and return the pointer to the previous task, for schedule_tail(). */ -struct task_struct *sim_notify_fork(struct task_struct *prev) -{ - struct task_struct *tsk = current; - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_FORK_PARENT | - (tsk->thread.creator_pid << _SIM_CONTROL_OPERATOR_BITS)); - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_FORK | - (tsk->pid << _SIM_CONTROL_OPERATOR_BITS)); - return prev; -} - -int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) -{ - struct pt_regs *ptregs = task_pt_regs(tsk); - elf_core_copy_regs(regs, ptregs); - return 1; -} - -#if CHIP_HAS_TILE_DMA() - -/* Allow user processes to access the DMA SPRs */ -void grant_dma_mpls(void) -{ -#if CONFIG_KERNEL_PL == 2 - __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1); - __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1); -#else - __insn_mtspr(SPR_MPL_DMA_CPL_SET_0, 1); - __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_0, 1); -#endif -} - -/* Forbid user processes from accessing the DMA SPRs */ -void restrict_dma_mpls(void) -{ -#if CONFIG_KERNEL_PL == 2 - __insn_mtspr(SPR_MPL_DMA_CPL_SET_2, 1); - __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_2, 1); -#else - __insn_mtspr(SPR_MPL_DMA_CPL_SET_1, 1); - __insn_mtspr(SPR_MPL_DMA_NOTIFY_SET_1, 1); -#endif -} - -/* Pause the DMA engine, then save off its state registers. */ -static void save_tile_dma_state(struct tile_dma_state *dma) -{ - unsigned long state = __insn_mfspr(SPR_DMA_USER_STATUS); - unsigned long post_suspend_state; - - /* If we're running, suspend the engine. */ - if ((state & DMA_STATUS_MASK) == SPR_DMA_STATUS__RUNNING_MASK) - __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__SUSPEND_MASK); - - /* - * Wait for the engine to idle, then save regs. Note that we - * want to record the "running" bit from before suspension, - * and the "done" bit from after, so that we can properly - * distinguish a case where the user suspended the engine from - * the case where the kernel suspended as part of the context - * swap. - */ - do { - post_suspend_state = __insn_mfspr(SPR_DMA_USER_STATUS); - } while (post_suspend_state & SPR_DMA_STATUS__BUSY_MASK); - - dma->src = __insn_mfspr(SPR_DMA_SRC_ADDR); - dma->src_chunk = __insn_mfspr(SPR_DMA_SRC_CHUNK_ADDR); - dma->dest = __insn_mfspr(SPR_DMA_DST_ADDR); - dma->dest_chunk = __insn_mfspr(SPR_DMA_DST_CHUNK_ADDR); - dma->strides = __insn_mfspr(SPR_DMA_STRIDE); - dma->chunk_size = __insn_mfspr(SPR_DMA_CHUNK_SIZE); - dma->byte = __insn_mfspr(SPR_DMA_BYTE); - dma->status = (state & SPR_DMA_STATUS__RUNNING_MASK) | - (post_suspend_state & SPR_DMA_STATUS__DONE_MASK); -} - -/* Restart a DMA that was running before we were context-switched out. */ -static void restore_tile_dma_state(struct thread_struct *t) -{ - const struct tile_dma_state *dma = &t->tile_dma_state; - - /* - * The only way to restore the done bit is to run a zero - * length transaction. - */ - if ((dma->status & SPR_DMA_STATUS__DONE_MASK) && - !(__insn_mfspr(SPR_DMA_USER_STATUS) & SPR_DMA_STATUS__DONE_MASK)) { - __insn_mtspr(SPR_DMA_BYTE, 0); - __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__REQUEST_MASK); - while (__insn_mfspr(SPR_DMA_USER_STATUS) & - SPR_DMA_STATUS__BUSY_MASK) - ; - } - - __insn_mtspr(SPR_DMA_SRC_ADDR, dma->src); - __insn_mtspr(SPR_DMA_SRC_CHUNK_ADDR, dma->src_chunk); - __insn_mtspr(SPR_DMA_DST_ADDR, dma->dest); - __insn_mtspr(SPR_DMA_DST_CHUNK_ADDR, dma->dest_chunk); - __insn_mtspr(SPR_DMA_STRIDE, dma->strides); - __insn_mtspr(SPR_DMA_CHUNK_SIZE, dma->chunk_size); - __insn_mtspr(SPR_DMA_BYTE, dma->byte); - - /* - * Restart the engine if we were running and not done. - * Clear a pending async DMA fault that we were waiting on return - * to user space to execute, since we expect the DMA engine - * to regenerate those faults for us now. Note that we don't - * try to clear the TIF_ASYNC_TLB flag, since it's relatively - * harmless if set, and it covers both DMA and the SN processor. - */ - if ((dma->status & DMA_STATUS_MASK) == SPR_DMA_STATUS__RUNNING_MASK) { - t->dma_async_tlb.fault_num = 0; - __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__REQUEST_MASK); - } -} - -#endif - -static void save_arch_state(struct thread_struct *t) -{ -#if CHIP_HAS_SPLIT_INTR_MASK() - t->interrupt_mask = __insn_mfspr(SPR_INTERRUPT_MASK_0_0) | - ((u64)__insn_mfspr(SPR_INTERRUPT_MASK_0_1) << 32); -#else - t->interrupt_mask = __insn_mfspr(SPR_INTERRUPT_MASK_0); -#endif - t->ex_context[0] = __insn_mfspr(SPR_EX_CONTEXT_0_0); - t->ex_context[1] = __insn_mfspr(SPR_EX_CONTEXT_0_1); - t->system_save[0] = __insn_mfspr(SPR_SYSTEM_SAVE_0_0); - t->system_save[1] = __insn_mfspr(SPR_SYSTEM_SAVE_0_1); - t->system_save[2] = __insn_mfspr(SPR_SYSTEM_SAVE_0_2); - t->system_save[3] = __insn_mfspr(SPR_SYSTEM_SAVE_0_3); - t->intctrl_0 = __insn_mfspr(SPR_INTCTRL_0_STATUS); - t->proc_status = __insn_mfspr(SPR_PROC_STATUS); -#if !CHIP_HAS_FIXED_INTVEC_BASE() - t->interrupt_vector_base = __insn_mfspr(SPR_INTERRUPT_VECTOR_BASE_0); -#endif - t->tile_rtf_hwm = __insn_mfspr(SPR_TILE_RTF_HWM); -#if CHIP_HAS_DSTREAM_PF() - t->dstream_pf = __insn_mfspr(SPR_DSTREAM_PF); -#endif -} - -static void restore_arch_state(const struct thread_struct *t) -{ -#if CHIP_HAS_SPLIT_INTR_MASK() - __insn_mtspr(SPR_INTERRUPT_MASK_0_0, (u32) t->interrupt_mask); - __insn_mtspr(SPR_INTERRUPT_MASK_0_1, t->interrupt_mask >> 32); -#else - __insn_mtspr(SPR_INTERRUPT_MASK_0, t->interrupt_mask); -#endif - __insn_mtspr(SPR_EX_CONTEXT_0_0, t->ex_context[0]); - __insn_mtspr(SPR_EX_CONTEXT_0_1, t->ex_context[1]); - __insn_mtspr(SPR_SYSTEM_SAVE_0_0, t->system_save[0]); - __insn_mtspr(SPR_SYSTEM_SAVE_0_1, t->system_save[1]); - __insn_mtspr(SPR_SYSTEM_SAVE_0_2, t->system_save[2]); - __insn_mtspr(SPR_SYSTEM_SAVE_0_3, t->system_save[3]); - __insn_mtspr(SPR_INTCTRL_0_STATUS, t->intctrl_0); - __insn_mtspr(SPR_PROC_STATUS, t->proc_status); -#if !CHIP_HAS_FIXED_INTVEC_BASE() - __insn_mtspr(SPR_INTERRUPT_VECTOR_BASE_0, t->interrupt_vector_base); -#endif - __insn_mtspr(SPR_TILE_RTF_HWM, t->tile_rtf_hwm); -#if CHIP_HAS_DSTREAM_PF() - __insn_mtspr(SPR_DSTREAM_PF, t->dstream_pf); -#endif -} - - -void _prepare_arch_switch(struct task_struct *next) -{ -#if CHIP_HAS_TILE_DMA() - struct tile_dma_state *dma = ¤t->thread.tile_dma_state; - if (dma->enabled) - save_tile_dma_state(dma); -#endif -} - - -struct task_struct *__sched _switch_to(struct task_struct *prev, - struct task_struct *next) -{ - /* DMA state is already saved; save off other arch state. */ - save_arch_state(&prev->thread); - -#if CHIP_HAS_TILE_DMA() - /* - * Restore DMA in new task if desired. - * Note that it is only safe to restart here since interrupts - * are disabled, so we can't take any DMATLB miss or access - * interrupts before we have finished switching stacks. - */ - if (next->thread.tile_dma_state.enabled) { - restore_tile_dma_state(&next->thread); - grant_dma_mpls(); - } else { - restrict_dma_mpls(); - } -#endif - - /* Restore other arch state. */ - restore_arch_state(&next->thread); - -#ifdef CONFIG_HARDWALL - /* Enable or disable access to the network registers appropriately. */ - hardwall_switch_tasks(prev, next); -#endif - - /* Notify the simulator of task exit. */ - if (unlikely(prev->state == TASK_DEAD)) - __insn_mtspr(SPR_SIM_CONTROL, SIM_CONTROL_OS_EXIT | - (prev->pid << _SIM_CONTROL_OPERATOR_BITS)); - - /* - * Switch kernel SP, PC, and callee-saved registers. - * In the context of the new task, return the old task pointer - * (i.e. the task that actually called __switch_to). - * Pass the value to use for SYSTEM_SAVE_K_0 when we reset our sp. - */ - return __switch_to(prev, next, next_current_ksp0(next)); -} - -/* - * This routine is called on return from interrupt if any of the - * TIF_ALLWORK_MASK flags are set in thread_info->flags. It is - * entered with interrupts disabled so we don't miss an event that - * modified the thread_info flags. We loop until all the tested flags - * are clear. Note that the function is called on certain conditions - * that are not listed in the loop condition here (e.g. SINGLESTEP) - * which guarantees we will do those things once, and redo them if any - * of the other work items is re-done, but won't continue looping if - * all the other work is done. - */ -void prepare_exit_to_usermode(struct pt_regs *regs, u32 thread_info_flags) -{ - if (WARN_ON(!user_mode(regs))) - return; - - do { - local_irq_enable(); - - if (thread_info_flags & _TIF_NEED_RESCHED) - schedule(); - -#if CHIP_HAS_TILE_DMA() - if (thread_info_flags & _TIF_ASYNC_TLB) - do_async_page_fault(regs); -#endif - - if (thread_info_flags & _TIF_SIGPENDING) - do_signal(regs); - - if (thread_info_flags & _TIF_NOTIFY_RESUME) { - clear_thread_flag(TIF_NOTIFY_RESUME); - tracehook_notify_resume(regs); - } - - local_irq_disable(); - thread_info_flags = READ_ONCE(current_thread_info()->flags); - - } while (thread_info_flags & _TIF_WORK_MASK); - - if (thread_info_flags & _TIF_SINGLESTEP) { - single_step_once(regs); -#ifndef __tilegx__ - /* - * FIXME: on tilepro, since we enable interrupts in - * this routine, it's possible that we miss a signal - * or other asynchronous event. - */ - local_irq_disable(); -#endif - } - - user_enter(); -} - -unsigned long get_wchan(struct task_struct *p) -{ - struct KBacktraceIterator kbt; - - if (!p || p == current || p->state == TASK_RUNNING) - return 0; - - for (KBacktraceIterator_init(&kbt, p, NULL); - !KBacktraceIterator_end(&kbt); - KBacktraceIterator_next(&kbt)) { - if (!in_sched_functions(kbt.it.pc)) - return kbt.it.pc; - } - - return 0; -} - -/* Flush thread state. */ -void flush_thread(void) -{ - /* Nothing */ -} - -/* - * Free current thread data structures etc.. - */ -void exit_thread(struct task_struct *tsk) -{ -#ifdef CONFIG_HARDWALL - /* - * Remove the task from the list of tasks that are associated - * with any live hardwalls. (If the task that is exiting held - * the last reference to a hardwall fd, it would already have - * been released and deactivated at this point.) - */ - hardwall_deactivate_all(tsk); -#endif -} - -void tile_show_regs(struct pt_regs *regs) -{ - int i; -#ifdef __tilegx__ - for (i = 0; i < 17; i++) - pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT" r%-2d: "REGFMT"\n", - i, regs->regs[i], i+18, regs->regs[i+18], - i+36, regs->regs[i+36]); - pr_err(" r17: "REGFMT" r35: "REGFMT" tp : "REGFMT"\n", - regs->regs[17], regs->regs[35], regs->tp); - pr_err(" sp : "REGFMT" lr : "REGFMT"\n", regs->sp, regs->lr); -#else - for (i = 0; i < 13; i++) - pr_err(" r%-2d: "REGFMT" r%-2d: "REGFMT - " r%-2d: "REGFMT" r%-2d: "REGFMT"\n", - i, regs->regs[i], i+14, regs->regs[i+14], - i+27, regs->regs[i+27], i+40, regs->regs[i+40]); - pr_err(" r13: "REGFMT" tp : "REGFMT" sp : "REGFMT" lr : "REGFMT"\n", - regs->regs[13], regs->tp, regs->sp, regs->lr); -#endif - pr_err(" pc : "REGFMT" ex1: %ld faultnum: %ld flags:%s%s%s%s\n", - regs->pc, regs->ex1, regs->faultnum, - is_compat_task() ? " compat" : "", - (regs->flags & PT_FLAGS_DISABLE_IRQ) ? " noirq" : "", - !(regs->flags & PT_FLAGS_CALLER_SAVES) ? " nocallersave" : "", - (regs->flags & PT_FLAGS_RESTORE_REGS) ? " restoreregs" : ""); -} - -void show_regs(struct pt_regs *regs) -{ - struct KBacktraceIterator kbt; - - show_regs_print_info(KERN_DEFAULT); - tile_show_regs(regs); - - KBacktraceIterator_init(&kbt, NULL, regs); - tile_show_stack(&kbt); -} - -#ifdef __tilegx__ -void nmi_raise_cpu_backtrace(struct cpumask *in_mask) -{ - struct cpumask mask; - HV_Coord tile; - unsigned int timeout; - int cpu; - HV_NMI_Info info[NR_CPUS]; - - /* Tentatively dump stack on remote tiles via NMI. */ - timeout = 100; - cpumask_copy(&mask, in_mask); - while (!cpumask_empty(&mask) && timeout) { - for_each_cpu(cpu, &mask) { - tile.x = cpu_x(cpu); - tile.y = cpu_y(cpu); - info[cpu] = hv_send_nmi(tile, TILE_NMI_DUMP_STACK, 0); - if (info[cpu].result == HV_NMI_RESULT_OK) - cpumask_clear_cpu(cpu, &mask); - } - - mdelay(10); - touch_softlockup_watchdog(); - timeout--; - } - - /* Warn about cpus stuck in ICS. */ - if (!cpumask_empty(&mask)) { - for_each_cpu(cpu, &mask) { - - /* Clear the bit as if nmi_cpu_backtrace() ran. */ - cpumask_clear_cpu(cpu, in_mask); - - switch (info[cpu].result) { - case HV_NMI_RESULT_FAIL_ICS: - pr_warn("Skipping stack dump of cpu %d in ICS at pc %#llx\n", - cpu, info[cpu].pc); - break; - case HV_NMI_RESULT_FAIL_HV: - pr_warn("Skipping stack dump of cpu %d in hypervisor\n", - cpu); - break; - case HV_ENOSYS: - WARN_ONCE(1, "Hypervisor too old to allow remote stack dumps.\n"); - break; - default: /* should not happen */ - pr_warn("Skipping stack dump of cpu %d [%d,%#llx]\n", - cpu, info[cpu].result, info[cpu].pc); - break; - } - } - } -} - -void arch_trigger_cpumask_backtrace(const cpumask_t *mask, bool exclude_self) -{ - nmi_trigger_cpumask_backtrace(mask, exclude_self, - nmi_raise_cpu_backtrace); -} -#endif /* __tilegx_ */ diff --git a/arch/tile/kernel/ptrace.c b/arch/tile/kernel/ptrace.c deleted file mode 100644 index d516d61751c2..000000000000 --- a/arch/tile/kernel/ptrace.c +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Copied from i386: Ross Biro 1/23/92 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#define CREATE_TRACE_POINTS -#include - -void user_enable_single_step(struct task_struct *child) -{ - set_tsk_thread_flag(child, TIF_SINGLESTEP); -} - -void user_disable_single_step(struct task_struct *child) -{ - clear_tsk_thread_flag(child, TIF_SINGLESTEP); -} - -/* - * Called by kernel/ptrace.c when detaching.. - */ -void ptrace_disable(struct task_struct *child) -{ - clear_tsk_thread_flag(child, TIF_SINGLESTEP); - - /* - * These two are currently unused, but will be set by arch_ptrace() - * and used in the syscall assembly when we do support them. - */ - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); -} - -/* - * Get registers from task and ready the result for userspace. - * Note that we localize the API issues to getregs() and putregs() at - * some cost in performance, e.g. we need a full pt_regs copy for - * PEEKUSR, and two copies for POKEUSR. But in general we expect - * GETREGS/PUTREGS to be the API of choice anyway. - */ -static char *getregs(struct task_struct *child, struct pt_regs *uregs) -{ - *uregs = *task_pt_regs(child); - - /* Set up flags ABI bits. */ - uregs->flags = 0; -#ifdef CONFIG_COMPAT - if (task_thread_info(child)->status & TS_COMPAT) - uregs->flags |= PT_FLAGS_COMPAT; -#endif - - return (char *)uregs; -} - -/* Put registers back to task. */ -static void putregs(struct task_struct *child, struct pt_regs *uregs) -{ - struct pt_regs *regs = task_pt_regs(child); - - /* Don't allow overwriting the kernel-internal flags word. */ - uregs->flags = regs->flags; - - /* Only allow setting the ICS bit in the ex1 word. */ - uregs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(uregs->ex1)); - - *regs = *uregs; -} - -enum tile_regset { - REGSET_GPR, -}; - -static int tile_gpr_get(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf) -{ - struct pt_regs regs; - - getregs(target, ®s); - - return user_regset_copyout(&pos, &count, &kbuf, &ubuf, ®s, 0, - sizeof(regs)); -} - -static int tile_gpr_set(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf) -{ - int ret; - struct pt_regs regs = *task_pt_regs(target); - - ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, ®s, 0, - sizeof(regs)); - if (ret) - return ret; - - putregs(target, ®s); - - return 0; -} - -static const struct user_regset tile_user_regset[] = { - [REGSET_GPR] = { - .core_note_type = NT_PRSTATUS, - .n = ELF_NGREG, - .size = sizeof(elf_greg_t), - .align = sizeof(elf_greg_t), - .get = tile_gpr_get, - .set = tile_gpr_set, - }, -}; - -static const struct user_regset_view tile_user_regset_view = { - .name = CHIP_ARCH_NAME, - .e_machine = ELF_ARCH, - .ei_osabi = ELF_OSABI, - .regsets = tile_user_regset, - .n = ARRAY_SIZE(tile_user_regset), -}; - -const struct user_regset_view *task_user_regset_view(struct task_struct *task) -{ - return &tile_user_regset_view; -} - -long arch_ptrace(struct task_struct *child, long request, - unsigned long addr, unsigned long data) -{ - unsigned long __user *datap = (long __user __force *)data; - unsigned long tmp; - long ret = -EIO; - char *childreg; - struct pt_regs copyregs; - - switch (request) { - - case PTRACE_PEEKUSR: /* Read register from pt_regs. */ - if (addr >= PTREGS_SIZE) - break; - childreg = getregs(child, ©regs) + addr; -#ifdef CONFIG_COMPAT - if (is_compat_task()) { - if (addr & (sizeof(compat_long_t)-1)) - break; - ret = put_user(*(compat_long_t *)childreg, - (compat_long_t __user *)datap); - } else -#endif - { - if (addr & (sizeof(long)-1)) - break; - ret = put_user(*(long *)childreg, datap); - } - break; - - case PTRACE_POKEUSR: /* Write register in pt_regs. */ - if (addr >= PTREGS_SIZE) - break; - childreg = getregs(child, ©regs) + addr; -#ifdef CONFIG_COMPAT - if (is_compat_task()) { - if (addr & (sizeof(compat_long_t)-1)) - break; - *(compat_long_t *)childreg = data; - } else -#endif - { - if (addr & (sizeof(long)-1)) - break; - *(long *)childreg = data; - } - putregs(child, ©regs); - ret = 0; - break; - - case PTRACE_GETREGS: /* Get all registers from the child. */ - ret = copy_regset_to_user(child, &tile_user_regset_view, - REGSET_GPR, 0, - sizeof(struct pt_regs), datap); - break; - - case PTRACE_SETREGS: /* Set all registers in the child. */ - ret = copy_regset_from_user(child, &tile_user_regset_view, - REGSET_GPR, 0, - sizeof(struct pt_regs), datap); - break; - - case PTRACE_GETFPREGS: /* Get the child FPU state. */ - case PTRACE_SETFPREGS: /* Set the child FPU state. */ - break; - - case PTRACE_SETOPTIONS: - /* Support TILE-specific ptrace options. */ - BUILD_BUG_ON(PTRACE_O_MASK_TILE & PTRACE_O_MASK); - tmp = data & PTRACE_O_MASK_TILE; - data &= ~PTRACE_O_MASK_TILE; - ret = ptrace_request(child, request, addr, data); - if (ret == 0) { - unsigned int flags = child->ptrace; - flags &= ~(PTRACE_O_MASK_TILE << PT_OPT_FLAG_SHIFT); - flags |= (tmp << PT_OPT_FLAG_SHIFT); - child->ptrace = flags; - } - break; - - default: -#ifdef CONFIG_COMPAT - if (task_thread_info(current)->status & TS_COMPAT) { - ret = compat_ptrace_request(child, request, - addr, data); - break; - } -#endif - ret = ptrace_request(child, request, addr, data); - break; - } - - return ret; -} - -#ifdef CONFIG_COMPAT -/* Not used; we handle compat issues in arch_ptrace() directly. */ -long compat_arch_ptrace(struct task_struct *child, compat_long_t request, - compat_ulong_t addr, compat_ulong_t data) -{ - BUG(); -} -#endif - -int do_syscall_trace_enter(struct pt_regs *regs) -{ - u32 work = READ_ONCE(current_thread_info()->flags); - - if ((work & _TIF_SYSCALL_TRACE) && - tracehook_report_syscall_entry(regs)) { - regs->regs[TREG_SYSCALL_NR] = -1; - return -1; - } - - if (secure_computing(NULL) == -1) - return -1; - - if (work & _TIF_SYSCALL_TRACEPOINT) - trace_sys_enter(regs, regs->regs[TREG_SYSCALL_NR]); - - return regs->regs[TREG_SYSCALL_NR]; -} - -void do_syscall_trace_exit(struct pt_regs *regs) -{ - long errno; - - /* - * The standard tile calling convention returns the value (or negative - * errno) in r0, and zero (or positive errno) in r1. - * It saves a couple of cycles on the hot path to do this work in - * registers only as we return, rather than updating the in-memory - * struct ptregs. - */ - errno = (long) regs->regs[0]; - if (errno < 0 && errno > -4096) - regs->regs[1] = -errno; - else - regs->regs[1] = 0; - - if (test_thread_flag(TIF_SYSCALL_TRACE)) - tracehook_report_syscall_exit(regs, 0); - - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) - trace_sys_exit(regs, regs->regs[0]); -} - -void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs) -{ - struct siginfo info; - - memset(&info, 0, sizeof(info)); - info.si_signo = SIGTRAP; - info.si_code = TRAP_BRKPT; - info.si_addr = (void __user *) regs->pc; - - /* Send us the fakey SIGTRAP */ - force_sig_info(SIGTRAP, &info, tsk); -} - -/* Handle synthetic interrupt delivered only by the simulator. */ -void __kprobes do_breakpoint(struct pt_regs* regs, int fault_num) -{ - send_sigtrap(current, regs); -} diff --git a/arch/tile/kernel/reboot.c b/arch/tile/kernel/reboot.c deleted file mode 100644 index 6c5d2c070a12..000000000000 --- a/arch/tile/kernel/reboot.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef CONFIG_SMP -#define smp_send_stop() -#endif - -void machine_halt(void) -{ - arch_local_irq_disable_all(); - smp_send_stop(); - hv_halt(); -} - -void machine_power_off(void) -{ - arch_local_irq_disable_all(); - smp_send_stop(); - hv_power_off(); -} - -void machine_restart(char *cmd) -{ - arch_local_irq_disable_all(); - smp_send_stop(); - hv_restart((HV_VirtAddr) "vmlinux", (HV_VirtAddr) cmd); -} - -/* No interesting distinction to be made here. */ -void (*pm_power_off)(void) = NULL; -EXPORT_SYMBOL(pm_power_off); diff --git a/arch/tile/kernel/regs_32.S b/arch/tile/kernel/regs_32.S deleted file mode 100644 index 542cae17a93a..000000000000 --- a/arch/tile/kernel/regs_32.S +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include - -/* - * See ; called with prev and next task_struct pointers. - * "prev" is returned in r0 for _switch_to and also for ret_from_fork. - * - * We want to save pc/sp in "prev", and get the new pc/sp from "next". - * We also need to save all the callee-saved registers on the stack. - * - * Intel enables/disables access to the hardware cycle counter in - * seccomp (secure computing) environments if necessary, based on - * has_secure_computing(). We might want to do this at some point, - * though it would require virtualizing the other SPRs under WORLD_ACCESS. - * - * Since we're saving to the stack, we omit sp from this list. - * And for parallels with other architectures, we save lr separately, - * in the thread_struct itself (as the "pc" field). - * - * This code also needs to be aligned with process.c copy_thread() - */ - -#if CALLEE_SAVED_REGS_COUNT != 24 -# error Mismatch between and kernel/entry.S -#endif -#define FRAME_SIZE ((2 + CALLEE_SAVED_REGS_COUNT) * 4) - -#define SAVE_REG(r) { sw r12, r; addi r12, r12, 4 } -#define LOAD_REG(r) { lw r, r12; addi r12, r12, 4 } -#define FOR_EACH_CALLEE_SAVED_REG(f) \ - f(r30); f(r31); \ - f(r32); f(r33); f(r34); f(r35); f(r36); f(r37); f(r38); f(r39); \ - f(r40); f(r41); f(r42); f(r43); f(r44); f(r45); f(r46); f(r47); \ - f(r48); f(r49); f(r50); f(r51); f(r52); - -STD_ENTRY_SECTION(__switch_to, .sched.text) - { - move r10, sp - sw sp, lr - addi sp, sp, -FRAME_SIZE - } - { - addi r11, sp, 4 - addi r12, sp, 8 - } - { - sw r11, r10 - addli r4, r1, TASK_STRUCT_THREAD_KSP_OFFSET - } - { - lw r13, r4 /* Load new sp to a temp register early. */ - addli r3, r0, TASK_STRUCT_THREAD_KSP_OFFSET - } - FOR_EACH_CALLEE_SAVED_REG(SAVE_REG) - { - sw r3, sp - addli r3, r0, TASK_STRUCT_THREAD_PC_OFFSET - } - { - sw r3, lr - addli r4, r1, TASK_STRUCT_THREAD_PC_OFFSET - } - { - lw lr, r4 - addi r12, r13, 8 - } - { - /* Update sp and ksp0 simultaneously to avoid backtracer warnings. */ - move sp, r13 - mtspr SPR_SYSTEM_SAVE_K_0, r2 - } - FOR_EACH_CALLEE_SAVED_REG(LOAD_REG) -.L__switch_to_pc: - { - addi sp, sp, FRAME_SIZE - jrp lr /* r0 is still valid here, so return it */ - } - STD_ENDPROC(__switch_to) - -/* Return a suitable address for the backtracer for suspended threads */ -STD_ENTRY_SECTION(get_switch_to_pc, .sched.text) - lnk r0 - { - addli r0, r0, .L__switch_to_pc - . - jrp lr - } - STD_ENDPROC(get_switch_to_pc) - -STD_ENTRY(get_pt_regs) - .irp reg, r0, r1, r2, r3, r4, r5, r6, r7, \ - r8, r9, r10, r11, r12, r13, r14, r15, \ - r16, r17, r18, r19, r20, r21, r22, r23, \ - r24, r25, r26, r27, r28, r29, r30, r31, \ - r32, r33, r34, r35, r36, r37, r38, r39, \ - r40, r41, r42, r43, r44, r45, r46, r47, \ - r48, r49, r50, r51, r52, tp, sp - { - sw r0, \reg - addi r0, r0, 4 - } - .endr - { - sw r0, lr - addi r0, r0, PTREGS_OFFSET_PC - PTREGS_OFFSET_LR - } - lnk r1 - { - sw r0, r1 - addi r0, r0, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC - } - mfspr r1, INTERRUPT_CRITICAL_SECTION - shli r1, r1, SPR_EX_CONTEXT_1_1__ICS_SHIFT - ori r1, r1, KERNEL_PL - { - sw r0, r1 - addi r0, r0, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1 - } - { - sw r0, zero /* clear faultnum */ - addi r0, r0, PTREGS_OFFSET_ORIG_R0 - PTREGS_OFFSET_FAULTNUM - } - { - sw r0, zero /* clear orig_r0 */ - addli r0, r0, -PTREGS_OFFSET_ORIG_R0 /* restore r0 to base */ - } - jrp lr - STD_ENDPROC(get_pt_regs) diff --git a/arch/tile/kernel/regs_64.S b/arch/tile/kernel/regs_64.S deleted file mode 100644 index bbffcc6f340f..000000000000 --- a/arch/tile/kernel/regs_64.S +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include - -/* - * See ; called with prev and next task_struct pointers. - * "prev" is returned in r0 for _switch_to and also for ret_from_fork. - * - * We want to save pc/sp in "prev", and get the new pc/sp from "next". - * We also need to save all the callee-saved registers on the stack. - * - * Intel enables/disables access to the hardware cycle counter in - * seccomp (secure computing) environments if necessary, based on - * has_secure_computing(). We might want to do this at some point, - * though it would require virtualizing the other SPRs under WORLD_ACCESS. - * - * Since we're saving to the stack, we omit sp from this list. - * And for parallels with other architectures, we save lr separately, - * in the thread_struct itself (as the "pc" field). - * - * This code also needs to be aligned with process.c copy_thread() - */ - -#if CALLEE_SAVED_REGS_COUNT != 24 -# error Mismatch between and kernel/entry.S -#endif -#define FRAME_SIZE ((2 + CALLEE_SAVED_REGS_COUNT) * 8) - -#define SAVE_REG(r) { st r12, r; addi r12, r12, 8 } -#define LOAD_REG(r) { ld r, r12; addi r12, r12, 8 } -#define FOR_EACH_CALLEE_SAVED_REG(f) \ - f(r30); f(r31); \ - f(r32); f(r33); f(r34); f(r35); f(r36); f(r37); f(r38); f(r39); \ - f(r40); f(r41); f(r42); f(r43); f(r44); f(r45); f(r46); f(r47); \ - f(r48); f(r49); f(r50); f(r51); f(r52); - -STD_ENTRY_SECTION(__switch_to, .sched.text) - { - move r10, sp - st sp, lr - } - { - addli r11, sp, -FRAME_SIZE + 8 - addli sp, sp, -FRAME_SIZE - } - { - st r11, r10 - addli r4, r1, TASK_STRUCT_THREAD_KSP_OFFSET - } - { - ld r13, r4 /* Load new sp to a temp register early. */ - addi r12, sp, 16 - } - FOR_EACH_CALLEE_SAVED_REG(SAVE_REG) - addli r3, r0, TASK_STRUCT_THREAD_KSP_OFFSET - { - st r3, sp - addli r3, r0, TASK_STRUCT_THREAD_PC_OFFSET - } - { - st r3, lr - addli r4, r1, TASK_STRUCT_THREAD_PC_OFFSET - } - { - ld lr, r4 - addi r12, r13, 16 - } - { - /* Update sp and ksp0 simultaneously to avoid backtracer warnings. */ - move sp, r13 - mtspr SPR_SYSTEM_SAVE_K_0, r2 - } - FOR_EACH_CALLEE_SAVED_REG(LOAD_REG) -.L__switch_to_pc: - { - addli sp, sp, FRAME_SIZE - jrp lr /* r0 is still valid here, so return it */ - } - STD_ENDPROC(__switch_to) - -/* Return a suitable address for the backtracer for suspended threads */ -STD_ENTRY_SECTION(get_switch_to_pc, .sched.text) - lnk r0 - { - addli r0, r0, .L__switch_to_pc - . - jrp lr - } - STD_ENDPROC(get_switch_to_pc) - -STD_ENTRY(get_pt_regs) - .irp reg, r0, r1, r2, r3, r4, r5, r6, r7, \ - r8, r9, r10, r11, r12, r13, r14, r15, \ - r16, r17, r18, r19, r20, r21, r22, r23, \ - r24, r25, r26, r27, r28, r29, r30, r31, \ - r32, r33, r34, r35, r36, r37, r38, r39, \ - r40, r41, r42, r43, r44, r45, r46, r47, \ - r48, r49, r50, r51, r52, tp, sp - { - st r0, \reg - addi r0, r0, 8 - } - .endr - { - st r0, lr - addi r0, r0, PTREGS_OFFSET_PC - PTREGS_OFFSET_LR - } - lnk r1 - { - st r0, r1 - addi r0, r0, PTREGS_OFFSET_EX1 - PTREGS_OFFSET_PC - } - mfspr r1, INTERRUPT_CRITICAL_SECTION - shli r1, r1, SPR_EX_CONTEXT_1_1__ICS_SHIFT - ori r1, r1, KERNEL_PL - { - st r0, r1 - addi r0, r0, PTREGS_OFFSET_FAULTNUM - PTREGS_OFFSET_EX1 - } - { - st r0, zero /* clear faultnum */ - addi r0, r0, PTREGS_OFFSET_ORIG_R0 - PTREGS_OFFSET_FAULTNUM - } - { - st r0, zero /* clear orig_r0 */ - addli r0, r0, -PTREGS_OFFSET_ORIG_R0 /* restore r0 to base */ - } - jrp lr - STD_ENDPROC(get_pt_regs) diff --git a/arch/tile/kernel/relocate_kernel_32.S b/arch/tile/kernel/relocate_kernel_32.S deleted file mode 100644 index e44fbcf8cbd5..000000000000 --- a/arch/tile/kernel/relocate_kernel_32.S +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * copy new kernel into place and then call hv_reexec - * - */ - -#include -#include -#include -#include - -#undef RELOCATE_NEW_KERNEL_VERBOSE - -STD_ENTRY(relocate_new_kernel) - - move r30, r0 /* page list */ - move r31, r1 /* address of page we are on */ - move r32, r2 /* start address of new kernel */ - - shri r1, r1, PAGE_SHIFT - addi r1, r1, 1 - shli sp, r1, PAGE_SHIFT - addi sp, sp, -8 - /* we now have a stack (whether we need one or not) */ - - moveli r40, lo16(hv_console_putc) - auli r40, r40, ha16(hv_console_putc) - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, 'r' - jalr r40 - - moveli r0, '_' - jalr r40 - - moveli r0, 'n' - jalr r40 - - moveli r0, '_' - jalr r40 - - moveli r0, 'k' - jalr r40 - - moveli r0, '\n' - jalr r40 -#endif - - /* - * Throughout this code r30 is pointer to the element of page - * list we are working on. - * - * Normally we get to the next element of the page list by - * incrementing r30 by four. The exception is if the element - * on the page list is an IND_INDIRECTION in which case we use - * the element with the low bits masked off as the new value - * of r30. - * - * To get this started, we need the value passed to us (which - * will always be an IND_INDIRECTION) in memory somewhere with - * r30 pointing at it. To do that, we push the value passed - * to us on the stack and make r30 point to it. - */ - - sw sp, r30 - move r30, sp - addi sp, sp, -8 - - /* - * On TILEPro, we need to flush all tiles' caches, since we may - * have been doing hash-for-home caching there. Note that we - * must do this _after_ we're completely done modifying any memory - * other than our output buffer (which we know is locally cached). - * We want the caches to be fully clean when we do the reexec, - * because the hypervisor is going to do this flush again at that - * point, and we don't want that second flush to overwrite any memory. - */ - { - move r0, zero /* cache_pa */ - move r1, zero - } - { - auli r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */ - movei r3, -1 /* cache_cpumask; -1 means all client tiles */ - } - { - move r4, zero /* tlb_va */ - move r5, zero /* tlb_length */ - } - { - move r6, zero /* tlb_pgsize */ - move r7, zero /* tlb_cpumask */ - } - { - move r8, zero /* asids */ - moveli r20, lo16(hv_flush_remote) - } - { - move r9, zero /* asidcount */ - auli r20, r20, ha16(hv_flush_remote) - } - - jalr r20 - - /* r33 is destination pointer, default to zero */ - - moveli r33, 0 - -.Lloop: lw r10, r30 - - andi r9, r10, 0xf /* low 4 bits tell us what type it is */ - xor r10, r10, r9 /* r10 is now value with low 4 bits stripped */ - - seqi r0, r9, 0x1 /* IND_DESTINATION */ - bzt r0, .Ltry2 - - move r33, r10 - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, 'd' - jalr r40 -#endif - - addi r30, r30, 4 - j .Lloop - -.Ltry2: - seqi r0, r9, 0x2 /* IND_INDIRECTION */ - bzt r0, .Ltry4 - - move r30, r10 - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, 'i' - jalr r40 -#endif - - j .Lloop - -.Ltry4: - seqi r0, r9, 0x4 /* IND_DONE */ - bzt r0, .Ltry8 - - mf - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, 'D' - jalr r40 - moveli r0, '\n' - jalr r40 -#endif - - move r0, r32 - moveli r1, 0 /* arg to hv_reexec is 64 bits */ - - moveli r41, lo16(hv_reexec) - auli r41, r41, ha16(hv_reexec) - - jalr r41 - - /* we should not get here */ - - moveli r0, '?' - jalr r40 - moveli r0, '\n' - jalr r40 - - j .Lhalt - -.Ltry8: seqi r0, r9, 0x8 /* IND_SOURCE */ - bz r0, .Lerr /* unknown type */ - - /* copy page at r10 to page at r33 */ - - move r11, r33 - - moveli r0, lo16(PAGE_SIZE) - auli r0, r0, ha16(PAGE_SIZE) - add r33, r33, r0 - - /* copy word at r10 to word at r11 until r11 equals r33 */ - - /* We know page size must be multiple of 16, so we can unroll - * 16 times safely without any edge case checking. - * - * Issue a flush of the destination every 16 words to avoid - * incoherence when starting the new kernel. (Now this is - * just good paranoia because the hv_reexec call will also - * take care of this.) - */ - -1: - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0; addi r11, r11, 4 } - { lw r0, r10; addi r10, r10, 4 } - { sw r11, r0 } - { flush r11 ; addi r11, r11, 4 } - - seq r0, r33, r11 - bzt r0, 1b - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, 's' - jalr r40 -#endif - - addi r30, r30, 4 - j .Lloop - - -.Lerr: moveli r0, 'e' - jalr r40 - moveli r0, 'r' - jalr r40 - moveli r0, 'r' - jalr r40 - moveli r0, '\n' - jalr r40 -.Lhalt: - moveli r41, lo16(hv_halt) - auli r41, r41, ha16(hv_halt) - - jalr r41 - STD_ENDPROC(relocate_new_kernel) - - .section .rodata,"a" - - .globl relocate_new_kernel_size -relocate_new_kernel_size: - .long .Lend_relocate_new_kernel - relocate_new_kernel diff --git a/arch/tile/kernel/relocate_kernel_64.S b/arch/tile/kernel/relocate_kernel_64.S deleted file mode 100644 index d9d8cf6176e8..000000000000 --- a/arch/tile/kernel/relocate_kernel_64.S +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * copy new kernel into place and then call hv_reexec - * - */ - -#include -#include -#include -#include - -#undef RELOCATE_NEW_KERNEL_VERBOSE - -STD_ENTRY(relocate_new_kernel) - - move r30, r0 /* page list */ - move r31, r1 /* address of page we are on */ - move r32, r2 /* start address of new kernel */ - - shrui r1, r1, PAGE_SHIFT - addi r1, r1, 1 - shli sp, r1, PAGE_SHIFT - addi sp, sp, -8 - /* we now have a stack (whether we need one or not) */ - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r40, hw2_last(hv_console_putc) - shl16insli r40, r40, hw1(hv_console_putc) - shl16insli r40, r40, hw0(hv_console_putc) - - moveli r0, 'r' - jalr r40 - - moveli r0, '_' - jalr r40 - - moveli r0, 'n' - jalr r40 - - moveli r0, '_' - jalr r40 - - moveli r0, 'k' - jalr r40 - - moveli r0, '\n' - jalr r40 -#endif - - /* - * Throughout this code r30 is pointer to the element of page - * list we are working on. - * - * Normally we get to the next element of the page list by - * incrementing r30 by eight. The exception is if the element - * on the page list is an IND_INDIRECTION in which case we use - * the element with the low bits masked off as the new value - * of r30. - * - * To get this started, we need the value passed to us (which - * will always be an IND_INDIRECTION) in memory somewhere with - * r30 pointing at it. To do that, we push the value passed - * to us on the stack and make r30 point to it. - */ - - st sp, r30 - move r30, sp - addi sp, sp, -16 - - /* - * On TILE-GX, we need to flush all tiles' caches, since we may - * have been doing hash-for-home caching there. Note that we - * must do this _after_ we're completely done modifying any memory - * other than our output buffer (which we know is locally cached). - * We want the caches to be fully clean when we do the reexec, - * because the hypervisor is going to do this flush again at that - * point, and we don't want that second flush to overwrite any memory. - */ - { - move r0, zero /* cache_pa */ - moveli r1, hw2_last(HV_FLUSH_EVICT_L2) - } - { - shl16insli r1, r1, hw1(HV_FLUSH_EVICT_L2) - movei r2, -1 /* cache_cpumask; -1 means all client tiles */ - } - { - shl16insli r1, r1, hw0(HV_FLUSH_EVICT_L2) /* cache_control */ - move r3, zero /* tlb_va */ - } - { - move r4, zero /* tlb_length */ - move r5, zero /* tlb_pgsize */ - } - { - move r6, zero /* tlb_cpumask */ - move r7, zero /* asids */ - } - { - moveli r20, hw2_last(hv_flush_remote) - move r8, zero /* asidcount */ - } - shl16insli r20, r20, hw1(hv_flush_remote) - shl16insli r20, r20, hw0(hv_flush_remote) - - jalr r20 - - /* r33 is destination pointer, default to zero */ - - moveli r33, 0 - -.Lloop: ld r10, r30 - - andi r9, r10, 0xf /* low 4 bits tell us what type it is */ - xor r10, r10, r9 /* r10 is now value with low 4 bits stripped */ - - cmpeqi r0, r9, 0x1 /* IND_DESTINATION */ - beqzt r0, .Ltry2 - - move r33, r10 - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, 'd' - jalr r40 -#endif - - addi r30, r30, 8 - j .Lloop - -.Ltry2: - cmpeqi r0, r9, 0x2 /* IND_INDIRECTION */ - beqzt r0, .Ltry4 - - move r30, r10 - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, 'i' - jalr r40 -#endif - - j .Lloop - -.Ltry4: - cmpeqi r0, r9, 0x4 /* IND_DONE */ - beqzt r0, .Ltry8 - - mf - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, 'D' - jalr r40 - moveli r0, '\n' - jalr r40 -#endif - - move r0, r32 - - moveli r41, hw2_last(hv_reexec) - shl16insli r41, r41, hw1(hv_reexec) - shl16insli r41, r41, hw0(hv_reexec) - - jalr r41 - - /* we should not get here */ - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, '?' - jalr r40 - moveli r0, '\n' - jalr r40 -#endif - - j .Lhalt - -.Ltry8: cmpeqi r0, r9, 0x8 /* IND_SOURCE */ - beqz r0, .Lerr /* unknown type */ - - /* copy page at r10 to page at r33 */ - - move r11, r33 - - moveli r0, hw2_last(PAGE_SIZE) - shl16insli r0, r0, hw1(PAGE_SIZE) - shl16insli r0, r0, hw0(PAGE_SIZE) - add r33, r33, r0 - - /* copy word at r10 to word at r11 until r11 equals r33 */ - - /* We know page size must be multiple of 8, so we can unroll - * 8 times safely without any edge case checking. - * - * Issue a flush of the destination every 8 words to avoid - * incoherence when starting the new kernel. (Now this is - * just good paranoia because the hv_reexec call will also - * take care of this.) - */ - -1: - { ld r0, r10; addi r10, r10, 8 } - { st r11, r0; addi r11, r11, 8 } - { ld r0, r10; addi r10, r10, 8 } - { st r11, r0; addi r11, r11, 8 } - { ld r0, r10; addi r10, r10, 8 } - { st r11, r0; addi r11, r11, 8 } - { ld r0, r10; addi r10, r10, 8 } - { st r11, r0; addi r11, r11, 8 } - { ld r0, r10; addi r10, r10, 8 } - { st r11, r0; addi r11, r11, 8 } - { ld r0, r10; addi r10, r10, 8 } - { st r11, r0; addi r11, r11, 8 } - { ld r0, r10; addi r10, r10, 8 } - { st r11, r0; addi r11, r11, 8 } - { ld r0, r10; addi r10, r10, 8 } - { st r11, r0 } - { flush r11 ; addi r11, r11, 8 } - - cmpeq r0, r33, r11 - beqzt r0, 1b - -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, 's' - jalr r40 -#endif - - addi r30, r30, 8 - j .Lloop - - -.Lerr: -#ifdef RELOCATE_NEW_KERNEL_VERBOSE - moveli r0, 'e' - jalr r40 - moveli r0, 'r' - jalr r40 - moveli r0, 'r' - jalr r40 - moveli r0, '\n' - jalr r40 -#endif -.Lhalt: - moveli r41, hw2_last(hv_halt) - shl16insli r41, r41, hw1(hv_halt) - shl16insli r41, r41, hw0(hv_halt) - - jalr r41 - STD_ENDPROC(relocate_new_kernel) - - .section .rodata,"a" - - .globl relocate_new_kernel_size -relocate_new_kernel_size: - .long .Lend_relocate_new_kernel - relocate_new_kernel diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c deleted file mode 100644 index eb4e198f6f93..000000000000 --- a/arch/tile/kernel/setup.c +++ /dev/null @@ -1,1743 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* doesn't provide this definition. */ -#ifndef CONFIG_SMP -#define setup_max_cpus 1 -#endif - -static inline int ABS(int x) { return x >= 0 ? x : -x; } - -/* Chip information */ -char chip_model[64] __ro_after_init; - -#ifdef CONFIG_VT -struct screen_info screen_info; -#endif - -struct pglist_data node_data[MAX_NUMNODES] __read_mostly; -EXPORT_SYMBOL(node_data); - -/* Information on the NUMA nodes that we compute early */ -unsigned long node_start_pfn[MAX_NUMNODES]; -unsigned long node_end_pfn[MAX_NUMNODES]; -unsigned long __initdata node_memmap_pfn[MAX_NUMNODES]; -unsigned long __initdata node_percpu_pfn[MAX_NUMNODES]; -unsigned long __initdata node_free_pfn[MAX_NUMNODES]; - -static unsigned long __initdata node_percpu[MAX_NUMNODES]; - -/* - * per-CPU stack and boot info. - */ -DEFINE_PER_CPU(unsigned long, boot_sp) = - (unsigned long)init_stack + THREAD_SIZE - STACK_TOP_DELTA; - -#ifdef CONFIG_SMP -DEFINE_PER_CPU(unsigned long, boot_pc) = (unsigned long)start_kernel; -#else -/* - * The variable must be __initdata since it references __init code. - * With CONFIG_SMP it is per-cpu data, which is exempt from validation. - */ -unsigned long __initdata boot_pc = (unsigned long)start_kernel; -#endif - -#ifdef CONFIG_HIGHMEM -/* Page frame index of end of lowmem on each controller. */ -unsigned long node_lowmem_end_pfn[MAX_NUMNODES]; - -/* Number of pages that can be mapped into lowmem. */ -static unsigned long __initdata mappable_physpages; -#endif - -/* Data on which physical memory controller corresponds to which NUMA node */ -int node_controller[MAX_NUMNODES] = { [0 ... MAX_NUMNODES-1] = -1 }; - -#ifdef CONFIG_HIGHMEM -/* Map information from VAs to PAs */ -unsigned long pbase_map[1 << (32 - HPAGE_SHIFT)] - __ro_after_init __attribute__((aligned(L2_CACHE_BYTES))); -EXPORT_SYMBOL(pbase_map); - -/* Map information from PAs to VAs */ -void *vbase_map[NR_PA_HIGHBIT_VALUES] - __ro_after_init __attribute__((aligned(L2_CACHE_BYTES))); -EXPORT_SYMBOL(vbase_map); -#endif - -/* Node number as a function of the high PA bits */ -int highbits_to_node[NR_PA_HIGHBIT_VALUES] __ro_after_init; -EXPORT_SYMBOL(highbits_to_node); - -static unsigned int __initdata maxmem_pfn = -1U; -static unsigned int __initdata maxnodemem_pfn[MAX_NUMNODES] = { - [0 ... MAX_NUMNODES-1] = -1U -}; -static nodemask_t __initdata isolnodes; - -#if defined(CONFIG_PCI) && !defined(__tilegx__) -enum { DEFAULT_PCI_RESERVE_MB = 64 }; -static unsigned int __initdata pci_reserve_mb = DEFAULT_PCI_RESERVE_MB; -unsigned long __initdata pci_reserve_start_pfn = -1U; -unsigned long __initdata pci_reserve_end_pfn = -1U; -#endif - -static int __init setup_maxmem(char *str) -{ - unsigned long long maxmem; - if (str == NULL || (maxmem = memparse(str, NULL)) == 0) - return -EINVAL; - - maxmem_pfn = (maxmem >> HPAGE_SHIFT) << (HPAGE_SHIFT - PAGE_SHIFT); - pr_info("Forcing RAM used to no more than %dMB\n", - maxmem_pfn >> (20 - PAGE_SHIFT)); - return 0; -} -early_param("maxmem", setup_maxmem); - -static int __init setup_maxnodemem(char *str) -{ - char *endp; - unsigned long long maxnodemem; - unsigned long node; - - node = str ? simple_strtoul(str, &endp, 0) : INT_MAX; - if (node >= MAX_NUMNODES || *endp != ':') - return -EINVAL; - - maxnodemem = memparse(endp+1, NULL); - maxnodemem_pfn[node] = (maxnodemem >> HPAGE_SHIFT) << - (HPAGE_SHIFT - PAGE_SHIFT); - pr_info("Forcing RAM used on node %ld to no more than %dMB\n", - node, maxnodemem_pfn[node] >> (20 - PAGE_SHIFT)); - return 0; -} -early_param("maxnodemem", setup_maxnodemem); - -struct memmap_entry { - u64 addr; /* start of memory segment */ - u64 size; /* size of memory segment */ -}; -static struct memmap_entry memmap_map[64]; -static int memmap_nr; - -static void add_memmap_region(u64 addr, u64 size) -{ - if (memmap_nr >= ARRAY_SIZE(memmap_map)) { - pr_err("Ooops! Too many entries in the memory map!\n"); - return; - } - memmap_map[memmap_nr].addr = addr; - memmap_map[memmap_nr].size = size; - memmap_nr++; -} - -static int __init setup_memmap(char *p) -{ - char *oldp; - u64 start_at, mem_size; - - if (!p) - return -EINVAL; - - if (!strncmp(p, "exactmap", 8)) { - pr_err("\"memmap=exactmap\" not valid on tile\n"); - return 0; - } - - oldp = p; - mem_size = memparse(p, &p); - if (p == oldp) - return -EINVAL; - - if (*p == '@') { - pr_err("\"memmap=nn@ss\" (force RAM) invalid on tile\n"); - } else if (*p == '#') { - pr_err("\"memmap=nn#ss\" (force ACPI data) invalid on tile\n"); - } else if (*p == '$') { - start_at = memparse(p+1, &p); - add_memmap_region(start_at, mem_size); - } else { - if (mem_size == 0) - return -EINVAL; - maxmem_pfn = (mem_size >> HPAGE_SHIFT) << - (HPAGE_SHIFT - PAGE_SHIFT); - } - return *p == '\0' ? 0 : -EINVAL; -} -early_param("memmap", setup_memmap); - -static int __init setup_mem(char *str) -{ - return setup_maxmem(str); -} -early_param("mem", setup_mem); /* compatibility with x86 */ - -static int __init setup_isolnodes(char *str) -{ - if (str == NULL || nodelist_parse(str, isolnodes) != 0) - return -EINVAL; - - pr_info("Set isolnodes value to '%*pbl'\n", - nodemask_pr_args(&isolnodes)); - return 0; -} -early_param("isolnodes", setup_isolnodes); - -#if defined(CONFIG_PCI) && !defined(__tilegx__) -static int __init setup_pci_reserve(char* str) -{ - if (str == NULL || kstrtouint(str, 0, &pci_reserve_mb) != 0 || - pci_reserve_mb > 3 * 1024) - return -EINVAL; - - pr_info("Reserving %dMB for PCIE root complex mappings\n", - pci_reserve_mb); - return 0; -} -early_param("pci_reserve", setup_pci_reserve); -#endif - -#ifndef __tilegx__ -/* - * vmalloc=size forces the vmalloc area to be exactly 'size' bytes. - * This can be used to increase (or decrease) the vmalloc area. - */ -static int __init parse_vmalloc(char *arg) -{ - if (!arg) - return -EINVAL; - - VMALLOC_RESERVE = (memparse(arg, &arg) + PGDIR_SIZE - 1) & PGDIR_MASK; - - /* See validate_va() for more on this test. */ - if ((long)_VMALLOC_START >= 0) - early_panic("\"vmalloc=%#lx\" value too large: maximum %#lx\n", - VMALLOC_RESERVE, _VMALLOC_END - 0x80000000UL); - - return 0; -} -early_param("vmalloc", parse_vmalloc); -#endif - -#ifdef CONFIG_HIGHMEM -/* - * Determine for each controller where its lowmem is mapped and how much of - * it is mapped there. On controller zero, the first few megabytes are - * already mapped in as code at MEM_SV_START, so in principle we could - * start our data mappings higher up, but for now we don't bother, to avoid - * additional confusion. - * - * One question is whether, on systems with more than 768 Mb and - * controllers of different sizes, to map in a proportionate amount of - * each one, or to try to map the same amount from each controller. - * (E.g. if we have three controllers with 256MB, 1GB, and 256MB - * respectively, do we map 256MB from each, or do we map 128 MB, 512 - * MB, and 128 MB respectively?) For now we use a proportionate - * solution like the latter. - * - * The VA/PA mapping demands that we align our decisions at 16 MB - * boundaries so that we can rapidly convert VA to PA. - */ -static void *__init setup_pa_va_mapping(void) -{ - unsigned long curr_pages = 0; - unsigned long vaddr = PAGE_OFFSET; - nodemask_t highonlynodes = isolnodes; - int i, j; - - memset(pbase_map, -1, sizeof(pbase_map)); - memset(vbase_map, -1, sizeof(vbase_map)); - - /* Node zero cannot be isolated for LOWMEM purposes. */ - node_clear(0, highonlynodes); - - /* Count up the number of pages on non-highonlynodes controllers. */ - mappable_physpages = 0; - for_each_online_node(i) { - if (!node_isset(i, highonlynodes)) - mappable_physpages += - node_end_pfn[i] - node_start_pfn[i]; - } - - for_each_online_node(i) { - unsigned long start = node_start_pfn[i]; - unsigned long end = node_end_pfn[i]; - unsigned long size = end - start; - unsigned long vaddr_end; - - if (node_isset(i, highonlynodes)) { - /* Mark this controller as having no lowmem. */ - node_lowmem_end_pfn[i] = start; - continue; - } - - curr_pages += size; - if (mappable_physpages > MAXMEM_PFN) { - vaddr_end = PAGE_OFFSET + - (((u64)curr_pages * MAXMEM_PFN / - mappable_physpages) - << PAGE_SHIFT); - } else { - vaddr_end = PAGE_OFFSET + (curr_pages << PAGE_SHIFT); - } - for (j = 0; vaddr < vaddr_end; vaddr += HPAGE_SIZE, ++j) { - unsigned long this_pfn = - start + (j << HUGETLB_PAGE_ORDER); - pbase_map[vaddr >> HPAGE_SHIFT] = this_pfn; - if (vbase_map[__pfn_to_highbits(this_pfn)] == - (void *)-1) - vbase_map[__pfn_to_highbits(this_pfn)] = - (void *)(vaddr & HPAGE_MASK); - } - node_lowmem_end_pfn[i] = start + (j << HUGETLB_PAGE_ORDER); - BUG_ON(node_lowmem_end_pfn[i] > end); - } - - /* Return highest address of any mapped memory. */ - return (void *)vaddr; -} -#endif /* CONFIG_HIGHMEM */ - -/* - * Register our most important memory mappings with the debug stub. - * - * This is up to 4 mappings for lowmem, one mapping per memory - * controller, plus one for our text segment. - */ -static void store_permanent_mappings(void) -{ - int i; - - for_each_online_node(i) { - HV_PhysAddr pa = ((HV_PhysAddr)node_start_pfn[i]) << PAGE_SHIFT; -#ifdef CONFIG_HIGHMEM - HV_PhysAddr high_mapped_pa = node_lowmem_end_pfn[i]; -#else - HV_PhysAddr high_mapped_pa = node_end_pfn[i]; -#endif - - unsigned long pages = high_mapped_pa - node_start_pfn[i]; - HV_VirtAddr addr = (HV_VirtAddr) __va(pa); - hv_store_mapping(addr, pages << PAGE_SHIFT, pa); - } - - hv_store_mapping((HV_VirtAddr)_text, - (uint32_t)(_einittext - _text), 0); -} - -/* - * Use hv_inquire_physical() to populate node_{start,end}_pfn[] - * and node_online_map, doing suitable sanity-checking. - * Also set min_low_pfn, max_low_pfn, and max_pfn. - */ -static void __init setup_memory(void) -{ - int i, j; - int highbits_seen[NR_PA_HIGHBIT_VALUES] = { 0 }; -#ifdef CONFIG_HIGHMEM - long highmem_pages; -#endif -#ifndef __tilegx__ - int cap; -#endif -#if defined(CONFIG_HIGHMEM) || defined(__tilegx__) - long lowmem_pages; -#endif - unsigned long physpages = 0; - - /* We are using a char to hold the cpu_2_node[] mapping */ - BUILD_BUG_ON(MAX_NUMNODES > 127); - - /* Discover the ranges of memory available to us */ - for (i = 0; ; ++i) { - unsigned long start, size, end, highbits; - HV_PhysAddrRange range = hv_inquire_physical(i); - if (range.size == 0) - break; -#ifdef CONFIG_FLATMEM - if (i > 0) { - pr_err("Can't use discontiguous PAs: %#llx..%#llx\n", - range.size, range.start + range.size); - continue; - } -#endif -#ifndef __tilegx__ - if ((unsigned long)range.start) { - pr_err("Range not at 4GB multiple: %#llx..%#llx\n", - range.start, range.start + range.size); - continue; - } -#endif - if ((range.start & (HPAGE_SIZE-1)) != 0 || - (range.size & (HPAGE_SIZE-1)) != 0) { - unsigned long long start_pa = range.start; - unsigned long long orig_size = range.size; - range.start = (start_pa + HPAGE_SIZE - 1) & HPAGE_MASK; - range.size -= (range.start - start_pa); - range.size &= HPAGE_MASK; - pr_err("Range not hugepage-aligned: %#llx..%#llx: now %#llx-%#llx\n", - start_pa, start_pa + orig_size, - range.start, range.start + range.size); - } - highbits = __pa_to_highbits(range.start); - if (highbits >= NR_PA_HIGHBIT_VALUES) { - pr_err("PA high bits too high: %#llx..%#llx\n", - range.start, range.start + range.size); - continue; - } - if (highbits_seen[highbits]) { - pr_err("Range overlaps in high bits: %#llx..%#llx\n", - range.start, range.start + range.size); - continue; - } - highbits_seen[highbits] = 1; - if (PFN_DOWN(range.size) > maxnodemem_pfn[i]) { - int max_size = maxnodemem_pfn[i]; - if (max_size > 0) { - pr_err("Maxnodemem reduced node %d to %d pages\n", - i, max_size); - range.size = PFN_PHYS(max_size); - } else { - pr_err("Maxnodemem disabled node %d\n", i); - continue; - } - } - if (physpages + PFN_DOWN(range.size) > maxmem_pfn) { - int max_size = maxmem_pfn - physpages; - if (max_size > 0) { - pr_err("Maxmem reduced node %d to %d pages\n", - i, max_size); - range.size = PFN_PHYS(max_size); - } else { - pr_err("Maxmem disabled node %d\n", i); - continue; - } - } - if (i >= MAX_NUMNODES) { - pr_err("Too many PA nodes (#%d): %#llx...%#llx\n", - i, range.size, range.size + range.start); - continue; - } - - start = range.start >> PAGE_SHIFT; - size = range.size >> PAGE_SHIFT; - end = start + size; - -#ifndef __tilegx__ - if (((HV_PhysAddr)end << PAGE_SHIFT) != - (range.start + range.size)) { - pr_err("PAs too high to represent: %#llx..%#llx\n", - range.start, range.start + range.size); - continue; - } -#endif -#if defined(CONFIG_PCI) && !defined(__tilegx__) - /* - * Blocks that overlap the pci reserved region must - * have enough space to hold the maximum percpu data - * region at the top of the range. If there isn't - * enough space above the reserved region, just - * truncate the node. - */ - if (start <= pci_reserve_start_pfn && - end > pci_reserve_start_pfn) { - unsigned int per_cpu_size = - __per_cpu_end - __per_cpu_start; - unsigned int percpu_pages = - NR_CPUS * (PFN_UP(per_cpu_size) >> PAGE_SHIFT); - if (end < pci_reserve_end_pfn + percpu_pages) { - end = pci_reserve_start_pfn; - pr_err("PCI mapping region reduced node %d to %ld pages\n", - i, end - start); - } - } -#endif - - for (j = __pfn_to_highbits(start); - j <= __pfn_to_highbits(end - 1); j++) - highbits_to_node[j] = i; - - node_start_pfn[i] = start; - node_end_pfn[i] = end; - node_controller[i] = range.controller; - physpages += size; - max_pfn = end; - - /* Mark node as online */ - node_set(i, node_online_map); - node_set(i, node_possible_map); - } - -#ifndef __tilegx__ - /* - * For 4KB pages, mem_map "struct page" data is 1% of the size - * of the physical memory, so can be quite big (640 MB for - * four 16G zones). These structures must be mapped in - * lowmem, and since we currently cap out at about 768 MB, - * it's impractical to try to use this much address space. - * For now, arbitrarily cap the amount of physical memory - * we're willing to use at 8 million pages (32GB of 4KB pages). - */ - cap = 8 * 1024 * 1024; /* 8 million pages */ - if (physpages > cap) { - int num_nodes = num_online_nodes(); - int cap_each = cap / num_nodes; - unsigned long dropped_pages = 0; - for (i = 0; i < num_nodes; ++i) { - int size = node_end_pfn[i] - node_start_pfn[i]; - if (size > cap_each) { - dropped_pages += (size - cap_each); - node_end_pfn[i] = node_start_pfn[i] + cap_each; - } - } - physpages -= dropped_pages; - pr_warn("Only using %ldMB memory - ignoring %ldMB\n", - physpages >> (20 - PAGE_SHIFT), - dropped_pages >> (20 - PAGE_SHIFT)); - pr_warn("Consider using a larger page size\n"); - } -#endif - - /* Heap starts just above the last loaded address. */ - min_low_pfn = PFN_UP((unsigned long)_end - PAGE_OFFSET); - -#ifdef CONFIG_HIGHMEM - /* Find where we map lowmem from each controller. */ - high_memory = setup_pa_va_mapping(); - - /* Set max_low_pfn based on what node 0 can directly address. */ - max_low_pfn = node_lowmem_end_pfn[0]; - - lowmem_pages = (mappable_physpages > MAXMEM_PFN) ? - MAXMEM_PFN : mappable_physpages; - highmem_pages = (long) (physpages - lowmem_pages); - - pr_notice("%ldMB HIGHMEM available\n", - pages_to_mb(highmem_pages > 0 ? highmem_pages : 0)); - pr_notice("%ldMB LOWMEM available\n", pages_to_mb(lowmem_pages)); -#else - /* Set max_low_pfn based on what node 0 can directly address. */ - max_low_pfn = node_end_pfn[0]; - -#ifndef __tilegx__ - if (node_end_pfn[0] > MAXMEM_PFN) { - pr_warn("Only using %ldMB LOWMEM\n", MAXMEM >> 20); - pr_warn("Use a HIGHMEM enabled kernel\n"); - max_low_pfn = MAXMEM_PFN; - max_pfn = MAXMEM_PFN; - node_end_pfn[0] = MAXMEM_PFN; - } else { - pr_notice("%ldMB memory available\n", - pages_to_mb(node_end_pfn[0])); - } - for (i = 1; i < MAX_NUMNODES; ++i) { - node_start_pfn[i] = 0; - node_end_pfn[i] = 0; - } - high_memory = __va(node_end_pfn[0]); -#else - lowmem_pages = 0; - for (i = 0; i < MAX_NUMNODES; ++i) { - int pages = node_end_pfn[i] - node_start_pfn[i]; - lowmem_pages += pages; - if (pages) - high_memory = pfn_to_kaddr(node_end_pfn[i]); - } - pr_notice("%ldMB memory available\n", pages_to_mb(lowmem_pages)); -#endif -#endif -} - -/* - * On 32-bit machines, we only put bootmem on the low controller, - * since PAs > 4GB can't be used in bootmem. In principle one could - * imagine, e.g., multiple 1 GB controllers all of which could support - * bootmem, but in practice using controllers this small isn't a - * particularly interesting scenario, so we just keep it simple and - * use only the first controller for bootmem on 32-bit machines. - */ -static inline int node_has_bootmem(int nid) -{ -#ifdef CONFIG_64BIT - return 1; -#else - return nid == 0; -#endif -} - -static inline unsigned long alloc_bootmem_pfn(int nid, - unsigned long size, - unsigned long goal) -{ - void *kva = __alloc_bootmem_node(NODE_DATA(nid), size, - PAGE_SIZE, goal); - unsigned long pfn = kaddr_to_pfn(kva); - BUG_ON(goal && PFN_PHYS(pfn) != goal); - return pfn; -} - -static void __init setup_bootmem_allocator_node(int i) -{ - unsigned long start, end, mapsize, mapstart; - - if (node_has_bootmem(i)) { - NODE_DATA(i)->bdata = &bootmem_node_data[i]; - } else { - /* Share controller zero's bdata for now. */ - NODE_DATA(i)->bdata = &bootmem_node_data[0]; - return; - } - - /* Skip up to after the bss in node 0. */ - start = (i == 0) ? min_low_pfn : node_start_pfn[i]; - - /* Only lowmem, if we're a HIGHMEM build. */ -#ifdef CONFIG_HIGHMEM - end = node_lowmem_end_pfn[i]; -#else - end = node_end_pfn[i]; -#endif - - /* No memory here. */ - if (end == start) - return; - - /* Figure out where the bootmem bitmap is located. */ - mapsize = bootmem_bootmap_pages(end - start); - if (i == 0) { - /* Use some space right before the heap on node 0. */ - mapstart = start; - start += mapsize; - } else { - /* Allocate bitmap on node 0 to avoid page table issues. */ - mapstart = alloc_bootmem_pfn(0, PFN_PHYS(mapsize), 0); - } - - /* Initialize a node. */ - init_bootmem_node(NODE_DATA(i), mapstart, start, end); - - /* Free all the space back into the allocator. */ - free_bootmem(PFN_PHYS(start), PFN_PHYS(end - start)); - -#if defined(CONFIG_PCI) && !defined(__tilegx__) - /* - * Throw away any memory aliased by the PCI region. - */ - if (pci_reserve_start_pfn < end && pci_reserve_end_pfn > start) { - start = max(pci_reserve_start_pfn, start); - end = min(pci_reserve_end_pfn, end); - reserve_bootmem(PFN_PHYS(start), PFN_PHYS(end - start), - BOOTMEM_EXCLUSIVE); - } -#endif -} - -static void __init setup_bootmem_allocator(void) -{ - int i; - for (i = 0; i < MAX_NUMNODES; ++i) - setup_bootmem_allocator_node(i); - - /* Reserve any memory excluded by "memmap" arguments. */ - for (i = 0; i < memmap_nr; ++i) { - struct memmap_entry *m = &memmap_map[i]; - reserve_bootmem(m->addr, m->size, BOOTMEM_DEFAULT); - } - -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start) { - /* Make sure the initrd memory region is not modified. */ - if (reserve_bootmem(initrd_start, initrd_end - initrd_start, - BOOTMEM_EXCLUSIVE)) { - pr_crit("The initrd memory region has been polluted. Disabling it.\n"); - initrd_start = 0; - initrd_end = 0; - } else { - /* - * Translate initrd_start & initrd_end from PA to VA for - * future access. - */ - initrd_start += PAGE_OFFSET; - initrd_end += PAGE_OFFSET; - } - } -#endif - -#ifdef CONFIG_KEXEC - if (crashk_res.start != crashk_res.end) - reserve_bootmem(crashk_res.start, resource_size(&crashk_res), - BOOTMEM_DEFAULT); -#endif -} - -void *__init alloc_remap(int nid, unsigned long size) -{ - int pages = node_end_pfn[nid] - node_start_pfn[nid]; - void *map = pfn_to_kaddr(node_memmap_pfn[nid]); - BUG_ON(size != pages * sizeof(struct page)); - memset(map, 0, size); - return map; -} - -static int __init percpu_size(void) -{ - int size = __per_cpu_end - __per_cpu_start; - size += PERCPU_MODULE_RESERVE; - size += PERCPU_DYNAMIC_EARLY_SIZE; - if (size < PCPU_MIN_UNIT_SIZE) - size = PCPU_MIN_UNIT_SIZE; - size = roundup(size, PAGE_SIZE); - - /* In several places we assume the per-cpu data fits on a huge page. */ - BUG_ON(kdata_huge && size > HPAGE_SIZE); - return size; -} - -static void __init zone_sizes_init(void) -{ - unsigned long zones_size[MAX_NR_ZONES] = { 0 }; - int size = percpu_size(); - int num_cpus = smp_height * smp_width; - const unsigned long dma_end = (1UL << (32 - PAGE_SHIFT)); - - int i; - - for (i = 0; i < num_cpus; ++i) - node_percpu[cpu_to_node(i)] += size; - - for_each_online_node(i) { - unsigned long start = node_start_pfn[i]; - unsigned long end = node_end_pfn[i]; -#ifdef CONFIG_HIGHMEM - unsigned long lowmem_end = node_lowmem_end_pfn[i]; -#else - unsigned long lowmem_end = end; -#endif - int memmap_size = (end - start) * sizeof(struct page); - node_free_pfn[i] = start; - - /* - * Set aside pages for per-cpu data and the mem_map array. - * - * Since the per-cpu data requires special homecaching, - * if we are in kdata_huge mode, we put it at the end of - * the lowmem region. If we're not in kdata_huge mode, - * we take the per-cpu pages from the bottom of the - * controller, since that avoids fragmenting a huge page - * that users might want. We always take the memmap - * from the bottom of the controller, since with - * kdata_huge that lets it be under a huge TLB entry. - * - * If the user has requested isolnodes for a controller, - * though, there'll be no lowmem, so we just alloc_bootmem - * the memmap. There will be no percpu memory either. - */ - if (i != 0 && node_isset(i, isolnodes)) { - node_memmap_pfn[i] = - alloc_bootmem_pfn(0, memmap_size, 0); - BUG_ON(node_percpu[i] != 0); - } else if (node_has_bootmem(start)) { - unsigned long goal = 0; - node_memmap_pfn[i] = - alloc_bootmem_pfn(i, memmap_size, 0); - if (kdata_huge) - goal = PFN_PHYS(lowmem_end) - node_percpu[i]; - if (node_percpu[i]) - node_percpu_pfn[i] = - alloc_bootmem_pfn(i, node_percpu[i], - goal); - } else { - /* In non-bootmem zones, just reserve some pages. */ - node_memmap_pfn[i] = node_free_pfn[i]; - node_free_pfn[i] += PFN_UP(memmap_size); - if (!kdata_huge) { - node_percpu_pfn[i] = node_free_pfn[i]; - node_free_pfn[i] += PFN_UP(node_percpu[i]); - } else { - node_percpu_pfn[i] = - lowmem_end - PFN_UP(node_percpu[i]); - } - } - -#ifdef CONFIG_HIGHMEM - if (start > lowmem_end) { - zones_size[ZONE_NORMAL] = 0; - zones_size[ZONE_HIGHMEM] = end - start; - } else { - zones_size[ZONE_NORMAL] = lowmem_end - start; - zones_size[ZONE_HIGHMEM] = end - lowmem_end; - } -#else - zones_size[ZONE_NORMAL] = end - start; -#endif - - if (start < dma_end) { - zones_size[ZONE_DMA32] = min(zones_size[ZONE_NORMAL], - dma_end - start); - zones_size[ZONE_NORMAL] -= zones_size[ZONE_DMA32]; - } else { - zones_size[ZONE_DMA32] = 0; - } - - /* Take zone metadata from controller 0 if we're isolnode. */ - if (node_isset(i, isolnodes)) - NODE_DATA(i)->bdata = &bootmem_node_data[0]; - - free_area_init_node(i, zones_size, start, NULL); - printk(KERN_DEBUG " Normal zone: %ld per-cpu pages\n", - PFN_UP(node_percpu[i])); - - /* Track the type of memory on each node */ - if (zones_size[ZONE_NORMAL] || zones_size[ZONE_DMA32]) - node_set_state(i, N_NORMAL_MEMORY); -#ifdef CONFIG_HIGHMEM - if (end != start) - node_set_state(i, N_HIGH_MEMORY); -#endif - - node_set_online(i); - } -} - -#ifdef CONFIG_NUMA - -/* which logical CPUs are on which nodes */ -struct cpumask node_2_cpu_mask[MAX_NUMNODES] __ro_after_init; -EXPORT_SYMBOL(node_2_cpu_mask); - -/* which node each logical CPU is on */ -char cpu_2_node[NR_CPUS] __ro_after_init __attribute__((aligned(L2_CACHE_BYTES))); -EXPORT_SYMBOL(cpu_2_node); - -/* Return cpu_to_node() except for cpus not yet assigned, which return -1 */ -static int __init cpu_to_bound_node(int cpu, struct cpumask* unbound_cpus) -{ - if (!cpu_possible(cpu) || cpumask_test_cpu(cpu, unbound_cpus)) - return -1; - else - return cpu_to_node(cpu); -} - -/* Return number of immediately-adjacent tiles sharing the same NUMA node. */ -static int __init node_neighbors(int node, int cpu, - struct cpumask *unbound_cpus) -{ - int neighbors = 0; - int w = smp_width; - int h = smp_height; - int x = cpu % w; - int y = cpu / w; - if (x > 0 && cpu_to_bound_node(cpu-1, unbound_cpus) == node) - ++neighbors; - if (x < w-1 && cpu_to_bound_node(cpu+1, unbound_cpus) == node) - ++neighbors; - if (y > 0 && cpu_to_bound_node(cpu-w, unbound_cpus) == node) - ++neighbors; - if (y < h-1 && cpu_to_bound_node(cpu+w, unbound_cpus) == node) - ++neighbors; - return neighbors; -} - -static void __init setup_numa_mapping(void) -{ - u8 distance[MAX_NUMNODES][NR_CPUS]; - HV_Coord coord; - int cpu, node, cpus, i, x, y; - int num_nodes = num_online_nodes(); - struct cpumask unbound_cpus; - nodemask_t default_nodes; - - cpumask_clear(&unbound_cpus); - - /* Get set of nodes we will use for defaults */ - nodes_andnot(default_nodes, node_online_map, isolnodes); - if (nodes_empty(default_nodes)) { - BUG_ON(!node_isset(0, node_online_map)); - pr_err("Forcing NUMA node zero available as a default node\n"); - node_set(0, default_nodes); - } - - /* Populate the distance[] array */ - memset(distance, -1, sizeof(distance)); - cpu = 0; - for (coord.y = 0; coord.y < smp_height; ++coord.y) { - for (coord.x = 0; coord.x < smp_width; - ++coord.x, ++cpu) { - BUG_ON(cpu >= nr_cpu_ids); - if (!cpu_possible(cpu)) { - cpu_2_node[cpu] = -1; - continue; - } - for_each_node_mask(node, default_nodes) { - HV_MemoryControllerInfo info = - hv_inquire_memory_controller( - coord, node_controller[node]); - distance[node][cpu] = - ABS(info.coord.x) + ABS(info.coord.y); - } - cpumask_set_cpu(cpu, &unbound_cpus); - } - } - cpus = cpu; - - /* - * Round-robin through the NUMA nodes until all the cpus are - * assigned. We could be more clever here (e.g. create four - * sorted linked lists on the same set of cpu nodes, and pull - * off them in round-robin sequence, removing from all four - * lists each time) but given the relatively small numbers - * involved, O(n^2) seem OK for a one-time cost. - */ - node = first_node(default_nodes); - while (!cpumask_empty(&unbound_cpus)) { - int best_cpu = -1; - int best_distance = INT_MAX; - for (cpu = 0; cpu < cpus; ++cpu) { - if (cpumask_test_cpu(cpu, &unbound_cpus)) { - /* - * Compute metric, which is how much - * closer the cpu is to this memory - * controller than the others, shifted - * up, and then the number of - * neighbors already in the node as an - * epsilon adjustment to try to keep - * the nodes compact. - */ - int d = distance[node][cpu] * num_nodes; - for_each_node_mask(i, default_nodes) { - if (i != node) - d -= distance[i][cpu]; - } - d *= 8; /* allow space for epsilon */ - d -= node_neighbors(node, cpu, &unbound_cpus); - if (d < best_distance) { - best_cpu = cpu; - best_distance = d; - } - } - } - BUG_ON(best_cpu < 0); - cpumask_set_cpu(best_cpu, &node_2_cpu_mask[node]); - cpu_2_node[best_cpu] = node; - cpumask_clear_cpu(best_cpu, &unbound_cpus); - node = next_node_in(node, default_nodes); - } - - /* Print out node assignments and set defaults for disabled cpus */ - cpu = 0; - for (y = 0; y < smp_height; ++y) { - printk(KERN_DEBUG "NUMA cpu-to-node row %d:", y); - for (x = 0; x < smp_width; ++x, ++cpu) { - if (cpu_to_node(cpu) < 0) { - pr_cont(" -"); - cpu_2_node[cpu] = first_node(default_nodes); - } else { - pr_cont(" %d", cpu_to_node(cpu)); - } - } - pr_cont("\n"); - } -} - -static struct cpu cpu_devices[NR_CPUS]; - -static int __init topology_init(void) -{ - int i; - - for_each_online_node(i) - register_one_node(i); - - for (i = 0; i < smp_height * smp_width; ++i) - register_cpu(&cpu_devices[i], i); - - return 0; -} - -subsys_initcall(topology_init); - -#else /* !CONFIG_NUMA */ - -#define setup_numa_mapping() do { } while (0) - -#endif /* CONFIG_NUMA */ - -/* - * Initialize hugepage support on this cpu. We do this on all cores - * early in boot: before argument parsing for the boot cpu, and after - * argument parsing but before the init functions run on the secondaries. - * So the values we set up here in the hypervisor may be overridden on - * the boot cpu as arguments are parsed. - */ -static void init_super_pages(void) -{ -#ifdef CONFIG_HUGETLB_SUPER_PAGES - int i; - for (i = 0; i < HUGE_SHIFT_ENTRIES; ++i) - hv_set_pte_super_shift(i, huge_shift[i]); -#endif -} - -/** - * setup_cpu() - Do all necessary per-cpu, tile-specific initialization. - * @boot: Is this the boot cpu? - * - * Called from setup_arch() on the boot cpu, or online_secondary(). - */ -void setup_cpu(int boot) -{ - /* The boot cpu sets up its permanent mappings much earlier. */ - if (!boot) - store_permanent_mappings(); - - /* Allow asynchronous TLB interrupts. */ -#if CHIP_HAS_TILE_DMA() - arch_local_irq_unmask(INT_DMATLB_MISS); - arch_local_irq_unmask(INT_DMATLB_ACCESS); -#endif -#ifdef __tilegx__ - arch_local_irq_unmask(INT_SINGLE_STEP_K); -#endif - - /* - * Allow user access to many generic SPRs, like the cycle - * counter, PASS/FAIL/DONE, INTERRUPT_CRITICAL_SECTION, etc. - */ - __insn_mtspr(SPR_MPL_WORLD_ACCESS_SET_0, 1); - -#if CHIP_HAS_SN() - /* Static network is not restricted. */ - __insn_mtspr(SPR_MPL_SN_ACCESS_SET_0, 1); -#endif - - /* - * Set the MPL for interrupt control 0 & 1 to the corresponding - * values. This includes access to the SYSTEM_SAVE and EX_CONTEXT - * SPRs, as well as the interrupt mask. - */ - __insn_mtspr(SPR_MPL_INTCTRL_0_SET_0, 1); - __insn_mtspr(SPR_MPL_INTCTRL_1_SET_1, 1); - - /* Initialize IRQ support for this cpu. */ - setup_irq_regs(); - -#ifdef CONFIG_HARDWALL - /* Reset the network state on this cpu. */ - reset_network_state(); -#endif - - init_super_pages(); -} - -#ifdef CONFIG_BLK_DEV_INITRD - -static int __initdata set_initramfs_file; -static char __initdata initramfs_file[128] = "initramfs"; - -static int __init setup_initramfs_file(char *str) -{ - if (str == NULL) - return -EINVAL; - strncpy(initramfs_file, str, sizeof(initramfs_file) - 1); - set_initramfs_file = 1; - - return 0; -} -early_param("initramfs_file", setup_initramfs_file); - -/* - * We look for a file called "initramfs" in the hvfs. If there is one, we - * allocate some memory for it and it will be unpacked to the initramfs. - * If it's compressed, the initd code will uncompress it first. - */ -static void __init load_hv_initrd(void) -{ - HV_FS_StatInfo stat; - int fd, rc; - void *initrd; - - /* If initrd has already been set, skip initramfs file in hvfs. */ - if (initrd_start) - return; - - fd = hv_fs_findfile((HV_VirtAddr) initramfs_file); - if (fd == HV_ENOENT) { - if (set_initramfs_file) { - pr_warn("No such hvfs initramfs file '%s'\n", - initramfs_file); - return; - } else { - /* Try old backwards-compatible name. */ - fd = hv_fs_findfile((HV_VirtAddr)"initramfs.cpio.gz"); - if (fd == HV_ENOENT) - return; - } - } - BUG_ON(fd < 0); - stat = hv_fs_fstat(fd); - BUG_ON(stat.size < 0); - if (stat.flags & HV_FS_ISDIR) { - pr_warn("Ignoring hvfs file '%s': it's a directory\n", - initramfs_file); - return; - } - initrd = alloc_bootmem_pages(stat.size); - rc = hv_fs_pread(fd, (HV_VirtAddr) initrd, stat.size, 0); - if (rc != stat.size) { - pr_err("Error reading %d bytes from hvfs file '%s': %d\n", - stat.size, initramfs_file, rc); - free_initrd_mem((unsigned long) initrd, stat.size); - return; - } - initrd_start = (unsigned long) initrd; - initrd_end = initrd_start + stat.size; -} - -void __init free_initrd_mem(unsigned long begin, unsigned long end) -{ - free_bootmem_late(__pa(begin), end - begin); -} - -static int __init setup_initrd(char *str) -{ - char *endp; - unsigned long initrd_size; - - initrd_size = str ? simple_strtoul(str, &endp, 0) : 0; - if (initrd_size == 0 || *endp != '@') - return -EINVAL; - - initrd_start = simple_strtoul(endp+1, &endp, 0); - if (initrd_start == 0) - return -EINVAL; - - initrd_end = initrd_start + initrd_size; - - return 0; -} -early_param("initrd", setup_initrd); - -#else -static inline void load_hv_initrd(void) {} -#endif /* CONFIG_BLK_DEV_INITRD */ - -static void __init validate_hv(void) -{ - /* - * It may already be too late, but let's check our built-in - * configuration against what the hypervisor is providing. - */ - unsigned long glue_size = hv_sysconf(HV_SYSCONF_GLUE_SIZE); - int hv_page_size = hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL); - int hv_hpage_size = hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE); - HV_ASIDRange asid_range; - -#ifndef CONFIG_SMP - HV_Topology topology = hv_inquire_topology(); - BUG_ON(topology.coord.x != 0 || topology.coord.y != 0); - if (topology.width != 1 || topology.height != 1) { - pr_warn("Warning: booting UP kernel on %dx%d grid; will ignore all but first tile\n", - topology.width, topology.height); - } -#endif - - if (PAGE_OFFSET + HV_GLUE_START_CPA + glue_size > (unsigned long)_text) - early_panic("Hypervisor glue size %ld is too big!\n", - glue_size); - if (hv_page_size != PAGE_SIZE) - early_panic("Hypervisor page size %#x != our %#lx\n", - hv_page_size, PAGE_SIZE); - if (hv_hpage_size != HPAGE_SIZE) - early_panic("Hypervisor huge page size %#x != our %#lx\n", - hv_hpage_size, HPAGE_SIZE); - -#ifdef CONFIG_SMP - /* - * Some hypervisor APIs take a pointer to a bitmap array - * whose size is at least the number of cpus on the chip. - * We use a struct cpumask for this, so it must be big enough. - */ - if ((smp_height * smp_width) > nr_cpu_ids) - early_panic("Hypervisor %d x %d grid too big for Linux NR_CPUS %u\n", - smp_height, smp_width, nr_cpu_ids); -#endif - - /* - * Check that we're using allowed ASIDs, and initialize the - * various asid variables to their appropriate initial states. - */ - asid_range = hv_inquire_asid(0); - min_asid = asid_range.start; - __this_cpu_write(current_asid, min_asid); - max_asid = asid_range.start + asid_range.size - 1; - - if (hv_confstr(HV_CONFSTR_CHIP_MODEL, (HV_VirtAddr)chip_model, - sizeof(chip_model)) < 0) { - pr_err("Warning: HV_CONFSTR_CHIP_MODEL not available\n"); - strlcpy(chip_model, "unknown", sizeof(chip_model)); - } -} - -static void __init validate_va(void) -{ -#ifndef __tilegx__ /* FIXME: GX: probably some validation relevant here */ - /* - * Similarly, make sure we're only using allowed VAs. - * We assume we can contiguously use MEM_USER_INTRPT .. MEM_HV_START, - * and 0 .. KERNEL_HIGH_VADDR. - * In addition, make sure we CAN'T use the end of memory, since - * we use the last chunk of each pgd for the pgd_list. - */ - int i, user_kernel_ok = 0; - unsigned long max_va = 0; - unsigned long list_va = - ((PGD_LIST_OFFSET / sizeof(pgd_t)) << PGDIR_SHIFT); - - for (i = 0; ; ++i) { - HV_VirtAddrRange range = hv_inquire_virtual(i); - if (range.size == 0) - break; - if (range.start <= MEM_USER_INTRPT && - range.start + range.size >= MEM_HV_START) - user_kernel_ok = 1; - if (range.start == 0) - max_va = range.size; - BUG_ON(range.start + range.size > list_va); - } - if (!user_kernel_ok) - early_panic("Hypervisor not configured for user/kernel VAs\n"); - if (max_va == 0) - early_panic("Hypervisor not configured for low VAs\n"); - if (max_va < KERNEL_HIGH_VADDR) - early_panic("Hypervisor max VA %#lx smaller than %#lx\n", - max_va, KERNEL_HIGH_VADDR); - - /* Kernel PCs must have their high bit set; see intvec.S. */ - if ((long)VMALLOC_START >= 0) - early_panic("Linux VMALLOC region below the 2GB line (%#lx)!\n" - "Reconfigure the kernel with smaller VMALLOC_RESERVE\n", - VMALLOC_START); -#endif -} - -/* - * cpu_lotar_map lists all the cpus that are valid for the supervisor - * to cache data on at a page level, i.e. what cpus can be placed in - * the LOTAR field of a PTE. It is equivalent to the set of possible - * cpus plus any other cpus that are willing to share their cache. - * It is set by hv_inquire_tiles(HV_INQ_TILES_LOTAR). - */ -struct cpumask __ro_after_init cpu_lotar_map; -EXPORT_SYMBOL(cpu_lotar_map); - -/* - * hash_for_home_map lists all the tiles that hash-for-home data - * will be cached on. Note that this may includes tiles that are not - * valid for this supervisor to use otherwise (e.g. if a hypervisor - * device is being shared between multiple supervisors). - * It is set by hv_inquire_tiles(HV_INQ_TILES_HFH_CACHE). - */ -struct cpumask hash_for_home_map; -EXPORT_SYMBOL(hash_for_home_map); - -/* - * cpu_cacheable_map lists all the cpus whose caches the hypervisor can - * flush on our behalf. It is set to cpu_possible_mask OR'ed with - * hash_for_home_map, and it is what should be passed to - * hv_flush_remote() to flush all caches. Note that if there are - * dedicated hypervisor driver tiles that have authorized use of their - * cache, those tiles will only appear in cpu_lotar_map, NOT in - * cpu_cacheable_map, as they are a special case. - */ -struct cpumask __ro_after_init cpu_cacheable_map; -EXPORT_SYMBOL(cpu_cacheable_map); - -static __initdata struct cpumask disabled_map; - -static int __init disabled_cpus(char *str) -{ - int boot_cpu = smp_processor_id(); - - if (str == NULL || cpulist_parse_crop(str, &disabled_map) != 0) - return -EINVAL; - if (cpumask_test_cpu(boot_cpu, &disabled_map)) { - pr_err("disabled_cpus: can't disable boot cpu %d\n", boot_cpu); - cpumask_clear_cpu(boot_cpu, &disabled_map); - } - return 0; -} - -early_param("disabled_cpus", disabled_cpus); - -void __init print_disabled_cpus(void) -{ - if (!cpumask_empty(&disabled_map)) - pr_info("CPUs not available for Linux: %*pbl\n", - cpumask_pr_args(&disabled_map)); -} - -static void __init setup_cpu_maps(void) -{ - struct cpumask hv_disabled_map, cpu_possible_init; - int boot_cpu = smp_processor_id(); - int cpus, i, rc; - - /* Learn which cpus are allowed by the hypervisor. */ - rc = hv_inquire_tiles(HV_INQ_TILES_AVAIL, - (HV_VirtAddr) cpumask_bits(&cpu_possible_init), - sizeof(cpu_cacheable_map)); - if (rc < 0) - early_panic("hv_inquire_tiles(AVAIL) failed: rc %d\n", rc); - if (!cpumask_test_cpu(boot_cpu, &cpu_possible_init)) - early_panic("Boot CPU %d disabled by hypervisor!\n", boot_cpu); - - /* Compute the cpus disabled by the hvconfig file. */ - cpumask_complement(&hv_disabled_map, &cpu_possible_init); - - /* Include them with the cpus disabled by "disabled_cpus". */ - cpumask_or(&disabled_map, &disabled_map, &hv_disabled_map); - - /* - * Disable every cpu after "setup_max_cpus". But don't mark - * as disabled the cpus that are outside of our initial rectangle, - * since that turns out to be confusing. - */ - cpus = 1; /* this cpu */ - cpumask_set_cpu(boot_cpu, &disabled_map); /* ignore this cpu */ - for (i = 0; cpus < setup_max_cpus; ++i) - if (!cpumask_test_cpu(i, &disabled_map)) - ++cpus; - for (; i < smp_height * smp_width; ++i) - cpumask_set_cpu(i, &disabled_map); - cpumask_clear_cpu(boot_cpu, &disabled_map); /* reset this cpu */ - for (i = smp_height * smp_width; i < NR_CPUS; ++i) - cpumask_clear_cpu(i, &disabled_map); - - /* - * Setup cpu_possible map as every cpu allocated to us, minus - * the results of any "disabled_cpus" settings. - */ - cpumask_andnot(&cpu_possible_init, &cpu_possible_init, &disabled_map); - init_cpu_possible(&cpu_possible_init); - - /* Learn which cpus are valid for LOTAR caching. */ - rc = hv_inquire_tiles(HV_INQ_TILES_LOTAR, - (HV_VirtAddr) cpumask_bits(&cpu_lotar_map), - sizeof(cpu_lotar_map)); - if (rc < 0) { - pr_err("warning: no HV_INQ_TILES_LOTAR; using AVAIL\n"); - cpu_lotar_map = *cpu_possible_mask; - } - - /* Retrieve set of CPUs used for hash-for-home caching */ - rc = hv_inquire_tiles(HV_INQ_TILES_HFH_CACHE, - (HV_VirtAddr) hash_for_home_map.bits, - sizeof(hash_for_home_map)); - if (rc < 0) - early_panic("hv_inquire_tiles(HFH_CACHE) failed: rc %d\n", rc); - cpumask_or(&cpu_cacheable_map, cpu_possible_mask, &hash_for_home_map); -} - - -static int __init dataplane(char *str) -{ - pr_warn("WARNING: dataplane support disabled in this kernel\n"); - return 0; -} - -early_param("dataplane", dataplane); - -#ifdef CONFIG_NO_HZ_FULL -/* Warn if hypervisor shared cpus are marked as nohz_full. */ -static int __init check_nohz_full_cpus(void) -{ - struct cpumask shared; - int cpu; - - if (hv_inquire_tiles(HV_INQ_TILES_SHARED, - (HV_VirtAddr) shared.bits, sizeof(shared)) < 0) { - pr_warn("WARNING: No support for inquiring hv shared tiles\n"); - return 0; - } - for_each_cpu(cpu, &shared) { - if (tick_nohz_full_cpu(cpu)) - pr_warn("WARNING: nohz_full cpu %d receives hypervisor interrupts!\n", - cpu); - } - return 0; -} -arch_initcall(check_nohz_full_cpus); -#endif - -#ifdef CONFIG_CMDLINE_BOOL -static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; -#endif - -void __init setup_arch(char **cmdline_p) -{ - int len; - -#if defined(CONFIG_CMDLINE_BOOL) && defined(CONFIG_CMDLINE_OVERRIDE) - len = hv_get_command_line((HV_VirtAddr) boot_command_line, - COMMAND_LINE_SIZE); - if (boot_command_line[0]) - pr_warn("WARNING: ignoring dynamic command line \"%s\"\n", - boot_command_line); - strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE); -#else - char *hv_cmdline; -#if defined(CONFIG_CMDLINE_BOOL) - if (builtin_cmdline[0]) { - int builtin_len = strlcpy(boot_command_line, builtin_cmdline, - COMMAND_LINE_SIZE); - if (builtin_len < COMMAND_LINE_SIZE-1) - boot_command_line[builtin_len++] = ' '; - hv_cmdline = &boot_command_line[builtin_len]; - len = COMMAND_LINE_SIZE - builtin_len; - } else -#endif - { - hv_cmdline = boot_command_line; - len = COMMAND_LINE_SIZE; - } - len = hv_get_command_line((HV_VirtAddr) hv_cmdline, len); - if (len < 0 || len > COMMAND_LINE_SIZE) - early_panic("hv_get_command_line failed: %d\n", len); -#endif - - *cmdline_p = boot_command_line; - - /* Set disabled_map and setup_max_cpus very early */ - parse_early_param(); - - /* Make sure the kernel is compatible with the hypervisor. */ - validate_hv(); - validate_va(); - - setup_cpu_maps(); - - -#if defined(CONFIG_PCI) && !defined(__tilegx__) - /* - * Initialize the PCI structures. This is done before memory - * setup so that we know whether or not a pci_reserve region - * is necessary. - */ - if (tile_pci_init() == 0) - pci_reserve_mb = 0; - - /* PCI systems reserve a region just below 4GB for mapping iomem. */ - pci_reserve_end_pfn = (1 << (32 - PAGE_SHIFT)); - pci_reserve_start_pfn = pci_reserve_end_pfn - - (pci_reserve_mb << (20 - PAGE_SHIFT)); -#endif - - init_mm.start_code = (unsigned long) _text; - init_mm.end_code = (unsigned long) _etext; - init_mm.end_data = (unsigned long) _edata; - init_mm.brk = (unsigned long) _end; - - setup_memory(); - store_permanent_mappings(); - setup_bootmem_allocator(); - - /* - * NOTE: before this point _nobody_ is allowed to allocate - * any memory using the bootmem allocator. - */ - -#ifdef CONFIG_SWIOTLB - swiotlb_init(0); -#endif - - paging_init(); - setup_numa_mapping(); - zone_sizes_init(); - set_page_homes(); - setup_cpu(1); - setup_clock(); - load_hv_initrd(); -} - - -/* - * Set up per-cpu memory. - */ - -unsigned long __per_cpu_offset[NR_CPUS] __ro_after_init; -EXPORT_SYMBOL(__per_cpu_offset); - -static size_t __initdata pfn_offset[MAX_NUMNODES] = { 0 }; -static unsigned long __initdata percpu_pfn[NR_CPUS] = { 0 }; - -/* - * As the percpu code allocates pages, we return the pages from the - * end of the node for the specified cpu. - */ -static void *__init pcpu_fc_alloc(unsigned int cpu, size_t size, size_t align) -{ - int nid = cpu_to_node(cpu); - unsigned long pfn = node_percpu_pfn[nid] + pfn_offset[nid]; - - BUG_ON(size % PAGE_SIZE != 0); - pfn_offset[nid] += size / PAGE_SIZE; - BUG_ON(node_percpu[nid] < size); - node_percpu[nid] -= size; - if (percpu_pfn[cpu] == 0) - percpu_pfn[cpu] = pfn; - return pfn_to_kaddr(pfn); -} - -/* - * Pages reserved for percpu memory are not freeable, and in any case we are - * on a short path to panic() in setup_per_cpu_area() at this point anyway. - */ -static void __init pcpu_fc_free(void *ptr, size_t size) -{ -} - -/* - * Set up vmalloc page tables using bootmem for the percpu code. - */ -static void __init pcpu_fc_populate_pte(unsigned long addr) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - - BUG_ON(pgd_addr_invalid(addr)); - if (addr < VMALLOC_START || addr >= VMALLOC_END) - panic("PCPU addr %#lx outside vmalloc range %#lx..%#lx; try increasing CONFIG_VMALLOC_RESERVE\n", - addr, VMALLOC_START, VMALLOC_END); - - pgd = swapper_pg_dir + pgd_index(addr); - pud = pud_offset(pgd, addr); - BUG_ON(!pud_present(*pud)); - pmd = pmd_offset(pud, addr); - if (pmd_present(*pmd)) { - BUG_ON(pmd_huge_page(*pmd)); - } else { - pte = __alloc_bootmem(L2_KERNEL_PGTABLE_SIZE, - HV_PAGE_TABLE_ALIGN, 0); - pmd_populate_kernel(&init_mm, pmd, pte); - } -} - -void __init setup_per_cpu_areas(void) -{ - struct page *pg; - unsigned long delta, pfn, lowmem_va; - unsigned long size = percpu_size(); - char *ptr; - int rc, cpu, i; - - rc = pcpu_page_first_chunk(PERCPU_MODULE_RESERVE, pcpu_fc_alloc, - pcpu_fc_free, pcpu_fc_populate_pte); - if (rc < 0) - panic("Cannot initialize percpu area (err=%d)", rc); - - delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; - for_each_possible_cpu(cpu) { - __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu]; - - /* finv the copy out of cache so we can change homecache */ - ptr = pcpu_base_addr + pcpu_unit_offsets[cpu]; - __finv_buffer(ptr, size); - pfn = percpu_pfn[cpu]; - - /* Rewrite the page tables to cache on that cpu */ - pg = pfn_to_page(pfn); - for (i = 0; i < size; i += PAGE_SIZE, ++pfn, ++pg) { - - /* Update the vmalloc mapping and page home. */ - unsigned long addr = (unsigned long)ptr + i; - pte_t *ptep = virt_to_kpte(addr); - pte_t pte = *ptep; - BUG_ON(pfn != pte_pfn(pte)); - pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3); - pte = set_remote_cache_cpu(pte, cpu); - set_pte_at(&init_mm, addr, ptep, pte); - - /* Update the lowmem mapping for consistency. */ - lowmem_va = (unsigned long)pfn_to_kaddr(pfn); - ptep = virt_to_kpte(lowmem_va); - if (pte_huge(*ptep)) { - printk(KERN_DEBUG "early shatter of huge page at %#lx\n", - lowmem_va); - shatter_pmd((pmd_t *)ptep); - ptep = virt_to_kpte(lowmem_va); - BUG_ON(pte_huge(*ptep)); - } - BUG_ON(pfn != pte_pfn(*ptep)); - set_pte_at(&init_mm, lowmem_va, ptep, pte); - } - } - - /* Set our thread pointer appropriately. */ - set_my_cpu_offset(__per_cpu_offset[smp_processor_id()]); - - /* Make sure the finv's have completed. */ - mb_incoherent(); - - /* Flush the TLB so we reference it properly from here on out. */ - local_flush_tlb_all(); -} - -static struct resource data_resource = { - .name = "Kernel data", - .start = 0, - .end = 0, - .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM -}; - -static struct resource code_resource = { - .name = "Kernel code", - .start = 0, - .end = 0, - .flags = IORESOURCE_BUSY | IORESOURCE_SYSTEM_RAM -}; - -/* - * On Pro, we reserve all resources above 4GB so that PCI won't try to put - * mappings above 4GB. - */ -#if defined(CONFIG_PCI) && !defined(__tilegx__) -static struct resource* __init -insert_non_bus_resource(void) -{ - struct resource *res = - kzalloc(sizeof(struct resource), GFP_ATOMIC); - if (!res) - return NULL; - res->name = "Non-Bus Physical Address Space"; - res->start = (1ULL << 32); - res->end = -1LL; - res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; - if (insert_resource(&iomem_resource, res)) { - kfree(res); - return NULL; - } - return res; -} -#endif - -static struct resource* __init -insert_ram_resource(u64 start_pfn, u64 end_pfn, bool reserved) -{ - struct resource *res = - kzalloc(sizeof(struct resource), GFP_ATOMIC); - if (!res) - return NULL; - res->start = start_pfn << PAGE_SHIFT; - res->end = (end_pfn << PAGE_SHIFT) - 1; - res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; - if (reserved) { - res->name = "Reserved"; - } else { - res->name = "System RAM"; - res->flags |= IORESOURCE_SYSRAM; - } - if (insert_resource(&iomem_resource, res)) { - kfree(res); - return NULL; - } - return res; -} - -/* - * Request address space for all standard resources - * - * If the system includes PCI root complex drivers, we need to create - * a window just below 4GB where PCI BARs can be mapped. - */ -static int __init request_standard_resources(void) -{ - int i; - enum { CODE_DELTA = MEM_SV_START - PAGE_OFFSET }; - -#if defined(CONFIG_PCI) && !defined(__tilegx__) - insert_non_bus_resource(); -#endif - - for_each_online_node(i) { - u64 start_pfn = node_start_pfn[i]; - u64 end_pfn = node_end_pfn[i]; - -#if defined(CONFIG_PCI) && !defined(__tilegx__) - if (start_pfn <= pci_reserve_start_pfn && - end_pfn > pci_reserve_start_pfn) { - if (end_pfn > pci_reserve_end_pfn) - insert_ram_resource(pci_reserve_end_pfn, - end_pfn, 0); - end_pfn = pci_reserve_start_pfn; - } -#endif - insert_ram_resource(start_pfn, end_pfn, 0); - } - - code_resource.start = __pa(_text - CODE_DELTA); - code_resource.end = __pa(_etext - CODE_DELTA)-1; - data_resource.start = __pa(_sdata); - data_resource.end = __pa(_end)-1; - - insert_resource(&iomem_resource, &code_resource); - insert_resource(&iomem_resource, &data_resource); - - /* Mark any "memmap" regions busy for the resource manager. */ - for (i = 0; i < memmap_nr; ++i) { - struct memmap_entry *m = &memmap_map[i]; - insert_ram_resource(PFN_DOWN(m->addr), - PFN_UP(m->addr + m->size - 1), 1); - } - -#ifdef CONFIG_KEXEC - insert_resource(&iomem_resource, &crashk_res); -#endif - - return 0; -} - -subsys_initcall(request_standard_resources); diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c deleted file mode 100644 index f2bf557bb005..000000000000 --- a/arch/tile/kernel/signal.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG_SIG 0 - -/* - * Do a signal return; undo the signal stack. - */ - -int restore_sigcontext(struct pt_regs *regs, - struct sigcontext __user *sc) -{ - int err; - - /* Always make any pending restarted system calls return -EINTR */ - current->restart_block.fn = do_no_restart_syscall; - - /* - * Enforce that sigcontext is like pt_regs, and doesn't mess - * up our stack alignment rules. - */ - BUILD_BUG_ON(sizeof(struct sigcontext) != sizeof(struct pt_regs)); - BUILD_BUG_ON(sizeof(struct sigcontext) % 8 != 0); - err = __copy_from_user(regs, sc, sizeof(*regs)); - - /* Ensure that the PL is always set to USER_PL. */ - regs->ex1 = PL_ICS_EX1(USER_PL, EX1_ICS(regs->ex1)); - - regs->faultnum = INT_SWINT_1_SIGRETURN; - - return err; -} - -void signal_fault(const char *type, struct pt_regs *regs, - void __user *frame, int sig) -{ - trace_unhandled_signal(type, regs, (unsigned long)frame, SIGSEGV); - force_sigsegv(sig, current); -} - -/* The assembly shim for this function arranges to ignore the return value. */ -SYSCALL_DEFINE0(rt_sigreturn) -{ - struct pt_regs *regs = current_pt_regs(); - struct rt_sigframe __user *frame = - (struct rt_sigframe __user *)(regs->sp); - sigset_t set; - - if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) - goto badframe; - if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) - goto badframe; - - set_current_blocked(&set); - - if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) - goto badframe; - - if (restore_altstack(&frame->uc.uc_stack)) - goto badframe; - - return 0; - -badframe: - signal_fault("bad sigreturn frame", regs, frame, 0); - return 0; -} - -/* - * Set up a signal frame. - */ - -int setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs) -{ - return __copy_to_user(sc, regs, sizeof(*regs)); -} - -/* - * Determine which stack to use.. - */ -static inline void __user *get_sigframe(struct k_sigaction *ka, - struct pt_regs *regs, - size_t frame_size) -{ - unsigned long sp; - - /* Default to using normal stack */ - sp = regs->sp; - - /* - * If we are on the alternate signal stack and would overflow - * it, don't. Return an always-bogus address instead so we - * will die with SIGSEGV. - */ - if (on_sig_stack(sp) && !likely(on_sig_stack(sp - frame_size))) - return (void __user __force *)-1UL; - - /* This is the X/Open sanctioned signal stack switching. */ - if (ka->sa.sa_flags & SA_ONSTACK) { - if (sas_ss_flags(sp) == 0) - sp = current->sas_ss_sp + current->sas_ss_size; - } - - sp -= frame_size; - /* - * Align the stack pointer according to the TILE ABI, - * i.e. so that on function entry (sp & 15) == 0. - */ - sp &= -16UL; - return (void __user *) sp; -} - -static int setup_rt_frame(struct ksignal *ksig, sigset_t *set, - struct pt_regs *regs) -{ - unsigned long restorer; - struct rt_sigframe __user *frame; - int err = 0, sig = ksig->sig; - - frame = get_sigframe(&ksig->ka, regs, sizeof(*frame)); - - if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) - goto err; - - /* Always write at least the signal number for the stack backtracer. */ - if (ksig->ka.sa.sa_flags & SA_SIGINFO) { - /* At sigreturn time, restore the callee-save registers too. */ - err |= copy_siginfo_to_user(&frame->info, &ksig->info); - regs->flags |= PT_FLAGS_RESTORE_REGS; - } else { - err |= __put_user(ksig->info.si_signo, &frame->info.si_signo); - } - - /* Create the ucontext. */ - err |= __clear_user(&frame->save_area, sizeof(frame->save_area)); - err |= __put_user(0, &frame->uc.uc_flags); - err |= __put_user(NULL, &frame->uc.uc_link); - err |= __save_altstack(&frame->uc.uc_stack, regs->sp); - err |= setup_sigcontext(&frame->uc.uc_mcontext, regs); - err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); - if (err) - goto err; - - restorer = VDSO_SYM(&__vdso_rt_sigreturn); - if (ksig->ka.sa.sa_flags & SA_RESTORER) - restorer = (unsigned long) ksig->ka.sa.sa_restorer; - - /* - * Set up registers for signal handler. - * Registers that we don't modify keep the value they had from - * user-space at the time we took the signal. - * We always pass siginfo and mcontext, regardless of SA_SIGINFO, - * since some things rely on this (e.g. glibc's debug/segfault.c). - */ - regs->pc = (unsigned long) ksig->ka.sa.sa_handler; - regs->ex1 = PL_ICS_EX1(USER_PL, 1); /* set crit sec in handler */ - regs->sp = (unsigned long) frame; - regs->lr = restorer; - regs->regs[0] = (unsigned long) sig; - regs->regs[1] = (unsigned long) &frame->info; - regs->regs[2] = (unsigned long) &frame->uc; - regs->flags |= PT_FLAGS_CALLER_SAVES; - return 0; - -err: - trace_unhandled_signal("bad sigreturn frame", regs, - (unsigned long)frame, SIGSEGV); - return -EFAULT; -} - -/* - * OK, we're invoking a handler - */ - -static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) -{ - sigset_t *oldset = sigmask_to_save(); - int ret; - - /* Are we from a system call? */ - if (regs->faultnum == INT_SWINT_1) { - /* If so, check system call restarting.. */ - switch (regs->regs[0]) { - case -ERESTART_RESTARTBLOCK: - case -ERESTARTNOHAND: - regs->regs[0] = -EINTR; - break; - - case -ERESTARTSYS: - if (!(ksig->ka.sa.sa_flags & SA_RESTART)) { - regs->regs[0] = -EINTR; - break; - } - /* fallthrough */ - case -ERESTARTNOINTR: - /* Reload caller-saves to restore r0..r5 and r10. */ - regs->flags |= PT_FLAGS_CALLER_SAVES; - regs->regs[0] = regs->orig_r0; - regs->pc -= 8; - } - } - - /* Set up the stack frame */ -#ifdef CONFIG_COMPAT - if (is_compat_task()) - ret = compat_setup_rt_frame(ksig, oldset, regs); - else -#endif - ret = setup_rt_frame(ksig, oldset, regs); - - signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP)); -} - -/* - * Note that 'init' is a special process: it doesn't get signals it doesn't - * want to handle. Thus you cannot kill init even with a SIGKILL even by - * mistake. - */ -void do_signal(struct pt_regs *regs) -{ - struct ksignal ksig; - - /* - * i386 will check if we're coming from kernel mode and bail out - * here. In my experience this just turns weird crashes into - * weird spin-hangs. But if we find a case where this seems - * helpful, we can reinstate the check on "!user_mode(regs)". - */ - - if (get_signal(&ksig)) { - /* Whee! Actually deliver the signal. */ - handle_signal(&ksig, regs); - goto done; - } - - /* Did we come from a system call? */ - if (regs->faultnum == INT_SWINT_1) { - /* Restart the system call - no handlers present */ - switch (regs->regs[0]) { - case -ERESTARTNOHAND: - case -ERESTARTSYS: - case -ERESTARTNOINTR: - regs->flags |= PT_FLAGS_CALLER_SAVES; - regs->regs[0] = regs->orig_r0; - regs->pc -= 8; - break; - - case -ERESTART_RESTARTBLOCK: - regs->flags |= PT_FLAGS_CALLER_SAVES; - regs->regs[TREG_SYSCALL_NR] = __NR_restart_syscall; - regs->pc -= 8; - break; - } - } - - /* If there's no signal to deliver, just put the saved sigmask back. */ - restore_saved_sigmask(); - -done: - /* Avoid double syscall restart if there are nested signals. */ - regs->faultnum = INT_SWINT_1_SIGRETURN; -} - -int show_unhandled_signals = 1; - -static int __init crashinfo(char *str) -{ - const char *word; - - if (*str == '\0') - show_unhandled_signals = 2; - else if (*str != '=' || kstrtoint(++str, 0, &show_unhandled_signals) != 0) - return 0; - - switch (show_unhandled_signals) { - case 0: - word = "No"; - break; - case 1: - word = "One-line"; - break; - default: - word = "Detailed"; - break; - } - pr_info("%s crash reports will be generated on the console\n", word); - return 1; -} -__setup("crashinfo", crashinfo); - -static void dump_mem(void __user *address) -{ - void __user *addr; - enum { region_size = 256, bytes_per_line = 16 }; - int i, j, k; - int found_readable_mem = 0; - - if (!access_ok(VERIFY_READ, address, 1)) { - pr_err("Not dumping at address 0x%lx (kernel address)\n", - (unsigned long)address); - return; - } - - addr = (void __user *) - (((unsigned long)address & -bytes_per_line) - region_size/2); - if (addr > address) - addr = NULL; - for (i = 0; i < region_size; - addr += bytes_per_line, i += bytes_per_line) { - unsigned char buf[bytes_per_line]; - char line[100]; - if (copy_from_user(buf, addr, bytes_per_line)) - continue; - if (!found_readable_mem) { - pr_err("Dumping memory around address 0x%lx:\n", - (unsigned long)address); - found_readable_mem = 1; - } - j = sprintf(line, REGFMT ":", (unsigned long)addr); - for (k = 0; k < bytes_per_line; ++k) - j += sprintf(&line[j], " %02x", buf[k]); - pr_err("%s\n", line); - } - if (!found_readable_mem) - pr_err("No readable memory around address 0x%lx\n", - (unsigned long)address); -} - -void trace_unhandled_signal(const char *type, struct pt_regs *regs, - unsigned long address, int sig) -{ - struct task_struct *tsk = current; - - if (show_unhandled_signals == 0) - return; - - /* If the signal is handled, don't show it here. */ - if (!is_global_init(tsk)) { - void __user *handler = - tsk->sighand->action[sig-1].sa.sa_handler; - if (handler != SIG_IGN && handler != SIG_DFL) - return; - } - - /* Rate-limit the one-line output, not the detailed output. */ - if (show_unhandled_signals <= 1 && !printk_ratelimit()) - return; - - printk("%s%s[%d]: %s at %lx pc "REGFMT" signal %d", - task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, - tsk->comm, task_pid_nr(tsk), type, address, regs->pc, sig); - - print_vma_addr(KERN_CONT " in ", regs->pc); - - printk(KERN_CONT "\n"); - - if (show_unhandled_signals > 1) { - switch (sig) { - case SIGILL: - case SIGFPE: - case SIGSEGV: - case SIGBUS: - pr_err("User crash: signal %d, trap %ld, address 0x%lx\n", - sig, regs->faultnum, address); - show_regs(regs); - dump_mem((void __user *)address); - break; - default: - pr_err("User crash: signal %d, trap %ld\n", - sig, regs->faultnum); - break; - } - } -} diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c deleted file mode 100644 index 479d8033a801..000000000000 --- a/arch/tile/kernel/single_step.c +++ /dev/null @@ -1,786 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * A code-rewriter that enables instruction single-stepping. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifndef __tilegx__ /* Hardware support for single step unavailable. */ - -#define signExtend17(val) sign_extend((val), 17) -#define TILE_X1_MASK (0xffffffffULL << 31) - -enum mem_op { - MEMOP_NONE, - MEMOP_LOAD, - MEMOP_STORE, - MEMOP_LOAD_POSTINCR, - MEMOP_STORE_POSTINCR -}; - -static inline tilepro_bundle_bits set_BrOff_X1(tilepro_bundle_bits n, - s32 offset) -{ - tilepro_bundle_bits result; - - /* mask out the old offset */ - tilepro_bundle_bits mask = create_BrOff_X1(-1); - result = n & (~mask); - - /* or in the new offset */ - result |= create_BrOff_X1(offset); - - return result; -} - -static inline tilepro_bundle_bits move_X1(tilepro_bundle_bits n, int dest, - int src) -{ - tilepro_bundle_bits result; - tilepro_bundle_bits op; - - result = n & (~TILE_X1_MASK); - - op = create_Opcode_X1(SPECIAL_0_OPCODE_X1) | - create_RRROpcodeExtension_X1(OR_SPECIAL_0_OPCODE_X1) | - create_Dest_X1(dest) | - create_SrcB_X1(TREG_ZERO) | - create_SrcA_X1(src) ; - - result |= op; - return result; -} - -static inline tilepro_bundle_bits nop_X1(tilepro_bundle_bits n) -{ - return move_X1(n, TREG_ZERO, TREG_ZERO); -} - -static inline tilepro_bundle_bits addi_X1( - tilepro_bundle_bits n, int dest, int src, int imm) -{ - n &= ~TILE_X1_MASK; - - n |= (create_SrcA_X1(src) | - create_Dest_X1(dest) | - create_Imm8_X1(imm) | - create_S_X1(0) | - create_Opcode_X1(IMM_0_OPCODE_X1) | - create_ImmOpcodeExtension_X1(ADDI_IMM_0_OPCODE_X1)); - - return n; -} - -static tilepro_bundle_bits rewrite_load_store_unaligned( - struct single_step_state *state, - tilepro_bundle_bits bundle, - struct pt_regs *regs, - enum mem_op mem_op, - int size, int sign_ext) -{ - unsigned char __user *addr; - int val_reg, addr_reg, err, val; - int align_ctl; - - align_ctl = unaligned_fixup; - switch (task_thread_info(current)->align_ctl) { - case PR_UNALIGN_NOPRINT: - align_ctl = 1; - break; - case PR_UNALIGN_SIGBUS: - align_ctl = 0; - break; - } - - /* Get address and value registers */ - if (bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK) { - addr_reg = get_SrcA_Y2(bundle); - val_reg = get_SrcBDest_Y2(bundle); - } else if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) { - addr_reg = get_SrcA_X1(bundle); - val_reg = get_Dest_X1(bundle); - } else { - addr_reg = get_SrcA_X1(bundle); - val_reg = get_SrcB_X1(bundle); - } - - /* - * If registers are not GPRs, don't try to handle it. - * - * FIXME: we could handle non-GPR loads by getting the real value - * from memory, writing it to the single step buffer, using a - * temp_reg to hold a pointer to that memory, then executing that - * instruction and resetting temp_reg. For non-GPR stores, it's a - * little trickier; we could use the single step buffer for that - * too, but we'd have to add some more state bits so that we could - * call back in here to copy that value to the real target. For - * now, we just handle the simple case. - */ - if ((val_reg >= PTREGS_NR_GPRS && - (val_reg != TREG_ZERO || - mem_op == MEMOP_LOAD || - mem_op == MEMOP_LOAD_POSTINCR)) || - addr_reg >= PTREGS_NR_GPRS) - return bundle; - - /* If it's aligned, don't handle it specially */ - addr = (void __user *)regs->regs[addr_reg]; - if (((unsigned long)addr % size) == 0) - return bundle; - - /* - * Return SIGBUS with the unaligned address, if requested. - * Note that we return SIGBUS even for completely invalid addresses - * as long as they are in fact unaligned; this matches what the - * tilepro hardware would be doing, if it could provide us with the - * actual bad address in an SPR, which it doesn't. - */ - if (align_ctl == 0) { - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGBUS; - info.si_code = BUS_ADRALN; - info.si_addr = addr; - - trace_unhandled_signal("unaligned trap", regs, - (unsigned long)addr, SIGBUS); - force_sig_info(info.si_signo, &info, current); - return (tilepro_bundle_bits) 0; - } - - /* Handle unaligned load/store */ - if (mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR) { - unsigned short val_16; - switch (size) { - case 2: - err = copy_from_user(&val_16, addr, sizeof(val_16)); - val = sign_ext ? ((short)val_16) : val_16; - break; - case 4: - err = copy_from_user(&val, addr, sizeof(val)); - break; - default: - BUG(); - } - if (err == 0) { - state->update_reg = val_reg; - state->update_value = val; - state->update = 1; - } - } else { - unsigned short val_16; - val = (val_reg == TREG_ZERO) ? 0 : regs->regs[val_reg]; - switch (size) { - case 2: - val_16 = val; - err = copy_to_user(addr, &val_16, sizeof(val_16)); - break; - case 4: - err = copy_to_user(addr, &val, sizeof(val)); - break; - default: - BUG(); - } - } - - if (err) { - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGBUS; - info.si_code = BUS_ADRALN; - info.si_addr = addr; - - trace_unhandled_signal("bad address for unaligned fixup", regs, - (unsigned long)addr, SIGBUS); - force_sig_info(info.si_signo, &info, current); - return (tilepro_bundle_bits) 0; - } - - if (unaligned_printk || unaligned_fixup_count == 0) { - pr_info("Process %d/%s: PC %#lx: Fixup of unaligned %s at %#lx\n", - current->pid, current->comm, regs->pc, - mem_op == MEMOP_LOAD || mem_op == MEMOP_LOAD_POSTINCR ? - "load" : "store", - (unsigned long)addr); - if (!unaligned_printk) { -#define P pr_info -P("\n"); -P("Unaligned fixups in the kernel will slow your application considerably.\n"); -P("To find them, write a \"1\" to /proc/sys/tile/unaligned_fixup/printk,\n"); -P("which requests the kernel show all unaligned fixups, or write a \"0\"\n"); -P("to /proc/sys/tile/unaligned_fixup/enabled, in which case each unaligned\n"); -P("access will become a SIGBUS you can debug. No further warnings will be\n"); -P("shown so as to avoid additional slowdown, but you can track the number\n"); -P("of fixups performed via /proc/sys/tile/unaligned_fixup/count.\n"); -P("Use the tile-addr2line command (see \"info addr2line\") to decode PCs.\n"); -P("\n"); -#undef P - } - } - ++unaligned_fixup_count; - - if (bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK) { - /* Convert the Y2 instruction to a prefetch. */ - bundle &= ~(create_SrcBDest_Y2(-1) | - create_Opcode_Y2(-1)); - bundle |= (create_SrcBDest_Y2(TREG_ZERO) | - create_Opcode_Y2(LW_OPCODE_Y2)); - /* Replace the load postincr with an addi */ - } else if (mem_op == MEMOP_LOAD_POSTINCR) { - bundle = addi_X1(bundle, addr_reg, addr_reg, - get_Imm8_X1(bundle)); - /* Replace the store postincr with an addi */ - } else if (mem_op == MEMOP_STORE_POSTINCR) { - bundle = addi_X1(bundle, addr_reg, addr_reg, - get_Dest_Imm8_X1(bundle)); - } else { - /* Convert the X1 instruction to a nop. */ - bundle &= ~(create_Opcode_X1(-1) | - create_UnShOpcodeExtension_X1(-1) | - create_UnOpcodeExtension_X1(-1)); - bundle |= (create_Opcode_X1(SHUN_0_OPCODE_X1) | - create_UnShOpcodeExtension_X1( - UN_0_SHUN_0_OPCODE_X1) | - create_UnOpcodeExtension_X1( - NOP_UN_0_SHUN_0_OPCODE_X1)); - } - - return bundle; -} - -/* - * Called after execve() has started the new image. This allows us - * to reset the info state. Note that the the mmap'ed memory, if there - * was any, has already been unmapped by the exec. - */ -void single_step_execve(void) -{ - struct thread_info *ti = current_thread_info(); - kfree(ti->step_state); - ti->step_state = NULL; -} - -/* - * single_step_once() - entry point when single stepping has been triggered. - * @regs: The machine register state - * - * When we arrive at this routine via a trampoline, the single step - * engine copies the executing bundle to the single step buffer. - * If the instruction is a condition branch, then the target is - * reset to one past the next instruction. If the instruction - * sets the lr, then that is noted. If the instruction is a jump - * or call, then the new target pc is preserved and the current - * bundle instruction set to null. - * - * The necessary post-single-step rewriting information is stored in - * single_step_state-> We use data segment values because the - * stack will be rewound when we run the rewritten single-stepped - * instruction. - */ -void single_step_once(struct pt_regs *regs) -{ - extern tilepro_bundle_bits __single_step_ill_insn; - extern tilepro_bundle_bits __single_step_j_insn; - extern tilepro_bundle_bits __single_step_addli_insn; - extern tilepro_bundle_bits __single_step_auli_insn; - struct thread_info *info = (void *)current_thread_info(); - struct single_step_state *state = info->step_state; - int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); - tilepro_bundle_bits __user *buffer, *pc; - tilepro_bundle_bits bundle; - int temp_reg; - int target_reg = TREG_LR; - int err; - enum mem_op mem_op = MEMOP_NONE; - int size = 0, sign_ext = 0; /* happy compiler */ - int align_ctl; - - align_ctl = unaligned_fixup; - switch (task_thread_info(current)->align_ctl) { - case PR_UNALIGN_NOPRINT: - align_ctl = 1; - break; - case PR_UNALIGN_SIGBUS: - align_ctl = 0; - break; - } - - asm( -" .pushsection .rodata.single_step\n" -" .align 8\n" -" .globl __single_step_ill_insn\n" -"__single_step_ill_insn:\n" -" ill\n" -" .globl __single_step_addli_insn\n" -"__single_step_addli_insn:\n" -" { nop; addli r0, zero, 0 }\n" -" .globl __single_step_auli_insn\n" -"__single_step_auli_insn:\n" -" { nop; auli r0, r0, 0 }\n" -" .globl __single_step_j_insn\n" -"__single_step_j_insn:\n" -" j .\n" -" .popsection\n" - ); - - /* - * Enable interrupts here to allow touching userspace and the like. - * The callers expect this: do_trap() already has interrupts - * enabled, and do_work_pending() handles functions that enable - * interrupts internally. - */ - local_irq_enable(); - - if (state == NULL) { - /* allocate a page of writable, executable memory */ - state = kmalloc(sizeof(struct single_step_state), GFP_KERNEL); - if (state == NULL) { - pr_err("Out of kernel memory trying to single-step\n"); - return; - } - - /* allocate a cache line of writable, executable memory */ - buffer = (void __user *) vm_mmap(NULL, 0, 64, - PROT_EXEC | PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - 0); - - if (IS_ERR((void __force *)buffer)) { - kfree(state); - pr_err("Out of kernel pages trying to single-step\n"); - return; - } - - state->buffer = buffer; - state->is_enabled = 0; - - info->step_state = state; - - /* Validate our stored instruction patterns */ - BUG_ON(get_Opcode_X1(__single_step_addli_insn) != - ADDLI_OPCODE_X1); - BUG_ON(get_Opcode_X1(__single_step_auli_insn) != - AULI_OPCODE_X1); - BUG_ON(get_SrcA_X1(__single_step_addli_insn) != TREG_ZERO); - BUG_ON(get_Dest_X1(__single_step_addli_insn) != 0); - BUG_ON(get_JOffLong_X1(__single_step_j_insn) != 0); - } - - /* - * If we are returning from a syscall, we still haven't hit the - * "ill" for the swint1 instruction. So back the PC up to be - * pointing at the swint1, but we'll actually return directly - * back to the "ill" so we come back in via SIGILL as if we - * had "executed" the swint1 without ever being in kernel space. - */ - if (regs->faultnum == INT_SWINT_1) - regs->pc -= 8; - - pc = (tilepro_bundle_bits __user *)(regs->pc); - if (get_user(bundle, pc) != 0) { - pr_err("Couldn't read instruction at %p trying to step\n", pc); - return; - } - - /* We'll follow the instruction with 2 ill op bundles */ - state->orig_pc = (unsigned long)pc; - state->next_pc = (unsigned long)(pc + 1); - state->branch_next_pc = 0; - state->update = 0; - - if (!(bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK)) { - /* two wide, check for control flow */ - int opcode = get_Opcode_X1(bundle); - - switch (opcode) { - /* branches */ - case BRANCH_OPCODE_X1: - { - s32 offset = signExtend17(get_BrOff_X1(bundle)); - - /* - * For branches, we use a rewriting trick to let the - * hardware evaluate whether the branch is taken or - * untaken. We record the target offset and then - * rewrite the branch instruction to target 1 insn - * ahead if the branch is taken. We then follow the - * rewritten branch with two bundles, each containing - * an "ill" instruction. The supervisor examines the - * pc after the single step code is executed, and if - * the pc is the first ill instruction, then the - * branch (if any) was not taken. If the pc is the - * second ill instruction, then the branch was - * taken. The new pc is computed for these cases, and - * inserted into the registers for the thread. If - * the pc is the start of the single step code, then - * an exception or interrupt was taken before the - * code started processing, and the same "original" - * pc is restored. This change, different from the - * original implementation, has the advantage of - * executing a single user instruction. - */ - state->branch_next_pc = (unsigned long)(pc + offset); - - /* rewrite branch offset to go forward one bundle */ - bundle = set_BrOff_X1(bundle, 2); - } - break; - - /* jumps */ - case JALB_OPCODE_X1: - case JALF_OPCODE_X1: - state->update = 1; - state->next_pc = - (unsigned long) (pc + get_JOffLong_X1(bundle)); - break; - - case JB_OPCODE_X1: - case JF_OPCODE_X1: - state->next_pc = - (unsigned long) (pc + get_JOffLong_X1(bundle)); - bundle = nop_X1(bundle); - break; - - case SPECIAL_0_OPCODE_X1: - switch (get_RRROpcodeExtension_X1(bundle)) { - /* jump-register */ - case JALRP_SPECIAL_0_OPCODE_X1: - case JALR_SPECIAL_0_OPCODE_X1: - state->update = 1; - state->next_pc = - regs->regs[get_SrcA_X1(bundle)]; - break; - - case JRP_SPECIAL_0_OPCODE_X1: - case JR_SPECIAL_0_OPCODE_X1: - state->next_pc = - regs->regs[get_SrcA_X1(bundle)]; - bundle = nop_X1(bundle); - break; - - case LNK_SPECIAL_0_OPCODE_X1: - state->update = 1; - target_reg = get_Dest_X1(bundle); - break; - - /* stores */ - case SH_SPECIAL_0_OPCODE_X1: - mem_op = MEMOP_STORE; - size = 2; - break; - - case SW_SPECIAL_0_OPCODE_X1: - mem_op = MEMOP_STORE; - size = 4; - break; - } - break; - - /* loads and iret */ - case SHUN_0_OPCODE_X1: - if (get_UnShOpcodeExtension_X1(bundle) == - UN_0_SHUN_0_OPCODE_X1) { - switch (get_UnOpcodeExtension_X1(bundle)) { - case LH_UN_0_SHUN_0_OPCODE_X1: - mem_op = MEMOP_LOAD; - size = 2; - sign_ext = 1; - break; - - case LH_U_UN_0_SHUN_0_OPCODE_X1: - mem_op = MEMOP_LOAD; - size = 2; - sign_ext = 0; - break; - - case LW_UN_0_SHUN_0_OPCODE_X1: - mem_op = MEMOP_LOAD; - size = 4; - break; - - case IRET_UN_0_SHUN_0_OPCODE_X1: - { - unsigned long ex0_0 = __insn_mfspr( - SPR_EX_CONTEXT_0_0); - unsigned long ex0_1 = __insn_mfspr( - SPR_EX_CONTEXT_0_1); - /* - * Special-case it if we're iret'ing - * to PL0 again. Otherwise just let - * it run and it will generate SIGILL. - */ - if (EX1_PL(ex0_1) == USER_PL) { - state->next_pc = ex0_0; - regs->ex1 = ex0_1; - bundle = nop_X1(bundle); - } - } - } - } - break; - - /* postincrement operations */ - case IMM_0_OPCODE_X1: - switch (get_ImmOpcodeExtension_X1(bundle)) { - case LWADD_IMM_0_OPCODE_X1: - mem_op = MEMOP_LOAD_POSTINCR; - size = 4; - break; - - case LHADD_IMM_0_OPCODE_X1: - mem_op = MEMOP_LOAD_POSTINCR; - size = 2; - sign_ext = 1; - break; - - case LHADD_U_IMM_0_OPCODE_X1: - mem_op = MEMOP_LOAD_POSTINCR; - size = 2; - sign_ext = 0; - break; - - case SWADD_IMM_0_OPCODE_X1: - mem_op = MEMOP_STORE_POSTINCR; - size = 4; - break; - - case SHADD_IMM_0_OPCODE_X1: - mem_op = MEMOP_STORE_POSTINCR; - size = 2; - break; - - default: - break; - } - break; - } - - if (state->update) { - /* - * Get an available register. We start with a - * bitmask with 1's for available registers. - * We truncate to the low 32 registers since - * we are guaranteed to have set bits in the - * low 32 bits, then use ctz to pick the first. - */ - u32 mask = (u32) ~((1ULL << get_Dest_X0(bundle)) | - (1ULL << get_SrcA_X0(bundle)) | - (1ULL << get_SrcB_X0(bundle)) | - (1ULL << target_reg)); - temp_reg = __builtin_ctz(mask); - state->update_reg = temp_reg; - state->update_value = regs->regs[temp_reg]; - regs->regs[temp_reg] = (unsigned long) (pc+1); - regs->flags |= PT_FLAGS_RESTORE_REGS; - bundle = move_X1(bundle, target_reg, temp_reg); - } - } else { - int opcode = get_Opcode_Y2(bundle); - - switch (opcode) { - /* loads */ - case LH_OPCODE_Y2: - mem_op = MEMOP_LOAD; - size = 2; - sign_ext = 1; - break; - - case LH_U_OPCODE_Y2: - mem_op = MEMOP_LOAD; - size = 2; - sign_ext = 0; - break; - - case LW_OPCODE_Y2: - mem_op = MEMOP_LOAD; - size = 4; - break; - - /* stores */ - case SH_OPCODE_Y2: - mem_op = MEMOP_STORE; - size = 2; - break; - - case SW_OPCODE_Y2: - mem_op = MEMOP_STORE; - size = 4; - break; - } - } - - /* - * Check if we need to rewrite an unaligned load/store. - * Returning zero is a special value meaning we generated a signal. - */ - if (mem_op != MEMOP_NONE && align_ctl >= 0) { - bundle = rewrite_load_store_unaligned(state, bundle, regs, - mem_op, size, sign_ext); - if (bundle == 0) - return; - } - - /* write the bundle to our execution area */ - buffer = state->buffer; - err = __put_user(bundle, buffer++); - - /* - * If we're really single-stepping, we take an INT_ILL after. - * If we're just handling an unaligned access, we can just - * jump directly back to where we were in user code. - */ - if (is_single_step) { - err |= __put_user(__single_step_ill_insn, buffer++); - err |= __put_user(__single_step_ill_insn, buffer++); - } else { - long delta; - - if (state->update) { - /* We have some state to update; do it inline */ - int ha16; - bundle = __single_step_addli_insn; - bundle |= create_Dest_X1(state->update_reg); - bundle |= create_Imm16_X1(state->update_value); - err |= __put_user(bundle, buffer++); - bundle = __single_step_auli_insn; - bundle |= create_Dest_X1(state->update_reg); - bundle |= create_SrcA_X1(state->update_reg); - ha16 = (state->update_value + 0x8000) >> 16; - bundle |= create_Imm16_X1(ha16); - err |= __put_user(bundle, buffer++); - state->update = 0; - } - - /* End with a jump back to the next instruction */ - delta = ((regs->pc + TILEPRO_BUNDLE_SIZE_IN_BYTES) - - (unsigned long)buffer) >> - TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES; - bundle = __single_step_j_insn; - bundle |= create_JOffLong_X1(delta); - err |= __put_user(bundle, buffer++); - } - - if (err) { - pr_err("Fault when writing to single-step buffer\n"); - return; - } - - /* - * Flush the buffer. - * We do a local flush only, since this is a thread-specific buffer. - */ - __flush_icache_range((unsigned long)state->buffer, - (unsigned long)buffer); - - /* Indicate enabled */ - state->is_enabled = is_single_step; - regs->pc = (unsigned long)state->buffer; - - /* Fault immediately if we are coming back from a syscall. */ - if (regs->faultnum == INT_SWINT_1) - regs->pc += 8; -} - -#else - -static DEFINE_PER_CPU(unsigned long, ss_saved_pc); - - -/* - * Called directly on the occasion of an interrupt. - * - * If the process doesn't have single step set, then we use this as an - * opportunity to turn single step off. - * - * It has been mentioned that we could conditionally turn off single stepping - * on each entry into the kernel and rely on single_step_once to turn it - * on for the processes that matter (as we already do), but this - * implementation is somewhat more efficient in that we muck with registers - * once on a bum interrupt rather than on every entry into the kernel. - * - * If SINGLE_STEP_CONTROL_K has CANCELED set, then an interrupt occurred, - * so we have to run through this process again before we can say that an - * instruction has executed. - * - * swint will set CANCELED, but it's a legitimate instruction. Fortunately - * it changes the PC. If it hasn't changed, then we know that the interrupt - * wasn't generated by swint and we'll need to run this process again before - * we can say an instruction has executed. - * - * If either CANCELED == 0 or the PC's changed, we send out SIGTRAPs and get - * on with our lives. - */ - -void gx_singlestep_handle(struct pt_regs *regs, int fault_num) -{ - unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc); - struct thread_info *info = (void *)current_thread_info(); - int is_single_step = test_ti_thread_flag(info, TIF_SINGLESTEP); - unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K); - - if (is_single_step == 0) { - __insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 0); - - } else if ((*ss_pc != regs->pc) || - (!(control & SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK))) { - - control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK; - control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK; - __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); - send_sigtrap(current, regs); - } -} - - -/* - * Called from need_singlestep. Set up the control registers and the enable - * register, then return back. - */ - -void single_step_once(struct pt_regs *regs) -{ - unsigned long *ss_pc = this_cpu_ptr(&ss_saved_pc); - unsigned long control = __insn_mfspr(SPR_SINGLE_STEP_CONTROL_K); - - *ss_pc = regs->pc; - control |= SPR_SINGLE_STEP_CONTROL_1__CANCELED_MASK; - control |= SPR_SINGLE_STEP_CONTROL_1__INHIBIT_MASK; - __insn_mtspr(SPR_SINGLE_STEP_CONTROL_K, control); - __insn_mtspr(SPR_SINGLE_STEP_EN_K_K, 1 << USER_PL); -} - -void single_step_execve(void) -{ - /* Nothing */ -} - -#endif /* !__tilegx__ */ diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c deleted file mode 100644 index 94a62e1197ce..000000000000 --- a/arch/tile/kernel/smp.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * TILE SMP support routines. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * We write to width and height with a single store in head_NN.S, - * so make the variable aligned to "long". - */ -HV_Topology smp_topology __ro_after_init __aligned(sizeof(long)); -EXPORT_SYMBOL(smp_topology); - -#if CHIP_HAS_IPI() -static unsigned long __iomem *ipi_mappings[NR_CPUS]; -#endif - -/* Does messaging work correctly to the local cpu? */ -bool self_interrupt_ok; - -/* - * Top-level send_IPI*() functions to send messages to other cpus. - */ - -/* Set by smp_send_stop() to avoid recursive panics. */ -static int stopping_cpus; - -static void __send_IPI_many(HV_Recipient *recip, int nrecip, int tag) -{ - int sent = 0; - while (sent < nrecip) { - int rc = hv_send_message(recip, nrecip, - (HV_VirtAddr)&tag, sizeof(tag)); - if (rc < 0) { - if (!stopping_cpus) /* avoid recursive panic */ - panic("hv_send_message returned %d", rc); - break; - } - WARN_ONCE(rc == 0, "hv_send_message() returned zero\n"); - sent += rc; - } -} - -void send_IPI_single(int cpu, int tag) -{ - HV_Recipient recip = { - .y = cpu / smp_width, - .x = cpu % smp_width, - .state = HV_TO_BE_SENT - }; - __send_IPI_many(&recip, 1, tag); -} - -void send_IPI_many(const struct cpumask *mask, int tag) -{ - HV_Recipient recip[NR_CPUS]; - int cpu; - int nrecip = 0; - int my_cpu = smp_processor_id(); - for_each_cpu(cpu, mask) { - HV_Recipient *r; - BUG_ON(cpu == my_cpu); - r = &recip[nrecip++]; - r->y = cpu / smp_width; - r->x = cpu % smp_width; - r->state = HV_TO_BE_SENT; - } - __send_IPI_many(recip, nrecip, tag); -} - -void send_IPI_allbutself(int tag) -{ - struct cpumask mask; - cpumask_copy(&mask, cpu_online_mask); - cpumask_clear_cpu(smp_processor_id(), &mask); - send_IPI_many(&mask, tag); -} - -/* - * Functions related to starting/stopping cpus. - */ - -/* Handler to start the current cpu. */ -static void smp_start_cpu_interrupt(void) -{ - get_irq_regs()->pc = start_cpu_function_addr; -} - -/* Handler to stop the current cpu. */ -static void smp_stop_cpu_interrupt(void) -{ - arch_local_irq_disable_all(); - set_cpu_online(smp_processor_id(), 0); - for (;;) - asm("nap; nop"); -} - -/* This function calls the 'stop' function on all other CPUs in the system. */ -void smp_send_stop(void) -{ - stopping_cpus = 1; - send_IPI_allbutself(MSG_TAG_STOP_CPU); -} - -/* On panic, just wait; we may get an smp_send_stop() later on. */ -void panic_smp_self_stop(void) -{ - while (1) - asm("nap; nop"); -} - -/* - * Dispatch code called from hv_message_intr() for HV_MSG_TILE hv messages. - */ -void evaluate_message(int tag) -{ - switch (tag) { - case MSG_TAG_START_CPU: /* Start up a cpu */ - smp_start_cpu_interrupt(); - break; - - case MSG_TAG_STOP_CPU: /* Sent to shut down slave CPU's */ - smp_stop_cpu_interrupt(); - break; - - case MSG_TAG_CALL_FUNCTION_MANY: /* Call function on cpumask */ - generic_smp_call_function_interrupt(); - break; - - case MSG_TAG_CALL_FUNCTION_SINGLE: /* Call function on one other CPU */ - generic_smp_call_function_single_interrupt(); - break; - - case MSG_TAG_IRQ_WORK: /* Invoke IRQ work */ - irq_work_run(); - break; - - default: - panic("Unknown IPI message tag %d", tag); - break; - } -} - - -/* - * flush_icache_range() code uses smp_call_function(). - */ - -struct ipi_flush { - unsigned long start; - unsigned long end; -}; - -static void ipi_flush_icache_range(void *info) -{ - struct ipi_flush *flush = (struct ipi_flush *) info; - __flush_icache_range(flush->start, flush->end); -} - -void flush_icache_range(unsigned long start, unsigned long end) -{ - struct ipi_flush flush = { start, end }; - - /* If invoked with irqs disabled, we can not issue IPIs. */ - if (irqs_disabled()) - flush_remote(0, HV_FLUSH_EVICT_L1I, NULL, 0, 0, 0, - NULL, NULL, 0); - else { - preempt_disable(); - on_each_cpu(ipi_flush_icache_range, &flush, 1); - preempt_enable(); - } -} -EXPORT_SYMBOL(flush_icache_range); - - -#ifdef CONFIG_IRQ_WORK -void arch_irq_work_raise(void) -{ - if (arch_irq_work_has_interrupt()) - send_IPI_single(smp_processor_id(), MSG_TAG_IRQ_WORK); -} -#endif - - -/* Called when smp_send_reschedule() triggers IRQ_RESCHEDULE. */ -static irqreturn_t handle_reschedule_ipi(int irq, void *token) -{ - __this_cpu_inc(irq_stat.irq_resched_count); - scheduler_ipi(); - - return IRQ_HANDLED; -} - -static struct irqaction resched_action = { - .handler = handle_reschedule_ipi, - .name = "resched", - .dev_id = handle_reschedule_ipi /* unique token */, -}; - -void __init ipi_init(void) -{ - int cpu = smp_processor_id(); - HV_Recipient recip = { .y = cpu_y(cpu), .x = cpu_x(cpu), - .state = HV_TO_BE_SENT }; - int tag = MSG_TAG_CALL_FUNCTION_SINGLE; - - /* - * Test if we can message ourselves for arch_irq_work_raise. - * This functionality is only available in the Tilera hypervisor - * in versions 4.3.4 and following. - */ - if (hv_send_message(&recip, 1, (HV_VirtAddr)&tag, sizeof(tag)) == 1) - self_interrupt_ok = true; - else - pr_warn("Older hypervisor: disabling fast irq_work_raise\n"); - -#if CHIP_HAS_IPI() - /* Map IPI trigger MMIO addresses. */ - for_each_possible_cpu(cpu) { - HV_Coord tile; - HV_PTE pte; - unsigned long offset; - - tile.x = cpu_x(cpu); - tile.y = cpu_y(cpu); - if (hv_get_ipi_pte(tile, KERNEL_PL, &pte) != 0) - panic("Failed to initialize IPI for cpu %d\n", cpu); - - offset = PFN_PHYS(pte_pfn(pte)); - ipi_mappings[cpu] = ioremap_prot(offset, PAGE_SIZE, pte); - } -#endif - - /* Bind handle_reschedule_ipi() to IRQ_RESCHEDULE. */ - tile_irq_activate(IRQ_RESCHEDULE, TILE_IRQ_PERCPU); - BUG_ON(setup_irq(IRQ_RESCHEDULE, &resched_action)); -} - -#if CHIP_HAS_IPI() - -void smp_send_reschedule(int cpu) -{ - WARN_ON(cpu_is_offline(cpu)); - - /* - * We just want to do an MMIO store. The traditional writeq() - * functions aren't really correct here, since they're always - * directed at the PCI shim. For now, just do a raw store, - * casting away the __iomem attribute. - */ - ((unsigned long __force *)ipi_mappings[cpu])[IRQ_RESCHEDULE] = 0; -} - -#else - -void smp_send_reschedule(int cpu) -{ - HV_Coord coord; - - WARN_ON(cpu_is_offline(cpu)); - - coord.y = cpu_y(cpu); - coord.x = cpu_x(cpu); - hv_trigger_ipi(coord, IRQ_RESCHEDULE); -} - -#endif /* CHIP_HAS_IPI() */ diff --git a/arch/tile/kernel/smpboot.c b/arch/tile/kernel/smpboot.c deleted file mode 100644 index 869c22e57561..000000000000 --- a/arch/tile/kernel/smpboot.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* State of each CPU. */ -static DEFINE_PER_CPU(int, cpu_state) = { 0 }; - -/* The messaging code jumps to this pointer during boot-up */ -unsigned long start_cpu_function_addr; - -/* Called very early during startup to mark boot cpu as online */ -void __init smp_prepare_boot_cpu(void) -{ - int cpu = smp_processor_id(); - set_cpu_online(cpu, 1); - set_cpu_present(cpu, 1); - __this_cpu_write(cpu_state, CPU_ONLINE); - - init_messaging(); -} - -static void start_secondary(void); - -/* - * Called at the top of init() to launch all the other CPUs. - * They run free to complete their initialization and then wait - * until they get an IPI from the boot cpu to come online. - */ -void __init smp_prepare_cpus(unsigned int max_cpus) -{ - long rc; - int cpu, cpu_count; - int boot_cpu = smp_processor_id(); - - current_thread_info()->cpu = boot_cpu; - - /* - * Pin this task to the boot CPU while we bring up the others, - * just to make sure we don't uselessly migrate as they come up. - */ - rc = sched_setaffinity(current->pid, cpumask_of(boot_cpu)); - if (rc != 0) - pr_err("Couldn't set init affinity to boot cpu (%ld)\n", rc); - - /* Print information about disabled and dataplane cpus. */ - print_disabled_cpus(); - - /* - * Tell the messaging subsystem how to respond to the - * startup message. We use a level of indirection to avoid - * confusing the linker with the fact that the messaging - * subsystem is calling __init code. - */ - start_cpu_function_addr = (unsigned long) &online_secondary; - - /* Set up thread context for all new processors. */ - cpu_count = 1; - for (cpu = 0; cpu < NR_CPUS; ++cpu) { - struct task_struct *idle; - - if (cpu == boot_cpu) - continue; - - if (!cpu_possible(cpu)) { - /* - * Make this processor do nothing on boot. - * Note that we don't give the boot_pc function - * a stack, so it has to be assembly code. - */ - per_cpu(boot_sp, cpu) = 0; - per_cpu(boot_pc, cpu) = (unsigned long) smp_nap; - continue; - } - - /* Create a new idle thread to run start_secondary() */ - idle = fork_idle(cpu); - if (IS_ERR(idle)) - panic("failed fork for CPU %d", cpu); - idle->thread.pc = (unsigned long) start_secondary; - - /* Make this thread the boot thread for this processor */ - per_cpu(boot_sp, cpu) = task_ksp0(idle); - per_cpu(boot_pc, cpu) = idle->thread.pc; - - ++cpu_count; - } - BUG_ON(cpu_count > (max_cpus ? max_cpus : 1)); - - /* Fire up the other tiles, if any */ - init_cpu_present(cpu_possible_mask); - if (cpumask_weight(cpu_present_mask) > 1) { - mb(); /* make sure all data is visible to new processors */ - hv_start_all_tiles(); - } -} - -static __initdata struct cpumask init_affinity; - -static __init int reset_init_affinity(void) -{ - long rc = sched_setaffinity(current->pid, &init_affinity); - if (rc != 0) - pr_warn("couldn't reset init affinity (%ld)\n", rc); - return 0; -} -late_initcall(reset_init_affinity); - -static struct cpumask cpu_started; - -/* - * Activate a secondary processor. Very minimal; don't add anything - * to this path without knowing what you're doing, since SMP booting - * is pretty fragile. - */ -static void start_secondary(void) -{ - int cpuid; - - preempt_disable(); - - cpuid = smp_processor_id(); - - /* Set our thread pointer appropriately. */ - set_my_cpu_offset(__per_cpu_offset[cpuid]); - - /* - * In large machines even this will slow us down, since we - * will be contending for for the printk spinlock. - */ - /* printk(KERN_DEBUG "Initializing CPU#%d\n", cpuid); */ - - /* Initialize the current asid for our first page table. */ - __this_cpu_write(current_asid, min_asid); - - /* Set up this thread as another owner of the init_mm */ - mmgrab(&init_mm); - current->active_mm = &init_mm; - if (current->mm) - BUG(); - enter_lazy_tlb(&init_mm, current); - - /* Allow hypervisor messages to be received */ - init_messaging(); - local_irq_enable(); - - /* Indicate that we're ready to come up. */ - /* Must not do this before we're ready to receive messages */ - if (cpumask_test_and_set_cpu(cpuid, &cpu_started)) { - pr_warn("CPU#%d already started!\n", cpuid); - for (;;) - local_irq_enable(); - } - - smp_nap(); -} - -/* - * Bring a secondary processor online. - */ -void online_secondary(void) -{ - /* - * low-memory mappings have been cleared, flush them from - * the local TLBs too. - */ - local_flush_tlb(); - - BUG_ON(in_interrupt()); - - /* This must be done before setting cpu_online_mask */ - wmb(); - - notify_cpu_starting(smp_processor_id()); - - set_cpu_online(smp_processor_id(), 1); - __this_cpu_write(cpu_state, CPU_ONLINE); - - /* Set up tile-specific state for this cpu. */ - setup_cpu(0); - - /* Set up tile-timer clock-event device on this cpu */ - setup_tile_timer(); - - cpu_startup_entry(CPUHP_AP_ONLINE_IDLE); -} - -int __cpu_up(unsigned int cpu, struct task_struct *tidle) -{ - /* Wait 5s total for all CPUs for them to come online */ - static int timeout; - for (; !cpumask_test_cpu(cpu, &cpu_started); timeout++) { - if (timeout >= 50000) { - pr_info("skipping unresponsive cpu%d\n", cpu); - local_irq_enable(); - return -EIO; - } - udelay(100); - } - - local_irq_enable(); - per_cpu(cpu_state, cpu) = CPU_UP_PREPARE; - - /* Unleash the CPU! */ - send_IPI_single(cpu, MSG_TAG_START_CPU); - while (!cpumask_test_cpu(cpu, cpu_online_mask)) - cpu_relax(); - return 0; -} - -static void panic_start_cpu(void) -{ - panic("Received a MSG_START_CPU IPI after boot finished."); -} - -void __init smp_cpus_done(unsigned int max_cpus) -{ - int cpu, next, rc; - - /* Reset the response to a (now illegal) MSG_START_CPU IPI. */ - start_cpu_function_addr = (unsigned long) &panic_start_cpu; - - cpumask_copy(&init_affinity, cpu_online_mask); - - /* - * Pin ourselves to a single cpu in the initial affinity set - * so that kernel mappings for the rootfs are not in the dataplane, - * if set, and to avoid unnecessary migrating during bringup. - * Use the last cpu just in case the whole chip has been - * isolated from the scheduler, to keep init away from likely - * more useful user code. This also ensures that work scheduled - * via schedule_delayed_work() in the init routines will land - * on this cpu. - */ - for (cpu = cpumask_first(&init_affinity); - (next = cpumask_next(cpu, &init_affinity)) < nr_cpu_ids; - cpu = next) - ; - rc = sched_setaffinity(current->pid, cpumask_of(cpu)); - if (rc != 0) - pr_err("Couldn't set init affinity to cpu %d (%d)\n", cpu, rc); -} diff --git a/arch/tile/kernel/stack.c b/arch/tile/kernel/stack.c deleted file mode 100644 index 94ecbc6676e5..000000000000 --- a/arch/tile/kernel/stack.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define KBT_ONGOING 0 /* Backtrace still ongoing */ -#define KBT_DONE 1 /* Backtrace cleanly completed */ -#define KBT_RUNNING 2 /* Can't run backtrace on a running task */ -#define KBT_LOOP 3 /* Backtrace entered a loop */ - -/* Is address on the specified kernel stack? */ -static int in_kernel_stack(struct KBacktraceIterator *kbt, unsigned long sp) -{ - ulong kstack_base = (ulong) kbt->task->stack; - if (kstack_base == 0) /* corrupt task pointer; just follow stack... */ - return sp >= PAGE_OFFSET && sp < (unsigned long)high_memory; - return sp >= kstack_base && sp < kstack_base + THREAD_SIZE; -} - -/* Callback for backtracer; basically a glorified memcpy */ -static bool read_memory_func(void *result, unsigned long address, - unsigned int size, void *vkbt) -{ - int retval; - struct KBacktraceIterator *kbt = (struct KBacktraceIterator *)vkbt; - - if (address == 0) - return 0; - if (__kernel_text_address(address)) { - /* OK to read kernel code. */ - } else if (address >= PAGE_OFFSET) { - /* We only tolerate kernel-space reads of this task's stack */ - if (!in_kernel_stack(kbt, address)) - return 0; - } else if (!kbt->is_current) { - return 0; /* can't read from other user address spaces */ - } - pagefault_disable(); - retval = __copy_from_user_inatomic(result, - (void __user __force *)address, - size); - pagefault_enable(); - return (retval == 0); -} - -/* Return a pt_regs pointer for a valid fault handler frame */ -static struct pt_regs *valid_fault_handler(struct KBacktraceIterator* kbt) -{ - char fault[64]; - unsigned long sp = kbt->it.sp; - struct pt_regs *p; - - if (sp % sizeof(long) != 0) - return NULL; - if (!in_kernel_stack(kbt, sp)) - return NULL; - if (!in_kernel_stack(kbt, sp + C_ABI_SAVE_AREA_SIZE + PTREGS_SIZE-1)) - return NULL; - p = (struct pt_regs *)(sp + C_ABI_SAVE_AREA_SIZE); - if (kbt->verbose) { /* else we aren't going to use it */ - if (p->faultnum == INT_SWINT_1 || - p->faultnum == INT_SWINT_1_SIGRETURN) - snprintf(fault, sizeof(fault), - "syscall %ld", p->regs[TREG_SYSCALL_NR]); - else - snprintf(fault, sizeof(fault), - "interrupt %ld", p->faultnum); - } - if (EX1_PL(p->ex1) == KERNEL_PL && - __kernel_text_address(p->pc) && - in_kernel_stack(kbt, p->sp) && - p->sp >= sp) { - if (kbt->verbose) - pr_err(" <%s while in kernel mode>\n", fault); - } else if (user_mode(p) && - p->sp < PAGE_OFFSET && p->sp != 0) { - if (kbt->verbose) - pr_err(" <%s while in user mode>\n", fault); - } else { - if (kbt->verbose && (p->pc != 0 || p->sp != 0 || p->ex1 != 0)) - pr_err(" (odd fault: pc %#lx, sp %#lx, ex1 %#lx?)\n", - p->pc, p->sp, p->ex1); - return NULL; - } - if (kbt->profile && ((1ULL << p->faultnum) & QUEUED_INTERRUPTS) != 0) - return NULL; - return p; -} - -/* Is the iterator pointing to a sigreturn trampoline? */ -static int is_sigreturn(struct KBacktraceIterator *kbt) -{ - return kbt->task->mm && - (kbt->it.pc == ((ulong)kbt->task->mm->context.vdso_base + - (ulong)&__vdso_rt_sigreturn)); -} - -/* Return a pt_regs pointer for a valid signal handler frame */ -static struct pt_regs *valid_sigframe(struct KBacktraceIterator* kbt, - struct rt_sigframe* kframe) -{ - BacktraceIterator *b = &kbt->it; - - if (is_sigreturn(kbt) && b->sp < PAGE_OFFSET && - b->sp % sizeof(long) == 0) { - int retval; - pagefault_disable(); - retval = __copy_from_user_inatomic( - kframe, (void __user __force *)b->sp, - sizeof(*kframe)); - pagefault_enable(); - if (retval != 0 || - (unsigned int)(kframe->info.si_signo) >= _NSIG) - return NULL; - if (kbt->verbose) { - pr_err(" \n", - kframe->info.si_signo); - } - return (struct pt_regs *)&kframe->uc.uc_mcontext; - } - return NULL; -} - -static int KBacktraceIterator_restart(struct KBacktraceIterator *kbt) -{ - struct pt_regs *p; - struct rt_sigframe kframe; - - p = valid_fault_handler(kbt); - if (p == NULL) - p = valid_sigframe(kbt, &kframe); - if (p == NULL) - return 0; - backtrace_init(&kbt->it, read_memory_func, kbt, - p->pc, p->lr, p->sp, p->regs[52]); - kbt->new_context = 1; - return 1; -} - -/* Find a frame that isn't a sigreturn, if there is one. */ -static int KBacktraceIterator_next_item_inclusive( - struct KBacktraceIterator *kbt) -{ - for (;;) { - do { - if (!is_sigreturn(kbt)) - return KBT_ONGOING; - } while (backtrace_next(&kbt->it)); - - if (!KBacktraceIterator_restart(kbt)) - return KBT_DONE; - } -} - -/* - * If the current sp is on a page different than what we recorded - * as the top-of-kernel-stack last time we context switched, we have - * probably blown the stack, and nothing is going to work out well. - * If we can at least get out a warning, that may help the debug, - * though we probably won't be able to backtrace into the code that - * actually did the recursive damage. - */ -static void validate_stack(struct pt_regs *regs) -{ - int cpu = raw_smp_processor_id(); - unsigned long ksp0 = get_current_ksp0(); - unsigned long ksp0_base = ksp0 & -THREAD_SIZE; - unsigned long sp = stack_pointer; - - if (EX1_PL(regs->ex1) == KERNEL_PL && regs->sp >= ksp0) { - pr_err("WARNING: cpu %d: kernel stack %#lx..%#lx underrun!\n" - " sp %#lx (%#lx in caller), caller pc %#lx, lr %#lx\n", - cpu, ksp0_base, ksp0, sp, regs->sp, regs->pc, regs->lr); - } - - else if (sp < ksp0_base + sizeof(struct thread_info)) { - pr_err("WARNING: cpu %d: kernel stack %#lx..%#lx overrun!\n" - " sp %#lx (%#lx in caller), caller pc %#lx, lr %#lx\n", - cpu, ksp0_base, ksp0, sp, regs->sp, regs->pc, regs->lr); - } -} - -void KBacktraceIterator_init(struct KBacktraceIterator *kbt, - struct task_struct *t, struct pt_regs *regs) -{ - unsigned long pc, lr, sp, r52; - int is_current; - - /* - * Set up callback information. We grab the kernel stack base - * so we will allow reads of that address range. - */ - is_current = (t == NULL || t == current); - kbt->is_current = is_current; - if (is_current) - t = validate_current(); - kbt->task = t; - kbt->verbose = 0; /* override in caller if desired */ - kbt->profile = 0; /* override in caller if desired */ - kbt->end = KBT_ONGOING; - kbt->new_context = 1; - if (is_current) - validate_stack(regs); - - if (regs == NULL) { - if (is_current || t->state == TASK_RUNNING) { - /* Can't do this; we need registers */ - kbt->end = KBT_RUNNING; - return; - } - pc = get_switch_to_pc(); - lr = t->thread.pc; - sp = t->thread.ksp; - r52 = 0; - } else { - pc = regs->pc; - lr = regs->lr; - sp = regs->sp; - r52 = regs->regs[52]; - } - - backtrace_init(&kbt->it, read_memory_func, kbt, pc, lr, sp, r52); - kbt->end = KBacktraceIterator_next_item_inclusive(kbt); -} -EXPORT_SYMBOL(KBacktraceIterator_init); - -int KBacktraceIterator_end(struct KBacktraceIterator *kbt) -{ - return kbt->end != KBT_ONGOING; -} -EXPORT_SYMBOL(KBacktraceIterator_end); - -void KBacktraceIterator_next(struct KBacktraceIterator *kbt) -{ - unsigned long old_pc = kbt->it.pc, old_sp = kbt->it.sp; - kbt->new_context = 0; - if (!backtrace_next(&kbt->it) && !KBacktraceIterator_restart(kbt)) { - kbt->end = KBT_DONE; - return; - } - kbt->end = KBacktraceIterator_next_item_inclusive(kbt); - if (old_pc == kbt->it.pc && old_sp == kbt->it.sp) { - /* Trapped in a loop; give up. */ - kbt->end = KBT_LOOP; - } -} -EXPORT_SYMBOL(KBacktraceIterator_next); - -static void describe_addr(struct KBacktraceIterator *kbt, - unsigned long address, - int have_mmap_sem, char *buf, size_t bufsize) -{ - struct vm_area_struct *vma; - size_t namelen, remaining; - unsigned long size, offset, adjust; - char *p, *modname; - const char *name; - int rc; - - /* - * Look one byte back for every caller frame (i.e. those that - * aren't a new context) so we look up symbol data for the - * call itself, not the following instruction, which may be on - * a different line (or in a different function). - */ - adjust = !kbt->new_context; - address -= adjust; - - if (address >= PAGE_OFFSET) { - /* Handle kernel symbols. */ - BUG_ON(bufsize < KSYM_NAME_LEN); - name = kallsyms_lookup(address, &size, &offset, - &modname, buf); - if (name == NULL) { - buf[0] = '\0'; - return; - } - namelen = strlen(buf); - remaining = (bufsize - 1) - namelen; - p = buf + namelen; - rc = snprintf(p, remaining, "+%#lx/%#lx ", - offset + adjust, size); - if (modname && rc < remaining) - snprintf(p + rc, remaining - rc, "[%s] ", modname); - buf[bufsize-1] = '\0'; - return; - } - - /* If we don't have the mmap_sem, we can't show any more info. */ - buf[0] = '\0'; - if (!have_mmap_sem) - return; - - /* Find vma info. */ - vma = find_vma(kbt->task->mm, address); - if (vma == NULL || address < vma->vm_start) { - snprintf(buf, bufsize, "[unmapped address] "); - return; - } - - if (vma->vm_file) { - p = file_path(vma->vm_file, buf, bufsize); - if (IS_ERR(p)) - p = "?"; - name = kbasename(p); - } else { - name = "anon"; - } - - /* Generate a string description of the vma info. */ - namelen = strlen(name); - remaining = (bufsize - 1) - namelen; - memmove(buf, name, namelen); - snprintf(buf + namelen, remaining, "[%lx+%lx] ", - vma->vm_start, vma->vm_end - vma->vm_start); -} - -/* - * Avoid possible crash recursion during backtrace. If it happens, it - * makes it easy to lose the actual root cause of the failure, so we - * put a simple guard on all the backtrace loops. - */ -static bool start_backtrace(void) -{ - if (current_thread_info()->in_backtrace) { - pr_err("Backtrace requested while in backtrace!\n"); - return false; - } - current_thread_info()->in_backtrace = true; - return true; -} - -static void end_backtrace(void) -{ - current_thread_info()->in_backtrace = false; -} - -/* - * This method wraps the backtracer's more generic support. - * It is only invoked from the architecture-specific code; show_stack() - * and dump_stack() are architecture-independent entry points. - */ -void tile_show_stack(struct KBacktraceIterator *kbt) -{ - int i; - int have_mmap_sem = 0; - - if (!start_backtrace()) - return; - kbt->verbose = 1; - i = 0; - for (; !KBacktraceIterator_end(kbt); KBacktraceIterator_next(kbt)) { - char namebuf[KSYM_NAME_LEN+100]; - unsigned long address = kbt->it.pc; - - /* - * Try to acquire the mmap_sem as we pass into userspace. - * If we're in an interrupt context, don't even try, since - * it's not safe to call e.g. d_path() from an interrupt, - * since it uses spin locks without disabling interrupts. - * Note we test "kbt->task == current", not "kbt->is_current", - * since we're checking that "current" will work in d_path(). - */ - if (kbt->task == current && address < PAGE_OFFSET && - !have_mmap_sem && kbt->task->mm && !in_interrupt()) { - have_mmap_sem = - down_read_trylock(&kbt->task->mm->mmap_sem); - } - - describe_addr(kbt, address, have_mmap_sem, - namebuf, sizeof(namebuf)); - - pr_err(" frame %d: 0x%lx %s(sp 0x%lx)\n", - i++, address, namebuf, (unsigned long)(kbt->it.sp)); - - if (i >= 100) { - pr_err("Stack dump truncated (%d frames)\n", i); - break; - } - } - if (kbt->end == KBT_LOOP) - pr_err("Stack dump stopped; next frame identical to this one\n"); - if (have_mmap_sem) - up_read(&kbt->task->mm->mmap_sem); - end_backtrace(); -} -EXPORT_SYMBOL(tile_show_stack); - -static struct pt_regs *regs_to_pt_regs(struct pt_regs *regs, - ulong pc, ulong lr, ulong sp, ulong r52) -{ - memset(regs, 0, sizeof(struct pt_regs)); - regs->pc = pc; - regs->lr = lr; - regs->sp = sp; - regs->regs[52] = r52; - return regs; -} - -/* Deprecated function currently only used by kernel_double_fault(). */ -void _dump_stack(int dummy, ulong pc, ulong lr, ulong sp, ulong r52) -{ - struct KBacktraceIterator kbt; - struct pt_regs regs; - - regs_to_pt_regs(®s, pc, lr, sp, r52); - KBacktraceIterator_init(&kbt, NULL, ®s); - tile_show_stack(&kbt); -} - -/* This is called from KBacktraceIterator_init_current() */ -void _KBacktraceIterator_init_current(struct KBacktraceIterator *kbt, ulong pc, - ulong lr, ulong sp, ulong r52) -{ - struct pt_regs regs; - KBacktraceIterator_init(kbt, NULL, - regs_to_pt_regs(®s, pc, lr, sp, r52)); -} - -/* - * Called from sched_show_task() with task != NULL, or dump_stack() - * with task == NULL. The esp argument is always NULL. - */ -void show_stack(struct task_struct *task, unsigned long *esp) -{ - struct KBacktraceIterator kbt; - if (task == NULL || task == current) { - KBacktraceIterator_init_current(&kbt); - KBacktraceIterator_next(&kbt); /* don't show first frame */ - } else { - KBacktraceIterator_init(&kbt, task, NULL); - } - tile_show_stack(&kbt); -} - -#ifdef CONFIG_STACKTRACE - -/* Support generic Linux stack API too */ - -static void save_stack_trace_common(struct task_struct *task, - struct pt_regs *regs, - bool user, - struct stack_trace *trace) -{ - struct KBacktraceIterator kbt; - int skip = trace->skip; - int i = 0; - - if (!start_backtrace()) - goto done; - if (regs != NULL) { - KBacktraceIterator_init(&kbt, NULL, regs); - } else if (task == NULL || task == current) { - KBacktraceIterator_init_current(&kbt); - skip++; /* don't show KBacktraceIterator_init_current */ - } else { - KBacktraceIterator_init(&kbt, task, NULL); - } - for (; !KBacktraceIterator_end(&kbt); KBacktraceIterator_next(&kbt)) { - if (skip) { - --skip; - continue; - } - if (i >= trace->max_entries || - (!user && kbt.it.pc < PAGE_OFFSET)) - break; - trace->entries[i++] = kbt.it.pc; - } - end_backtrace(); -done: - if (i < trace->max_entries) - trace->entries[i++] = ULONG_MAX; - trace->nr_entries = i; -} - -void save_stack_trace_tsk(struct task_struct *task, struct stack_trace *trace) -{ - save_stack_trace_common(task, NULL, false, trace); -} -EXPORT_SYMBOL(save_stack_trace_tsk); - -void save_stack_trace(struct stack_trace *trace) -{ - save_stack_trace_common(NULL, NULL, false, trace); -} -EXPORT_SYMBOL_GPL(save_stack_trace); - -void save_stack_trace_regs(struct pt_regs *regs, struct stack_trace *trace) -{ - save_stack_trace_common(NULL, regs, false, trace); -} - -void save_stack_trace_user(struct stack_trace *trace) -{ - /* Trace user stack if we are not a kernel thread. */ - if (current->mm) - save_stack_trace_common(NULL, task_pt_regs(current), - true, trace); - else if (trace->nr_entries < trace->max_entries) - trace->entries[trace->nr_entries++] = ULONG_MAX; -} -#endif - -/* In entry.S */ -EXPORT_SYMBOL(KBacktraceIterator_init_current); diff --git a/arch/tile/kernel/sys.c b/arch/tile/kernel/sys.c deleted file mode 100644 index c7418dcbbb08..000000000000 --- a/arch/tile/kernel/sys.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * This file contains various random system calls that - * have a non-standard calling sequence on the Linux/TILE - * platform. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, len, - unsigned long, flags) -{ - /* DCACHE is not particularly effective if not bound to one cpu. */ - if (flags & DCACHE) - homecache_evict(cpumask_of(raw_smp_processor_id())); - - if (flags & ICACHE) - flush_remote(0, HV_FLUSH_EVICT_L1I, mm_cpumask(current->mm), - 0, 0, 0, NULL, NULL, 0); - return 0; -} - -/* - * Syscalls that pass 64-bit values on 32-bit systems normally - * pass them as (low,high) word packed into the immediately adjacent - * registers. If the low word naturally falls on an even register, - * our ABI makes it work correctly; if not, we adjust it here. - * Handling it here means we don't have to fix uclibc AND glibc AND - * any other standard libcs we want to support. - */ - -#if !defined(__tilegx__) || defined(CONFIG_COMPAT) - -#ifdef __BIG_ENDIAN -#define SYSCALL_PAIR(name) u32 name ## _hi, u32 name ## _lo -#else -#define SYSCALL_PAIR(name) u32 name ## _lo, u32 name ## _hi -#endif - -ssize_t sys32_readahead(int fd, SYSCALL_PAIR(offset), u32 count) -{ - return sys_readahead(fd, ((loff_t)offset_hi << 32) | offset_lo, count); -} - -int sys32_fadvise64_64(int fd, SYSCALL_PAIR(offset), - SYSCALL_PAIR(len), int advice) -{ - return sys_fadvise64_64(fd, ((loff_t)offset_hi << 32) | offset_lo, - ((loff_t)len_hi << 32) | len_lo, advice); -} - -#endif /* 32-bit syscall wrappers */ - -/* Note: used by the compat code even in 64-bit Linux. */ -SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, - unsigned long, prot, unsigned long, flags, - unsigned long, fd, unsigned long, off_4k) -{ -#define PAGE_ADJUST (PAGE_SHIFT - 12) - if (off_4k & ((1 << PAGE_ADJUST) - 1)) - return -EINVAL; - return sys_mmap_pgoff(addr, len, prot, flags, fd, - off_4k >> PAGE_ADJUST); -} - -#ifdef __tilegx__ -SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, - unsigned long, prot, unsigned long, flags, - unsigned long, fd, off_t, offset) -{ - if (offset & ((1 << PAGE_SHIFT) - 1)) - return -EINVAL; - return sys_mmap_pgoff(addr, len, prot, flags, fd, - offset >> PAGE_SHIFT); -} -#endif - - -/* Provide the actual syscall number to call mapping. */ -#undef __SYSCALL -#define __SYSCALL(nr, call) [nr] = (call), - -#ifndef __tilegx__ -/* See comments at the top of the file. */ -#define sys_fadvise64_64 sys32_fadvise64_64 -#define sys_readahead sys32_readahead -#endif - -/* Call the assembly trampolines where necessary. */ -#undef sys_rt_sigreturn -#define sys_rt_sigreturn _sys_rt_sigreturn -#define sys_clone _sys_clone - -/* - * Note that we can't include here since the header - * guard will defeat us; checks for __SYSCALL as well. - */ -void *sys_call_table[__NR_syscalls] = { - [0 ... __NR_syscalls-1] = sys_ni_syscall, -#include -}; diff --git a/arch/tile/kernel/sysfs.c b/arch/tile/kernel/sysfs.c deleted file mode 100644 index b09456a3d77a..000000000000 --- a/arch/tile/kernel/sysfs.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * /sys entry support. - */ - -#include -#include -#include -#include -#include -#include - -/* Return a string queried from the hypervisor, truncated to page size. */ -static ssize_t get_hv_confstr(char *page, int query) -{ - ssize_t n = hv_confstr(query, (unsigned long)page, PAGE_SIZE - 1); - n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1) - 1; - if (n) - page[n++] = '\n'; - page[n] = '\0'; - return n; -} - -static ssize_t chip_width_show(struct device *dev, - struct device_attribute *attr, - char *page) -{ - return sprintf(page, "%u\n", smp_width); -} -static DEVICE_ATTR_RO(chip_width); - -static ssize_t chip_height_show(struct device *dev, - struct device_attribute *attr, - char *page) -{ - return sprintf(page, "%u\n", smp_height); -} -static DEVICE_ATTR_RO(chip_height); - -static ssize_t chip_serial_show(struct device *dev, - struct device_attribute *attr, - char *page) -{ - return get_hv_confstr(page, HV_CONFSTR_CHIP_SERIAL_NUM); -} -static DEVICE_ATTR_RO(chip_serial); - -static ssize_t chip_revision_show(struct device *dev, - struct device_attribute *attr, - char *page) -{ - return get_hv_confstr(page, HV_CONFSTR_CHIP_REV); -} -static DEVICE_ATTR_RO(chip_revision); - - -static ssize_t type_show(struct device *dev, - struct device_attribute *attr, - char *page) -{ - return sprintf(page, "tilera\n"); -} -static DEVICE_ATTR_RO(type); - -#define HV_CONF_ATTR(name, conf) \ - static ssize_t name ## _show(struct device *dev, \ - struct device_attribute *attr, \ - char *page) \ - { \ - return get_hv_confstr(page, conf); \ - } \ - static DEVICE_ATTR(name, 0444, name ## _show, NULL); - -HV_CONF_ATTR(version, HV_CONFSTR_HV_SW_VER) -HV_CONF_ATTR(config_version, HV_CONFSTR_HV_CONFIG_VER) - -HV_CONF_ATTR(board_part, HV_CONFSTR_BOARD_PART_NUM) -HV_CONF_ATTR(board_serial, HV_CONFSTR_BOARD_SERIAL_NUM) -HV_CONF_ATTR(board_revision, HV_CONFSTR_BOARD_REV) -HV_CONF_ATTR(board_description, HV_CONFSTR_BOARD_DESC) -HV_CONF_ATTR(mezz_part, HV_CONFSTR_MEZZ_PART_NUM) -HV_CONF_ATTR(mezz_serial, HV_CONFSTR_MEZZ_SERIAL_NUM) -HV_CONF_ATTR(mezz_revision, HV_CONFSTR_MEZZ_REV) -HV_CONF_ATTR(mezz_description, HV_CONFSTR_MEZZ_DESC) -HV_CONF_ATTR(cpumod_part, HV_CONFSTR_CPUMOD_PART_NUM) -HV_CONF_ATTR(cpumod_serial, HV_CONFSTR_CPUMOD_SERIAL_NUM) -HV_CONF_ATTR(cpumod_revision, HV_CONFSTR_CPUMOD_REV) -HV_CONF_ATTR(cpumod_description,HV_CONFSTR_CPUMOD_DESC) -HV_CONF_ATTR(switch_control, HV_CONFSTR_SWITCH_CONTROL) - -static struct attribute *board_attrs[] = { - &dev_attr_board_part.attr, - &dev_attr_board_serial.attr, - &dev_attr_board_revision.attr, - &dev_attr_board_description.attr, - &dev_attr_mezz_part.attr, - &dev_attr_mezz_serial.attr, - &dev_attr_mezz_revision.attr, - &dev_attr_mezz_description.attr, - &dev_attr_cpumod_part.attr, - &dev_attr_cpumod_serial.attr, - &dev_attr_cpumod_revision.attr, - &dev_attr_cpumod_description.attr, - &dev_attr_switch_control.attr, - NULL -}; - -static struct attribute_group board_attr_group = { - .name = "board", - .attrs = board_attrs, -}; - - -static struct bin_attribute hvconfig_bin; - -static ssize_t -hvconfig_bin_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - static size_t size; - - /* Lazily learn the true size (minus the trailing NUL). */ - if (size == 0) - size = hv_confstr(HV_CONFSTR_HV_CONFIG, 0, 0) - 1; - - /* Check and adjust input parameters. */ - if (off > size) - return -EINVAL; - if (count > size - off) - count = size - off; - - if (count) { - /* Get a copy of the hvc and copy out the relevant portion. */ - char *hvc; - - size = off + count; - hvc = kmalloc(size, GFP_KERNEL); - if (hvc == NULL) - return -ENOMEM; - hv_confstr(HV_CONFSTR_HV_CONFIG, (unsigned long)hvc, size); - memcpy(buf, hvc + off, count); - kfree(hvc); - } - - return count; -} - -static ssize_t hv_stats_show(struct device *dev, - struct device_attribute *attr, - char *page) -{ - int cpu = dev->id; - long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu)); - - ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, - (unsigned long)page, PAGE_SIZE - 1, - lotar, 0); - n = n < 0 ? 0 : min(n, (ssize_t)PAGE_SIZE - 1); - page[n] = '\0'; - return n; -} - -static ssize_t hv_stats_store(struct device *dev, - struct device_attribute *attr, - const char *page, - size_t count) -{ - int cpu = dev->id; - long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu)); - - ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, 0, 0, lotar, 1); - return n < 0 ? n : count; -} - -static DEVICE_ATTR_RW(hv_stats); - -static int hv_stats_device_add(struct device *dev, struct subsys_interface *sif) -{ - int err, cpu = dev->id; - - if (!cpu_online(cpu)) - return 0; - - err = sysfs_create_file(&dev->kobj, &dev_attr_hv_stats.attr); - - return err; -} - -static void hv_stats_device_remove(struct device *dev, - struct subsys_interface *sif) -{ - int cpu = dev->id; - - if (cpu_online(cpu)) - sysfs_remove_file(&dev->kobj, &dev_attr_hv_stats.attr); -} - - -static struct subsys_interface hv_stats_interface = { - .name = "hv_stats", - .subsys = &cpu_subsys, - .add_dev = hv_stats_device_add, - .remove_dev = hv_stats_device_remove, -}; - -static int __init create_sysfs_entries(void) -{ - int err = 0; - -#define create_cpu_attr(name) \ - if (!err) \ - err = device_create_file(cpu_subsys.dev_root, &dev_attr_##name); - create_cpu_attr(chip_width); - create_cpu_attr(chip_height); - create_cpu_attr(chip_serial); - create_cpu_attr(chip_revision); - -#define create_hv_attr(name) \ - if (!err) \ - err = sysfs_create_file(hypervisor_kobj, &dev_attr_##name.attr); - create_hv_attr(type); - create_hv_attr(version); - create_hv_attr(config_version); - - if (!err) - err = sysfs_create_group(hypervisor_kobj, &board_attr_group); - - if (!err) { - sysfs_bin_attr_init(&hvconfig_bin); - hvconfig_bin.attr.name = "hvconfig"; - hvconfig_bin.attr.mode = S_IRUGO; - hvconfig_bin.read = hvconfig_bin_read; - hvconfig_bin.size = PAGE_SIZE; - err = sysfs_create_bin_file(hypervisor_kobj, &hvconfig_bin); - } - - if (!err) { - /* - * Don't bother adding the hv_stats files on each CPU if - * our hypervisor doesn't supply statistics. - */ - int cpu = raw_smp_processor_id(); - long lotar = HV_XY_TO_LOTAR(cpu_x(cpu), cpu_y(cpu)); - char dummy; - ssize_t n = hv_confstr(HV_CONFSTR_HV_STATS, - (unsigned long) &dummy, 1, - lotar, 0); - if (n >= 0) - err = subsys_interface_register(&hv_stats_interface); - } - - return err; -} -subsys_initcall(create_sysfs_entries); diff --git a/arch/tile/kernel/tile-desc_32.c b/arch/tile/kernel/tile-desc_32.c deleted file mode 100644 index dd7bd1d8563c..000000000000 --- a/arch/tile/kernel/tile-desc_32.c +++ /dev/null @@ -1,2605 +0,0 @@ -/* TILEPro opcode information. - * - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * - * - * - * - */ - -/* This define is BFD_RELOC_##x for real bfd, or -1 for everyone else. */ -#define BFD_RELOC(x) -1 - -/* Special registers. */ -#define TREG_LR 55 -#define TREG_SN 56 -#define TREG_ZERO 63 - -#include -#include - -const struct tilepro_opcode tilepro_opcodes[395] = -{ - { "bpt", TILEPRO_OPC_BPT, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "info", TILEPRO_OPC_INFO, 0xf, 1, TREG_ZERO, 1, - { { 0 }, { 1 }, { 2 }, { 3 }, { 0, } }, - }, - { "infol", TILEPRO_OPC_INFOL, 0x3, 1, TREG_ZERO, 1, - { { 4 }, { 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "j", TILEPRO_OPC_J, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 6 }, { 0, }, { 0, }, { 0, } }, - }, - { "jal", TILEPRO_OPC_JAL, 0x2, 1, TREG_LR, 1, - { { 0, }, { 6 }, { 0, }, { 0, }, { 0, } }, - }, - { "move", TILEPRO_OPC_MOVE, 0xf, 2, TREG_ZERO, 1, - { { 7, 8 }, { 9, 10 }, { 11, 12 }, { 13, 14 }, { 0, } }, - }, - { "move.sn", TILEPRO_OPC_MOVE_SN, 0x3, 2, TREG_SN, 1, - { { 7, 8 }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "movei", TILEPRO_OPC_MOVEI, 0xf, 2, TREG_ZERO, 1, - { { 7, 0 }, { 9, 1 }, { 11, 2 }, { 13, 3 }, { 0, } }, - }, - { "movei.sn", TILEPRO_OPC_MOVEI_SN, 0x3, 2, TREG_SN, 1, - { { 7, 0 }, { 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "moveli", TILEPRO_OPC_MOVELI, 0x3, 2, TREG_ZERO, 1, - { { 7, 4 }, { 9, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "moveli.sn", TILEPRO_OPC_MOVELI_SN, 0x3, 2, TREG_SN, 1, - { { 7, 4 }, { 9, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "movelis", TILEPRO_OPC_MOVELIS, 0x3, 2, TREG_SN, 1, - { { 7, 4 }, { 9, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "prefetch", TILEPRO_OPC_PREFETCH, 0x12, 1, TREG_ZERO, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 15 } }, - }, - { "raise", TILEPRO_OPC_RAISE, 0x2, 0, TREG_ZERO, 1, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "add", TILEPRO_OPC_ADD, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "add.sn", TILEPRO_OPC_ADD_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "addb", TILEPRO_OPC_ADDB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "addb.sn", TILEPRO_OPC_ADDB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "addbs_u", TILEPRO_OPC_ADDBS_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "addbs_u.sn", TILEPRO_OPC_ADDBS_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "addh", TILEPRO_OPC_ADDH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "addh.sn", TILEPRO_OPC_ADDH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "addhs", TILEPRO_OPC_ADDHS, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "addhs.sn", TILEPRO_OPC_ADDHS_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "addi", TILEPRO_OPC_ADDI, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, - }, - { "addi.sn", TILEPRO_OPC_ADDI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "addib", TILEPRO_OPC_ADDIB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "addib.sn", TILEPRO_OPC_ADDIB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "addih", TILEPRO_OPC_ADDIH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "addih.sn", TILEPRO_OPC_ADDIH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "addli", TILEPRO_OPC_ADDLI, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 4 }, { 9, 10, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "addli.sn", TILEPRO_OPC_ADDLI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 4 }, { 9, 10, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "addlis", TILEPRO_OPC_ADDLIS, 0x3, 3, TREG_SN, 1, - { { 7, 8, 4 }, { 9, 10, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "adds", TILEPRO_OPC_ADDS, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "adds.sn", TILEPRO_OPC_ADDS_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "adiffb_u", TILEPRO_OPC_ADIFFB_U, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "adiffb_u.sn", TILEPRO_OPC_ADIFFB_U_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "adiffh", TILEPRO_OPC_ADIFFH, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "adiffh.sn", TILEPRO_OPC_ADIFFH_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "and", TILEPRO_OPC_AND, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "and.sn", TILEPRO_OPC_AND_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "andi", TILEPRO_OPC_ANDI, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, - }, - { "andi.sn", TILEPRO_OPC_ANDI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "auli", TILEPRO_OPC_AULI, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 4 }, { 9, 10, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "avgb_u", TILEPRO_OPC_AVGB_U, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "avgb_u.sn", TILEPRO_OPC_AVGB_U_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "avgh", TILEPRO_OPC_AVGH, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "avgh.sn", TILEPRO_OPC_AVGH_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "bbns", TILEPRO_OPC_BBNS, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bbns.sn", TILEPRO_OPC_BBNS_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bbnst", TILEPRO_OPC_BBNST, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bbnst.sn", TILEPRO_OPC_BBNST_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bbs", TILEPRO_OPC_BBS, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bbs.sn", TILEPRO_OPC_BBS_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bbst", TILEPRO_OPC_BBST, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bbst.sn", TILEPRO_OPC_BBST_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgez", TILEPRO_OPC_BGEZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgez.sn", TILEPRO_OPC_BGEZ_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgezt", TILEPRO_OPC_BGEZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgezt.sn", TILEPRO_OPC_BGEZT_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgz", TILEPRO_OPC_BGZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgz.sn", TILEPRO_OPC_BGZ_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgzt", TILEPRO_OPC_BGZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgzt.sn", TILEPRO_OPC_BGZT_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bitx", TILEPRO_OPC_BITX, 0x5, 2, TREG_ZERO, 1, - { { 7, 8 }, { 0, }, { 11, 12 }, { 0, }, { 0, } }, - }, - { "bitx.sn", TILEPRO_OPC_BITX_SN, 0x1, 2, TREG_SN, 1, - { { 7, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "blez", TILEPRO_OPC_BLEZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blez.sn", TILEPRO_OPC_BLEZ_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blezt", TILEPRO_OPC_BLEZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blezt.sn", TILEPRO_OPC_BLEZT_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blz", TILEPRO_OPC_BLZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blz.sn", TILEPRO_OPC_BLZ_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blzt", TILEPRO_OPC_BLZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blzt.sn", TILEPRO_OPC_BLZT_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bnz", TILEPRO_OPC_BNZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bnz.sn", TILEPRO_OPC_BNZ_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bnzt", TILEPRO_OPC_BNZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bnzt.sn", TILEPRO_OPC_BNZT_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bytex", TILEPRO_OPC_BYTEX, 0x5, 2, TREG_ZERO, 1, - { { 7, 8 }, { 0, }, { 11, 12 }, { 0, }, { 0, } }, - }, - { "bytex.sn", TILEPRO_OPC_BYTEX_SN, 0x1, 2, TREG_SN, 1, - { { 7, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "bz", TILEPRO_OPC_BZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bz.sn", TILEPRO_OPC_BZ_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bzt", TILEPRO_OPC_BZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bzt.sn", TILEPRO_OPC_BZT_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 10, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "clz", TILEPRO_OPC_CLZ, 0x5, 2, TREG_ZERO, 1, - { { 7, 8 }, { 0, }, { 11, 12 }, { 0, }, { 0, } }, - }, - { "clz.sn", TILEPRO_OPC_CLZ_SN, 0x1, 2, TREG_SN, 1, - { { 7, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "crc32_32", TILEPRO_OPC_CRC32_32, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "crc32_32.sn", TILEPRO_OPC_CRC32_32_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "crc32_8", TILEPRO_OPC_CRC32_8, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "crc32_8.sn", TILEPRO_OPC_CRC32_8_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "ctz", TILEPRO_OPC_CTZ, 0x5, 2, TREG_ZERO, 1, - { { 7, 8 }, { 0, }, { 11, 12 }, { 0, }, { 0, } }, - }, - { "ctz.sn", TILEPRO_OPC_CTZ_SN, 0x1, 2, TREG_SN, 1, - { { 7, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "drain", TILEPRO_OPC_DRAIN, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "dtlbpr", TILEPRO_OPC_DTLBPR, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "dword_align", TILEPRO_OPC_DWORD_ALIGN, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "dword_align.sn", TILEPRO_OPC_DWORD_ALIGN_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "finv", TILEPRO_OPC_FINV, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "flush", TILEPRO_OPC_FLUSH, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "fnop", TILEPRO_OPC_FNOP, 0xf, 0, TREG_ZERO, 1, - { { }, { }, { }, { }, { 0, } }, - }, - { "icoh", TILEPRO_OPC_ICOH, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "ill", TILEPRO_OPC_ILL, 0xa, 0, TREG_ZERO, 1, - { { 0, }, { }, { 0, }, { }, { 0, } }, - }, - { "inthb", TILEPRO_OPC_INTHB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "inthb.sn", TILEPRO_OPC_INTHB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "inthh", TILEPRO_OPC_INTHH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "inthh.sn", TILEPRO_OPC_INTHH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "intlb", TILEPRO_OPC_INTLB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "intlb.sn", TILEPRO_OPC_INTLB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "intlh", TILEPRO_OPC_INTLH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "intlh.sn", TILEPRO_OPC_INTLH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "inv", TILEPRO_OPC_INV, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "iret", TILEPRO_OPC_IRET, 0x2, 0, TREG_ZERO, 1, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "jalb", TILEPRO_OPC_JALB, 0x2, 1, TREG_LR, 1, - { { 0, }, { 22 }, { 0, }, { 0, }, { 0, } }, - }, - { "jalf", TILEPRO_OPC_JALF, 0x2, 1, TREG_LR, 1, - { { 0, }, { 22 }, { 0, }, { 0, }, { 0, } }, - }, - { "jalr", TILEPRO_OPC_JALR, 0x2, 1, TREG_LR, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "jalrp", TILEPRO_OPC_JALRP, 0x2, 1, TREG_LR, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "jb", TILEPRO_OPC_JB, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 22 }, { 0, }, { 0, }, { 0, } }, - }, - { "jf", TILEPRO_OPC_JF, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 22 }, { 0, }, { 0, }, { 0, } }, - }, - { "jr", TILEPRO_OPC_JR, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "jrp", TILEPRO_OPC_JRP, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "lb", TILEPRO_OPC_LB, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 23, 15 } }, - }, - { "lb.sn", TILEPRO_OPC_LB_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "lb_u", TILEPRO_OPC_LB_U, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 23, 15 } }, - }, - { "lb_u.sn", TILEPRO_OPC_LB_U_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "lbadd", TILEPRO_OPC_LBADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lbadd.sn", TILEPRO_OPC_LBADD_SN, 0x2, 3, TREG_SN, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lbadd_u", TILEPRO_OPC_LBADD_U, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lbadd_u.sn", TILEPRO_OPC_LBADD_U_SN, 0x2, 3, TREG_SN, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lh", TILEPRO_OPC_LH, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 23, 15 } }, - }, - { "lh.sn", TILEPRO_OPC_LH_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "lh_u", TILEPRO_OPC_LH_U, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 23, 15 } }, - }, - { "lh_u.sn", TILEPRO_OPC_LH_U_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "lhadd", TILEPRO_OPC_LHADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lhadd.sn", TILEPRO_OPC_LHADD_SN, 0x2, 3, TREG_SN, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lhadd_u", TILEPRO_OPC_LHADD_U, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lhadd_u.sn", TILEPRO_OPC_LHADD_U_SN, 0x2, 3, TREG_SN, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lnk", TILEPRO_OPC_LNK, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "lnk.sn", TILEPRO_OPC_LNK_SN, 0x2, 1, TREG_SN, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "lw", TILEPRO_OPC_LW, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 23, 15 } }, - }, - { "lw.sn", TILEPRO_OPC_LW_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "lw_na", TILEPRO_OPC_LW_NA, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "lw_na.sn", TILEPRO_OPC_LW_NA_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "lwadd", TILEPRO_OPC_LWADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lwadd.sn", TILEPRO_OPC_LWADD_SN, 0x2, 3, TREG_SN, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lwadd_na", TILEPRO_OPC_LWADD_NA, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lwadd_na.sn", TILEPRO_OPC_LWADD_NA_SN, 0x2, 3, TREG_SN, 1, - { { 0, }, { 9, 24, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "maxb_u", TILEPRO_OPC_MAXB_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "maxb_u.sn", TILEPRO_OPC_MAXB_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "maxh", TILEPRO_OPC_MAXH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "maxh.sn", TILEPRO_OPC_MAXH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "maxib_u", TILEPRO_OPC_MAXIB_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "maxib_u.sn", TILEPRO_OPC_MAXIB_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "maxih", TILEPRO_OPC_MAXIH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "maxih.sn", TILEPRO_OPC_MAXIH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "mf", TILEPRO_OPC_MF, 0x2, 0, TREG_ZERO, 1, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "mfspr", TILEPRO_OPC_MFSPR, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 25 }, { 0, }, { 0, }, { 0, } }, - }, - { "minb_u", TILEPRO_OPC_MINB_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "minb_u.sn", TILEPRO_OPC_MINB_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "minh", TILEPRO_OPC_MINH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "minh.sn", TILEPRO_OPC_MINH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "minib_u", TILEPRO_OPC_MINIB_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "minib_u.sn", TILEPRO_OPC_MINIB_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "minih", TILEPRO_OPC_MINIH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "minih.sn", TILEPRO_OPC_MINIH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "mm", TILEPRO_OPC_MM, 0x3, 5, TREG_ZERO, 1, - { { 7, 8, 16, 26, 27 }, { 9, 10, 17, 28, 29 }, { 0, }, { 0, }, { 0, } }, - }, - { "mnz", TILEPRO_OPC_MNZ, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "mnz.sn", TILEPRO_OPC_MNZ_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "mnzb", TILEPRO_OPC_MNZB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "mnzb.sn", TILEPRO_OPC_MNZB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "mnzh", TILEPRO_OPC_MNZH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "mnzh.sn", TILEPRO_OPC_MNZH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "mtspr", TILEPRO_OPC_MTSPR, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 30, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhh_ss", TILEPRO_OPC_MULHH_SS, 0x5, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 11, 12, 18 }, { 0, }, { 0, } }, - }, - { "mulhh_ss.sn", TILEPRO_OPC_MULHH_SS_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhh_su", TILEPRO_OPC_MULHH_SU, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhh_su.sn", TILEPRO_OPC_MULHH_SU_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhh_uu", TILEPRO_OPC_MULHH_UU, 0x5, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 11, 12, 18 }, { 0, }, { 0, } }, - }, - { "mulhh_uu.sn", TILEPRO_OPC_MULHH_UU_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhha_ss", TILEPRO_OPC_MULHHA_SS, 0x5, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, - }, - { "mulhha_ss.sn", TILEPRO_OPC_MULHHA_SS_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhha_su", TILEPRO_OPC_MULHHA_SU, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhha_su.sn", TILEPRO_OPC_MULHHA_SU_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhha_uu", TILEPRO_OPC_MULHHA_UU, 0x5, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, - }, - { "mulhha_uu.sn", TILEPRO_OPC_MULHHA_UU_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhhsa_uu", TILEPRO_OPC_MULHHSA_UU, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhhsa_uu.sn", TILEPRO_OPC_MULHHSA_UU_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhl_ss", TILEPRO_OPC_MULHL_SS, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhl_ss.sn", TILEPRO_OPC_MULHL_SS_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhl_su", TILEPRO_OPC_MULHL_SU, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhl_su.sn", TILEPRO_OPC_MULHL_SU_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhl_us", TILEPRO_OPC_MULHL_US, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhl_us.sn", TILEPRO_OPC_MULHL_US_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhl_uu", TILEPRO_OPC_MULHL_UU, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhl_uu.sn", TILEPRO_OPC_MULHL_UU_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhla_ss", TILEPRO_OPC_MULHLA_SS, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhla_ss.sn", TILEPRO_OPC_MULHLA_SS_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhla_su", TILEPRO_OPC_MULHLA_SU, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhla_su.sn", TILEPRO_OPC_MULHLA_SU_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhla_us", TILEPRO_OPC_MULHLA_US, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhla_us.sn", TILEPRO_OPC_MULHLA_US_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhla_uu", TILEPRO_OPC_MULHLA_UU, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhla_uu.sn", TILEPRO_OPC_MULHLA_UU_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulhlsa_uu", TILEPRO_OPC_MULHLSA_UU, 0x5, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, - }, - { "mulhlsa_uu.sn", TILEPRO_OPC_MULHLSA_UU_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulll_ss", TILEPRO_OPC_MULLL_SS, 0x5, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 11, 12, 18 }, { 0, }, { 0, } }, - }, - { "mulll_ss.sn", TILEPRO_OPC_MULLL_SS_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulll_su", TILEPRO_OPC_MULLL_SU, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulll_su.sn", TILEPRO_OPC_MULLL_SU_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulll_uu", TILEPRO_OPC_MULLL_UU, 0x5, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 11, 12, 18 }, { 0, }, { 0, } }, - }, - { "mulll_uu.sn", TILEPRO_OPC_MULLL_UU_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mullla_ss", TILEPRO_OPC_MULLLA_SS, 0x5, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, - }, - { "mullla_ss.sn", TILEPRO_OPC_MULLLA_SS_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mullla_su", TILEPRO_OPC_MULLLA_SU, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mullla_su.sn", TILEPRO_OPC_MULLLA_SU_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mullla_uu", TILEPRO_OPC_MULLLA_UU, 0x5, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, - }, - { "mullla_uu.sn", TILEPRO_OPC_MULLLA_UU_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulllsa_uu", TILEPRO_OPC_MULLLSA_UU, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mulllsa_uu.sn", TILEPRO_OPC_MULLLSA_UU_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mvnz", TILEPRO_OPC_MVNZ, 0x5, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, - }, - { "mvnz.sn", TILEPRO_OPC_MVNZ_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mvz", TILEPRO_OPC_MVZ, 0x5, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 31, 12, 18 }, { 0, }, { 0, } }, - }, - { "mvz.sn", TILEPRO_OPC_MVZ_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mz", TILEPRO_OPC_MZ, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "mz.sn", TILEPRO_OPC_MZ_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "mzb", TILEPRO_OPC_MZB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "mzb.sn", TILEPRO_OPC_MZB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "mzh", TILEPRO_OPC_MZH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "mzh.sn", TILEPRO_OPC_MZH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "nap", TILEPRO_OPC_NAP, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "nop", TILEPRO_OPC_NOP, 0xf, 0, TREG_ZERO, 1, - { { }, { }, { }, { }, { 0, } }, - }, - { "nor", TILEPRO_OPC_NOR, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "nor.sn", TILEPRO_OPC_NOR_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "or", TILEPRO_OPC_OR, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "or.sn", TILEPRO_OPC_OR_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "ori", TILEPRO_OPC_ORI, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, - }, - { "ori.sn", TILEPRO_OPC_ORI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "packbs_u", TILEPRO_OPC_PACKBS_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "packbs_u.sn", TILEPRO_OPC_PACKBS_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "packhb", TILEPRO_OPC_PACKHB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "packhb.sn", TILEPRO_OPC_PACKHB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "packhs", TILEPRO_OPC_PACKHS, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "packhs.sn", TILEPRO_OPC_PACKHS_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "packlb", TILEPRO_OPC_PACKLB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "packlb.sn", TILEPRO_OPC_PACKLB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "pcnt", TILEPRO_OPC_PCNT, 0x5, 2, TREG_ZERO, 1, - { { 7, 8 }, { 0, }, { 11, 12 }, { 0, }, { 0, } }, - }, - { "pcnt.sn", TILEPRO_OPC_PCNT_SN, 0x1, 2, TREG_SN, 1, - { { 7, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "rl", TILEPRO_OPC_RL, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "rl.sn", TILEPRO_OPC_RL_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "rli", TILEPRO_OPC_RLI, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 11, 12, 34 }, { 13, 14, 35 }, { 0, } }, - }, - { "rli.sn", TILEPRO_OPC_RLI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "s1a", TILEPRO_OPC_S1A, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "s1a.sn", TILEPRO_OPC_S1A_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "s2a", TILEPRO_OPC_S2A, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "s2a.sn", TILEPRO_OPC_S2A_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "s3a", TILEPRO_OPC_S3A, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "s3a.sn", TILEPRO_OPC_S3A_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sadab_u", TILEPRO_OPC_SADAB_U, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadab_u.sn", TILEPRO_OPC_SADAB_U_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadah", TILEPRO_OPC_SADAH, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadah.sn", TILEPRO_OPC_SADAH_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadah_u", TILEPRO_OPC_SADAH_U, 0x1, 3, TREG_ZERO, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadah_u.sn", TILEPRO_OPC_SADAH_U_SN, 0x1, 3, TREG_SN, 1, - { { 21, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadb_u", TILEPRO_OPC_SADB_U, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadb_u.sn", TILEPRO_OPC_SADB_U_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadh", TILEPRO_OPC_SADH, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadh.sn", TILEPRO_OPC_SADH_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadh_u", TILEPRO_OPC_SADH_U, 0x1, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sadh_u.sn", TILEPRO_OPC_SADH_U_SN, 0x1, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "sb", TILEPRO_OPC_SB, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 10, 17 }, { 0, }, { 0, }, { 15, 36 } }, - }, - { "sbadd", TILEPRO_OPC_SBADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 24, 17, 37 }, { 0, }, { 0, }, { 0, } }, - }, - { "seq", TILEPRO_OPC_SEQ, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "seq.sn", TILEPRO_OPC_SEQ_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "seqb", TILEPRO_OPC_SEQB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "seqb.sn", TILEPRO_OPC_SEQB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "seqh", TILEPRO_OPC_SEQH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "seqh.sn", TILEPRO_OPC_SEQH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "seqi", TILEPRO_OPC_SEQI, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, - }, - { "seqi.sn", TILEPRO_OPC_SEQI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "seqib", TILEPRO_OPC_SEQIB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "seqib.sn", TILEPRO_OPC_SEQIB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "seqih", TILEPRO_OPC_SEQIH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "seqih.sn", TILEPRO_OPC_SEQIH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "sh", TILEPRO_OPC_SH, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 10, 17 }, { 0, }, { 0, }, { 15, 36 } }, - }, - { "shadd", TILEPRO_OPC_SHADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 24, 17, 37 }, { 0, }, { 0, }, { 0, } }, - }, - { "shl", TILEPRO_OPC_SHL, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "shl.sn", TILEPRO_OPC_SHL_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shlb", TILEPRO_OPC_SHLB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shlb.sn", TILEPRO_OPC_SHLB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shlh", TILEPRO_OPC_SHLH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shlh.sn", TILEPRO_OPC_SHLH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shli", TILEPRO_OPC_SHLI, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 11, 12, 34 }, { 13, 14, 35 }, { 0, } }, - }, - { "shli.sn", TILEPRO_OPC_SHLI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "shlib", TILEPRO_OPC_SHLIB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "shlib.sn", TILEPRO_OPC_SHLIB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "shlih", TILEPRO_OPC_SHLIH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "shlih.sn", TILEPRO_OPC_SHLIH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "shr", TILEPRO_OPC_SHR, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "shr.sn", TILEPRO_OPC_SHR_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shrb", TILEPRO_OPC_SHRB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shrb.sn", TILEPRO_OPC_SHRB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shrh", TILEPRO_OPC_SHRH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shrh.sn", TILEPRO_OPC_SHRH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shri", TILEPRO_OPC_SHRI, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 11, 12, 34 }, { 13, 14, 35 }, { 0, } }, - }, - { "shri.sn", TILEPRO_OPC_SHRI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "shrib", TILEPRO_OPC_SHRIB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "shrib.sn", TILEPRO_OPC_SHRIB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "shrih", TILEPRO_OPC_SHRIH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "shrih.sn", TILEPRO_OPC_SHRIH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "slt", TILEPRO_OPC_SLT, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "slt.sn", TILEPRO_OPC_SLT_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slt_u", TILEPRO_OPC_SLT_U, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "slt_u.sn", TILEPRO_OPC_SLT_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltb", TILEPRO_OPC_SLTB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltb.sn", TILEPRO_OPC_SLTB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltb_u", TILEPRO_OPC_SLTB_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltb_u.sn", TILEPRO_OPC_SLTB_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slte", TILEPRO_OPC_SLTE, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "slte.sn", TILEPRO_OPC_SLTE_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slte_u", TILEPRO_OPC_SLTE_U, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "slte_u.sn", TILEPRO_OPC_SLTE_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slteb", TILEPRO_OPC_SLTEB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slteb.sn", TILEPRO_OPC_SLTEB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slteb_u", TILEPRO_OPC_SLTEB_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slteb_u.sn", TILEPRO_OPC_SLTEB_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slteh", TILEPRO_OPC_SLTEH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slteh.sn", TILEPRO_OPC_SLTEH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slteh_u", TILEPRO_OPC_SLTEH_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slteh_u.sn", TILEPRO_OPC_SLTEH_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slth", TILEPRO_OPC_SLTH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slth.sn", TILEPRO_OPC_SLTH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slth_u", TILEPRO_OPC_SLTH_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slth_u.sn", TILEPRO_OPC_SLTH_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "slti", TILEPRO_OPC_SLTI, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, - }, - { "slti.sn", TILEPRO_OPC_SLTI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "slti_u", TILEPRO_OPC_SLTI_U, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 11, 12, 2 }, { 13, 14, 3 }, { 0, } }, - }, - { "slti_u.sn", TILEPRO_OPC_SLTI_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltib", TILEPRO_OPC_SLTIB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltib.sn", TILEPRO_OPC_SLTIB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltib_u", TILEPRO_OPC_SLTIB_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltib_u.sn", TILEPRO_OPC_SLTIB_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltih", TILEPRO_OPC_SLTIH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltih.sn", TILEPRO_OPC_SLTIH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltih_u", TILEPRO_OPC_SLTIH_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "sltih_u.sn", TILEPRO_OPC_SLTIH_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "sne", TILEPRO_OPC_SNE, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "sne.sn", TILEPRO_OPC_SNE_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sneb", TILEPRO_OPC_SNEB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sneb.sn", TILEPRO_OPC_SNEB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sneh", TILEPRO_OPC_SNEH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sneh.sn", TILEPRO_OPC_SNEH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sra", TILEPRO_OPC_SRA, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "sra.sn", TILEPRO_OPC_SRA_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "srab", TILEPRO_OPC_SRAB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "srab.sn", TILEPRO_OPC_SRAB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "srah", TILEPRO_OPC_SRAH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "srah.sn", TILEPRO_OPC_SRAH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "srai", TILEPRO_OPC_SRAI, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 11, 12, 34 }, { 13, 14, 35 }, { 0, } }, - }, - { "srai.sn", TILEPRO_OPC_SRAI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "sraib", TILEPRO_OPC_SRAIB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "sraib.sn", TILEPRO_OPC_SRAIB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "sraih", TILEPRO_OPC_SRAIH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "sraih.sn", TILEPRO_OPC_SRAIH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 32 }, { 9, 10, 33 }, { 0, }, { 0, }, { 0, } }, - }, - { "sub", TILEPRO_OPC_SUB, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "sub.sn", TILEPRO_OPC_SUB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "subb", TILEPRO_OPC_SUBB, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "subb.sn", TILEPRO_OPC_SUBB_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "subbs_u", TILEPRO_OPC_SUBBS_U, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "subbs_u.sn", TILEPRO_OPC_SUBBS_U_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "subh", TILEPRO_OPC_SUBH, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "subh.sn", TILEPRO_OPC_SUBH_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "subhs", TILEPRO_OPC_SUBHS, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "subhs.sn", TILEPRO_OPC_SUBHS_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "subs", TILEPRO_OPC_SUBS, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "subs.sn", TILEPRO_OPC_SUBS_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "sw", TILEPRO_OPC_SW, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 10, 17 }, { 0, }, { 0, }, { 15, 36 } }, - }, - { "swadd", TILEPRO_OPC_SWADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 24, 17, 37 }, { 0, }, { 0, }, { 0, } }, - }, - { "swint0", TILEPRO_OPC_SWINT0, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "swint1", TILEPRO_OPC_SWINT1, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "swint2", TILEPRO_OPC_SWINT2, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "swint3", TILEPRO_OPC_SWINT3, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "tblidxb0", TILEPRO_OPC_TBLIDXB0, 0x5, 2, TREG_ZERO, 1, - { { 21, 8 }, { 0, }, { 31, 12 }, { 0, }, { 0, } }, - }, - { "tblidxb0.sn", TILEPRO_OPC_TBLIDXB0_SN, 0x1, 2, TREG_SN, 1, - { { 21, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "tblidxb1", TILEPRO_OPC_TBLIDXB1, 0x5, 2, TREG_ZERO, 1, - { { 21, 8 }, { 0, }, { 31, 12 }, { 0, }, { 0, } }, - }, - { "tblidxb1.sn", TILEPRO_OPC_TBLIDXB1_SN, 0x1, 2, TREG_SN, 1, - { { 21, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "tblidxb2", TILEPRO_OPC_TBLIDXB2, 0x5, 2, TREG_ZERO, 1, - { { 21, 8 }, { 0, }, { 31, 12 }, { 0, }, { 0, } }, - }, - { "tblidxb2.sn", TILEPRO_OPC_TBLIDXB2_SN, 0x1, 2, TREG_SN, 1, - { { 21, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "tblidxb3", TILEPRO_OPC_TBLIDXB3, 0x5, 2, TREG_ZERO, 1, - { { 21, 8 }, { 0, }, { 31, 12 }, { 0, }, { 0, } }, - }, - { "tblidxb3.sn", TILEPRO_OPC_TBLIDXB3_SN, 0x1, 2, TREG_SN, 1, - { { 21, 8 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "tns", TILEPRO_OPC_TNS, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "tns.sn", TILEPRO_OPC_TNS_SN, 0x2, 2, TREG_SN, 1, - { { 0, }, { 9, 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "wh64", TILEPRO_OPC_WH64, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 10 }, { 0, }, { 0, }, { 0, } }, - }, - { "xor", TILEPRO_OPC_XOR, 0xf, 3, TREG_ZERO, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 11, 12, 18 }, { 13, 14, 19 }, { 0, } }, - }, - { "xor.sn", TILEPRO_OPC_XOR_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 16 }, { 9, 10, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "xori", TILEPRO_OPC_XORI, 0x3, 3, TREG_ZERO, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "xori.sn", TILEPRO_OPC_XORI_SN, 0x3, 3, TREG_SN, 1, - { { 7, 8, 0 }, { 9, 10, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { NULL, TILEPRO_OPC_NONE, 0, 0, TREG_ZERO, 0, { { 0, } }, - } -}; -#define BITFIELD(start, size) ((start) | (((1 << (size)) - 1) << 6)) -#define CHILD(array_index) (TILEPRO_OPC_NONE + (array_index)) - -static const unsigned short decode_X0_fsm[1153] = -{ - BITFIELD(22, 9) /* index 0 */, - CHILD(513), CHILD(530), CHILD(547), CHILD(564), CHILD(596), CHILD(613), - CHILD(630), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(663), CHILD(680), CHILD(697), - CHILD(714), CHILD(746), CHILD(763), CHILD(780), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(813), - CHILD(813), CHILD(813), CHILD(813), CHILD(813), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), CHILD(828), - CHILD(828), CHILD(828), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(873), CHILD(878), CHILD(883), CHILD(903), CHILD(908), - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(913), - CHILD(918), CHILD(923), CHILD(943), CHILD(948), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(953), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(988), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, CHILD(993), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(1076), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(18, 4) /* index 513 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_ADDB, TILEPRO_OPC_ADDH, TILEPRO_OPC_ADD, - TILEPRO_OPC_ADIFFB_U, TILEPRO_OPC_ADIFFH, TILEPRO_OPC_AND, - TILEPRO_OPC_AVGB_U, TILEPRO_OPC_AVGH, TILEPRO_OPC_CRC32_32, - TILEPRO_OPC_CRC32_8, TILEPRO_OPC_INTHB, TILEPRO_OPC_INTHH, - TILEPRO_OPC_INTLB, TILEPRO_OPC_INTLH, TILEPRO_OPC_MAXB_U, - BITFIELD(18, 4) /* index 530 */, - TILEPRO_OPC_MAXH, TILEPRO_OPC_MINB_U, TILEPRO_OPC_MINH, TILEPRO_OPC_MNZB, - TILEPRO_OPC_MNZH, TILEPRO_OPC_MNZ, TILEPRO_OPC_MULHHA_SS, - TILEPRO_OPC_MULHHA_SU, TILEPRO_OPC_MULHHA_UU, TILEPRO_OPC_MULHHSA_UU, - TILEPRO_OPC_MULHH_SS, TILEPRO_OPC_MULHH_SU, TILEPRO_OPC_MULHH_UU, - TILEPRO_OPC_MULHLA_SS, TILEPRO_OPC_MULHLA_SU, TILEPRO_OPC_MULHLA_US, - BITFIELD(18, 4) /* index 547 */, - TILEPRO_OPC_MULHLA_UU, TILEPRO_OPC_MULHLSA_UU, TILEPRO_OPC_MULHL_SS, - TILEPRO_OPC_MULHL_SU, TILEPRO_OPC_MULHL_US, TILEPRO_OPC_MULHL_UU, - TILEPRO_OPC_MULLLA_SS, TILEPRO_OPC_MULLLA_SU, TILEPRO_OPC_MULLLA_UU, - TILEPRO_OPC_MULLLSA_UU, TILEPRO_OPC_MULLL_SS, TILEPRO_OPC_MULLL_SU, - TILEPRO_OPC_MULLL_UU, TILEPRO_OPC_MVNZ, TILEPRO_OPC_MVZ, TILEPRO_OPC_MZB, - BITFIELD(18, 4) /* index 564 */, - TILEPRO_OPC_MZH, TILEPRO_OPC_MZ, TILEPRO_OPC_NOR, CHILD(581), - TILEPRO_OPC_PACKHB, TILEPRO_OPC_PACKLB, TILEPRO_OPC_RL, TILEPRO_OPC_S1A, - TILEPRO_OPC_S2A, TILEPRO_OPC_S3A, TILEPRO_OPC_SADAB_U, TILEPRO_OPC_SADAH, - TILEPRO_OPC_SADAH_U, TILEPRO_OPC_SADB_U, TILEPRO_OPC_SADH, - TILEPRO_OPC_SADH_U, - BITFIELD(12, 2) /* index 581 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(586), - BITFIELD(14, 2) /* index 586 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(591), - BITFIELD(16, 2) /* index 591 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_MOVE, - BITFIELD(18, 4) /* index 596 */, - TILEPRO_OPC_SEQB, TILEPRO_OPC_SEQH, TILEPRO_OPC_SEQ, TILEPRO_OPC_SHLB, - TILEPRO_OPC_SHLH, TILEPRO_OPC_SHL, TILEPRO_OPC_SHRB, TILEPRO_OPC_SHRH, - TILEPRO_OPC_SHR, TILEPRO_OPC_SLTB, TILEPRO_OPC_SLTB_U, TILEPRO_OPC_SLTEB, - TILEPRO_OPC_SLTEB_U, TILEPRO_OPC_SLTEH, TILEPRO_OPC_SLTEH_U, - TILEPRO_OPC_SLTE, - BITFIELD(18, 4) /* index 613 */, - TILEPRO_OPC_SLTE_U, TILEPRO_OPC_SLTH, TILEPRO_OPC_SLTH_U, TILEPRO_OPC_SLT, - TILEPRO_OPC_SLT_U, TILEPRO_OPC_SNEB, TILEPRO_OPC_SNEH, TILEPRO_OPC_SNE, - TILEPRO_OPC_SRAB, TILEPRO_OPC_SRAH, TILEPRO_OPC_SRA, TILEPRO_OPC_SUBB, - TILEPRO_OPC_SUBH, TILEPRO_OPC_SUB, TILEPRO_OPC_XOR, TILEPRO_OPC_DWORD_ALIGN, - BITFIELD(18, 3) /* index 630 */, - CHILD(639), CHILD(642), CHILD(645), CHILD(648), CHILD(651), CHILD(654), - CHILD(657), CHILD(660), - BITFIELD(21, 1) /* index 639 */, - TILEPRO_OPC_ADDS, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 642 */, - TILEPRO_OPC_SUBS, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 645 */, - TILEPRO_OPC_ADDBS_U, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 648 */, - TILEPRO_OPC_ADDHS, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 651 */, - TILEPRO_OPC_SUBBS_U, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 654 */, - TILEPRO_OPC_SUBHS, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 657 */, - TILEPRO_OPC_PACKHS, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 660 */, - TILEPRO_OPC_PACKBS_U, TILEPRO_OPC_NONE, - BITFIELD(18, 4) /* index 663 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_ADDB_SN, TILEPRO_OPC_ADDH_SN, - TILEPRO_OPC_ADD_SN, TILEPRO_OPC_ADIFFB_U_SN, TILEPRO_OPC_ADIFFH_SN, - TILEPRO_OPC_AND_SN, TILEPRO_OPC_AVGB_U_SN, TILEPRO_OPC_AVGH_SN, - TILEPRO_OPC_CRC32_32_SN, TILEPRO_OPC_CRC32_8_SN, TILEPRO_OPC_INTHB_SN, - TILEPRO_OPC_INTHH_SN, TILEPRO_OPC_INTLB_SN, TILEPRO_OPC_INTLH_SN, - TILEPRO_OPC_MAXB_U_SN, - BITFIELD(18, 4) /* index 680 */, - TILEPRO_OPC_MAXH_SN, TILEPRO_OPC_MINB_U_SN, TILEPRO_OPC_MINH_SN, - TILEPRO_OPC_MNZB_SN, TILEPRO_OPC_MNZH_SN, TILEPRO_OPC_MNZ_SN, - TILEPRO_OPC_MULHHA_SS_SN, TILEPRO_OPC_MULHHA_SU_SN, - TILEPRO_OPC_MULHHA_UU_SN, TILEPRO_OPC_MULHHSA_UU_SN, - TILEPRO_OPC_MULHH_SS_SN, TILEPRO_OPC_MULHH_SU_SN, TILEPRO_OPC_MULHH_UU_SN, - TILEPRO_OPC_MULHLA_SS_SN, TILEPRO_OPC_MULHLA_SU_SN, - TILEPRO_OPC_MULHLA_US_SN, - BITFIELD(18, 4) /* index 697 */, - TILEPRO_OPC_MULHLA_UU_SN, TILEPRO_OPC_MULHLSA_UU_SN, - TILEPRO_OPC_MULHL_SS_SN, TILEPRO_OPC_MULHL_SU_SN, TILEPRO_OPC_MULHL_US_SN, - TILEPRO_OPC_MULHL_UU_SN, TILEPRO_OPC_MULLLA_SS_SN, TILEPRO_OPC_MULLLA_SU_SN, - TILEPRO_OPC_MULLLA_UU_SN, TILEPRO_OPC_MULLLSA_UU_SN, - TILEPRO_OPC_MULLL_SS_SN, TILEPRO_OPC_MULLL_SU_SN, TILEPRO_OPC_MULLL_UU_SN, - TILEPRO_OPC_MVNZ_SN, TILEPRO_OPC_MVZ_SN, TILEPRO_OPC_MZB_SN, - BITFIELD(18, 4) /* index 714 */, - TILEPRO_OPC_MZH_SN, TILEPRO_OPC_MZ_SN, TILEPRO_OPC_NOR_SN, CHILD(731), - TILEPRO_OPC_PACKHB_SN, TILEPRO_OPC_PACKLB_SN, TILEPRO_OPC_RL_SN, - TILEPRO_OPC_S1A_SN, TILEPRO_OPC_S2A_SN, TILEPRO_OPC_S3A_SN, - TILEPRO_OPC_SADAB_U_SN, TILEPRO_OPC_SADAH_SN, TILEPRO_OPC_SADAH_U_SN, - TILEPRO_OPC_SADB_U_SN, TILEPRO_OPC_SADH_SN, TILEPRO_OPC_SADH_U_SN, - BITFIELD(12, 2) /* index 731 */, - TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, CHILD(736), - BITFIELD(14, 2) /* index 736 */, - TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, CHILD(741), - BITFIELD(16, 2) /* index 741 */, - TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, - TILEPRO_OPC_MOVE_SN, - BITFIELD(18, 4) /* index 746 */, - TILEPRO_OPC_SEQB_SN, TILEPRO_OPC_SEQH_SN, TILEPRO_OPC_SEQ_SN, - TILEPRO_OPC_SHLB_SN, TILEPRO_OPC_SHLH_SN, TILEPRO_OPC_SHL_SN, - TILEPRO_OPC_SHRB_SN, TILEPRO_OPC_SHRH_SN, TILEPRO_OPC_SHR_SN, - TILEPRO_OPC_SLTB_SN, TILEPRO_OPC_SLTB_U_SN, TILEPRO_OPC_SLTEB_SN, - TILEPRO_OPC_SLTEB_U_SN, TILEPRO_OPC_SLTEH_SN, TILEPRO_OPC_SLTEH_U_SN, - TILEPRO_OPC_SLTE_SN, - BITFIELD(18, 4) /* index 763 */, - TILEPRO_OPC_SLTE_U_SN, TILEPRO_OPC_SLTH_SN, TILEPRO_OPC_SLTH_U_SN, - TILEPRO_OPC_SLT_SN, TILEPRO_OPC_SLT_U_SN, TILEPRO_OPC_SNEB_SN, - TILEPRO_OPC_SNEH_SN, TILEPRO_OPC_SNE_SN, TILEPRO_OPC_SRAB_SN, - TILEPRO_OPC_SRAH_SN, TILEPRO_OPC_SRA_SN, TILEPRO_OPC_SUBB_SN, - TILEPRO_OPC_SUBH_SN, TILEPRO_OPC_SUB_SN, TILEPRO_OPC_XOR_SN, - TILEPRO_OPC_DWORD_ALIGN_SN, - BITFIELD(18, 3) /* index 780 */, - CHILD(789), CHILD(792), CHILD(795), CHILD(798), CHILD(801), CHILD(804), - CHILD(807), CHILD(810), - BITFIELD(21, 1) /* index 789 */, - TILEPRO_OPC_ADDS_SN, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 792 */, - TILEPRO_OPC_SUBS_SN, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 795 */, - TILEPRO_OPC_ADDBS_U_SN, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 798 */, - TILEPRO_OPC_ADDHS_SN, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 801 */, - TILEPRO_OPC_SUBBS_U_SN, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 804 */, - TILEPRO_OPC_SUBHS_SN, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 807 */, - TILEPRO_OPC_PACKHS_SN, TILEPRO_OPC_NONE, - BITFIELD(21, 1) /* index 810 */, - TILEPRO_OPC_PACKBS_U_SN, TILEPRO_OPC_NONE, - BITFIELD(6, 2) /* index 813 */, - TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, - CHILD(818), - BITFIELD(8, 2) /* index 818 */, - TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, - CHILD(823), - BITFIELD(10, 2) /* index 823 */, - TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, - TILEPRO_OPC_MOVELI_SN, - BITFIELD(6, 2) /* index 828 */, - TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, CHILD(833), - BITFIELD(8, 2) /* index 833 */, - TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, CHILD(838), - BITFIELD(10, 2) /* index 838 */, - TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_MOVELI, - BITFIELD(0, 2) /* index 843 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(848), - BITFIELD(2, 2) /* index 848 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(853), - BITFIELD(4, 2) /* index 853 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(858), - BITFIELD(6, 2) /* index 858 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(863), - BITFIELD(8, 2) /* index 863 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(868), - BITFIELD(10, 2) /* index 868 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_INFOL, - BITFIELD(20, 2) /* index 873 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_ADDIB, TILEPRO_OPC_ADDIH, TILEPRO_OPC_ADDI, - BITFIELD(20, 2) /* index 878 */, - TILEPRO_OPC_MAXIB_U, TILEPRO_OPC_MAXIH, TILEPRO_OPC_MINIB_U, - TILEPRO_OPC_MINIH, - BITFIELD(20, 2) /* index 883 */, - CHILD(888), TILEPRO_OPC_SEQIB, TILEPRO_OPC_SEQIH, TILEPRO_OPC_SEQI, - BITFIELD(6, 2) /* index 888 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(893), - BITFIELD(8, 2) /* index 893 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(898), - BITFIELD(10, 2) /* index 898 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_MOVEI, - BITFIELD(20, 2) /* index 903 */, - TILEPRO_OPC_SLTIB, TILEPRO_OPC_SLTIB_U, TILEPRO_OPC_SLTIH, - TILEPRO_OPC_SLTIH_U, - BITFIELD(20, 2) /* index 908 */, - TILEPRO_OPC_SLTI, TILEPRO_OPC_SLTI_U, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(20, 2) /* index 913 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_ADDIB_SN, TILEPRO_OPC_ADDIH_SN, - TILEPRO_OPC_ADDI_SN, - BITFIELD(20, 2) /* index 918 */, - TILEPRO_OPC_MAXIB_U_SN, TILEPRO_OPC_MAXIH_SN, TILEPRO_OPC_MINIB_U_SN, - TILEPRO_OPC_MINIH_SN, - BITFIELD(20, 2) /* index 923 */, - CHILD(928), TILEPRO_OPC_SEQIB_SN, TILEPRO_OPC_SEQIH_SN, TILEPRO_OPC_SEQI_SN, - BITFIELD(6, 2) /* index 928 */, - TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, CHILD(933), - BITFIELD(8, 2) /* index 933 */, - TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, CHILD(938), - BITFIELD(10, 2) /* index 938 */, - TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, - TILEPRO_OPC_MOVEI_SN, - BITFIELD(20, 2) /* index 943 */, - TILEPRO_OPC_SLTIB_SN, TILEPRO_OPC_SLTIB_U_SN, TILEPRO_OPC_SLTIH_SN, - TILEPRO_OPC_SLTIH_U_SN, - BITFIELD(20, 2) /* index 948 */, - TILEPRO_OPC_SLTI_SN, TILEPRO_OPC_SLTI_U_SN, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, - BITFIELD(20, 2) /* index 953 */, - TILEPRO_OPC_NONE, CHILD(958), TILEPRO_OPC_XORI, TILEPRO_OPC_NONE, - BITFIELD(0, 2) /* index 958 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(963), - BITFIELD(2, 2) /* index 963 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(968), - BITFIELD(4, 2) /* index 968 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(973), - BITFIELD(6, 2) /* index 973 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(978), - BITFIELD(8, 2) /* index 978 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(983), - BITFIELD(10, 2) /* index 983 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_INFO, - BITFIELD(20, 2) /* index 988 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_ANDI_SN, TILEPRO_OPC_XORI_SN, - TILEPRO_OPC_NONE, - BITFIELD(17, 5) /* index 993 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_RLI, TILEPRO_OPC_SHLIB, TILEPRO_OPC_SHLIH, - TILEPRO_OPC_SHLI, TILEPRO_OPC_SHRIB, TILEPRO_OPC_SHRIH, TILEPRO_OPC_SHRI, - TILEPRO_OPC_SRAIB, TILEPRO_OPC_SRAIH, TILEPRO_OPC_SRAI, CHILD(1026), - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(12, 4) /* index 1026 */, - TILEPRO_OPC_NONE, CHILD(1043), CHILD(1046), CHILD(1049), CHILD(1052), - CHILD(1055), CHILD(1058), CHILD(1061), CHILD(1064), CHILD(1067), - CHILD(1070), CHILD(1073), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1043 */, - TILEPRO_OPC_BITX, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1046 */, - TILEPRO_OPC_BYTEX, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1049 */, - TILEPRO_OPC_CLZ, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1052 */, - TILEPRO_OPC_CTZ, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1055 */, - TILEPRO_OPC_FNOP, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1058 */, - TILEPRO_OPC_NOP, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1061 */, - TILEPRO_OPC_PCNT, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1064 */, - TILEPRO_OPC_TBLIDXB0, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1067 */, - TILEPRO_OPC_TBLIDXB1, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1070 */, - TILEPRO_OPC_TBLIDXB2, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1073 */, - TILEPRO_OPC_TBLIDXB3, TILEPRO_OPC_NONE, - BITFIELD(17, 5) /* index 1076 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_RLI_SN, TILEPRO_OPC_SHLIB_SN, - TILEPRO_OPC_SHLIH_SN, TILEPRO_OPC_SHLI_SN, TILEPRO_OPC_SHRIB_SN, - TILEPRO_OPC_SHRIH_SN, TILEPRO_OPC_SHRI_SN, TILEPRO_OPC_SRAIB_SN, - TILEPRO_OPC_SRAIH_SN, TILEPRO_OPC_SRAI_SN, CHILD(1109), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(12, 4) /* index 1109 */, - TILEPRO_OPC_NONE, CHILD(1126), CHILD(1129), CHILD(1132), CHILD(1135), - CHILD(1055), CHILD(1058), CHILD(1138), CHILD(1141), CHILD(1144), - CHILD(1147), CHILD(1150), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1126 */, - TILEPRO_OPC_BITX_SN, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1129 */, - TILEPRO_OPC_BYTEX_SN, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1132 */, - TILEPRO_OPC_CLZ_SN, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1135 */, - TILEPRO_OPC_CTZ_SN, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1138 */, - TILEPRO_OPC_PCNT_SN, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1141 */, - TILEPRO_OPC_TBLIDXB0_SN, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1144 */, - TILEPRO_OPC_TBLIDXB1_SN, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1147 */, - TILEPRO_OPC_TBLIDXB2_SN, TILEPRO_OPC_NONE, - BITFIELD(16, 1) /* index 1150 */, - TILEPRO_OPC_TBLIDXB3_SN, TILEPRO_OPC_NONE, -}; - -static const unsigned short decode_X1_fsm[1540] = -{ - BITFIELD(54, 9) /* index 0 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - CHILD(513), CHILD(561), CHILD(594), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(641), - CHILD(689), CHILD(722), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(766), - CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), - CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), - CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), - CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), - CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), CHILD(766), - CHILD(766), CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), - CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), - CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), - CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), - CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), CHILD(781), - CHILD(781), CHILD(781), CHILD(781), CHILD(796), CHILD(796), CHILD(796), - CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), - CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), - CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), - CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), - CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(796), CHILD(826), - CHILD(826), CHILD(826), CHILD(826), CHILD(826), CHILD(826), CHILD(826), - CHILD(826), CHILD(826), CHILD(826), CHILD(826), CHILD(826), CHILD(826), - CHILD(826), CHILD(826), CHILD(826), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), CHILD(843), - CHILD(843), CHILD(860), CHILD(899), CHILD(923), CHILD(932), - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - CHILD(941), CHILD(950), CHILD(974), CHILD(983), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, - TILEPRO_OPC_MM, TILEPRO_OPC_MM, TILEPRO_OPC_MM, CHILD(992), - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, CHILD(1334), - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, - TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_J, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, - TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_JAL, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(49, 5) /* index 513 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_ADDB, TILEPRO_OPC_ADDH, TILEPRO_OPC_ADD, - TILEPRO_OPC_AND, TILEPRO_OPC_INTHB, TILEPRO_OPC_INTHH, TILEPRO_OPC_INTLB, - TILEPRO_OPC_INTLH, TILEPRO_OPC_JALRP, TILEPRO_OPC_JALR, TILEPRO_OPC_JRP, - TILEPRO_OPC_JR, TILEPRO_OPC_LNK, TILEPRO_OPC_MAXB_U, TILEPRO_OPC_MAXH, - TILEPRO_OPC_MINB_U, TILEPRO_OPC_MINH, TILEPRO_OPC_MNZB, TILEPRO_OPC_MNZH, - TILEPRO_OPC_MNZ, TILEPRO_OPC_MZB, TILEPRO_OPC_MZH, TILEPRO_OPC_MZ, - TILEPRO_OPC_NOR, CHILD(546), TILEPRO_OPC_PACKHB, TILEPRO_OPC_PACKLB, - TILEPRO_OPC_RL, TILEPRO_OPC_S1A, TILEPRO_OPC_S2A, TILEPRO_OPC_S3A, - BITFIELD(43, 2) /* index 546 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(551), - BITFIELD(45, 2) /* index 551 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(556), - BITFIELD(47, 2) /* index 556 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_MOVE, - BITFIELD(49, 5) /* index 561 */, - TILEPRO_OPC_SB, TILEPRO_OPC_SEQB, TILEPRO_OPC_SEQH, TILEPRO_OPC_SEQ, - TILEPRO_OPC_SHLB, TILEPRO_OPC_SHLH, TILEPRO_OPC_SHL, TILEPRO_OPC_SHRB, - TILEPRO_OPC_SHRH, TILEPRO_OPC_SHR, TILEPRO_OPC_SH, TILEPRO_OPC_SLTB, - TILEPRO_OPC_SLTB_U, TILEPRO_OPC_SLTEB, TILEPRO_OPC_SLTEB_U, - TILEPRO_OPC_SLTEH, TILEPRO_OPC_SLTEH_U, TILEPRO_OPC_SLTE, - TILEPRO_OPC_SLTE_U, TILEPRO_OPC_SLTH, TILEPRO_OPC_SLTH_U, TILEPRO_OPC_SLT, - TILEPRO_OPC_SLT_U, TILEPRO_OPC_SNEB, TILEPRO_OPC_SNEH, TILEPRO_OPC_SNE, - TILEPRO_OPC_SRAB, TILEPRO_OPC_SRAH, TILEPRO_OPC_SRA, TILEPRO_OPC_SUBB, - TILEPRO_OPC_SUBH, TILEPRO_OPC_SUB, - BITFIELD(49, 4) /* index 594 */, - CHILD(611), CHILD(614), CHILD(617), CHILD(620), CHILD(623), CHILD(626), - CHILD(629), CHILD(632), CHILD(635), CHILD(638), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 611 */, - TILEPRO_OPC_SW, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 614 */, - TILEPRO_OPC_XOR, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 617 */, - TILEPRO_OPC_ADDS, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 620 */, - TILEPRO_OPC_SUBS, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 623 */, - TILEPRO_OPC_ADDBS_U, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 626 */, - TILEPRO_OPC_ADDHS, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 629 */, - TILEPRO_OPC_SUBBS_U, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 632 */, - TILEPRO_OPC_SUBHS, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 635 */, - TILEPRO_OPC_PACKHS, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 638 */, - TILEPRO_OPC_PACKBS_U, TILEPRO_OPC_NONE, - BITFIELD(49, 5) /* index 641 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_ADDB_SN, TILEPRO_OPC_ADDH_SN, - TILEPRO_OPC_ADD_SN, TILEPRO_OPC_AND_SN, TILEPRO_OPC_INTHB_SN, - TILEPRO_OPC_INTHH_SN, TILEPRO_OPC_INTLB_SN, TILEPRO_OPC_INTLH_SN, - TILEPRO_OPC_JALRP, TILEPRO_OPC_JALR, TILEPRO_OPC_JRP, TILEPRO_OPC_JR, - TILEPRO_OPC_LNK_SN, TILEPRO_OPC_MAXB_U_SN, TILEPRO_OPC_MAXH_SN, - TILEPRO_OPC_MINB_U_SN, TILEPRO_OPC_MINH_SN, TILEPRO_OPC_MNZB_SN, - TILEPRO_OPC_MNZH_SN, TILEPRO_OPC_MNZ_SN, TILEPRO_OPC_MZB_SN, - TILEPRO_OPC_MZH_SN, TILEPRO_OPC_MZ_SN, TILEPRO_OPC_NOR_SN, CHILD(674), - TILEPRO_OPC_PACKHB_SN, TILEPRO_OPC_PACKLB_SN, TILEPRO_OPC_RL_SN, - TILEPRO_OPC_S1A_SN, TILEPRO_OPC_S2A_SN, TILEPRO_OPC_S3A_SN, - BITFIELD(43, 2) /* index 674 */, - TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, CHILD(679), - BITFIELD(45, 2) /* index 679 */, - TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, CHILD(684), - BITFIELD(47, 2) /* index 684 */, - TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, TILEPRO_OPC_OR_SN, - TILEPRO_OPC_MOVE_SN, - BITFIELD(49, 5) /* index 689 */, - TILEPRO_OPC_SB, TILEPRO_OPC_SEQB_SN, TILEPRO_OPC_SEQH_SN, - TILEPRO_OPC_SEQ_SN, TILEPRO_OPC_SHLB_SN, TILEPRO_OPC_SHLH_SN, - TILEPRO_OPC_SHL_SN, TILEPRO_OPC_SHRB_SN, TILEPRO_OPC_SHRH_SN, - TILEPRO_OPC_SHR_SN, TILEPRO_OPC_SH, TILEPRO_OPC_SLTB_SN, - TILEPRO_OPC_SLTB_U_SN, TILEPRO_OPC_SLTEB_SN, TILEPRO_OPC_SLTEB_U_SN, - TILEPRO_OPC_SLTEH_SN, TILEPRO_OPC_SLTEH_U_SN, TILEPRO_OPC_SLTE_SN, - TILEPRO_OPC_SLTE_U_SN, TILEPRO_OPC_SLTH_SN, TILEPRO_OPC_SLTH_U_SN, - TILEPRO_OPC_SLT_SN, TILEPRO_OPC_SLT_U_SN, TILEPRO_OPC_SNEB_SN, - TILEPRO_OPC_SNEH_SN, TILEPRO_OPC_SNE_SN, TILEPRO_OPC_SRAB_SN, - TILEPRO_OPC_SRAH_SN, TILEPRO_OPC_SRA_SN, TILEPRO_OPC_SUBB_SN, - TILEPRO_OPC_SUBH_SN, TILEPRO_OPC_SUB_SN, - BITFIELD(49, 4) /* index 722 */, - CHILD(611), CHILD(739), CHILD(742), CHILD(745), CHILD(748), CHILD(751), - CHILD(754), CHILD(757), CHILD(760), CHILD(763), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 739 */, - TILEPRO_OPC_XOR_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 742 */, - TILEPRO_OPC_ADDS_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 745 */, - TILEPRO_OPC_SUBS_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 748 */, - TILEPRO_OPC_ADDBS_U_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 751 */, - TILEPRO_OPC_ADDHS_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 754 */, - TILEPRO_OPC_SUBBS_U_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 757 */, - TILEPRO_OPC_SUBHS_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 760 */, - TILEPRO_OPC_PACKHS_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 763 */, - TILEPRO_OPC_PACKBS_U_SN, TILEPRO_OPC_NONE, - BITFIELD(37, 2) /* index 766 */, - TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, - CHILD(771), - BITFIELD(39, 2) /* index 771 */, - TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, - CHILD(776), - BITFIELD(41, 2) /* index 776 */, - TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, TILEPRO_OPC_ADDLI_SN, - TILEPRO_OPC_MOVELI_SN, - BITFIELD(37, 2) /* index 781 */, - TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, CHILD(786), - BITFIELD(39, 2) /* index 786 */, - TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, CHILD(791), - BITFIELD(41, 2) /* index 791 */, - TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_ADDLI, TILEPRO_OPC_MOVELI, - BITFIELD(31, 2) /* index 796 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(801), - BITFIELD(33, 2) /* index 801 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(806), - BITFIELD(35, 2) /* index 806 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(811), - BITFIELD(37, 2) /* index 811 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(816), - BITFIELD(39, 2) /* index 816 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, CHILD(821), - BITFIELD(41, 2) /* index 821 */, - TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_AULI, TILEPRO_OPC_INFOL, - BITFIELD(31, 4) /* index 826 */, - TILEPRO_OPC_BZ, TILEPRO_OPC_BZT, TILEPRO_OPC_BNZ, TILEPRO_OPC_BNZT, - TILEPRO_OPC_BGZ, TILEPRO_OPC_BGZT, TILEPRO_OPC_BGEZ, TILEPRO_OPC_BGEZT, - TILEPRO_OPC_BLZ, TILEPRO_OPC_BLZT, TILEPRO_OPC_BLEZ, TILEPRO_OPC_BLEZT, - TILEPRO_OPC_BBS, TILEPRO_OPC_BBST, TILEPRO_OPC_BBNS, TILEPRO_OPC_BBNST, - BITFIELD(31, 4) /* index 843 */, - TILEPRO_OPC_BZ_SN, TILEPRO_OPC_BZT_SN, TILEPRO_OPC_BNZ_SN, - TILEPRO_OPC_BNZT_SN, TILEPRO_OPC_BGZ_SN, TILEPRO_OPC_BGZT_SN, - TILEPRO_OPC_BGEZ_SN, TILEPRO_OPC_BGEZT_SN, TILEPRO_OPC_BLZ_SN, - TILEPRO_OPC_BLZT_SN, TILEPRO_OPC_BLEZ_SN, TILEPRO_OPC_BLEZT_SN, - TILEPRO_OPC_BBS_SN, TILEPRO_OPC_BBST_SN, TILEPRO_OPC_BBNS_SN, - TILEPRO_OPC_BBNST_SN, - BITFIELD(51, 3) /* index 860 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_ADDIB, TILEPRO_OPC_ADDIH, TILEPRO_OPC_ADDI, - CHILD(869), TILEPRO_OPC_MAXIB_U, TILEPRO_OPC_MAXIH, TILEPRO_OPC_MFSPR, - BITFIELD(31, 2) /* index 869 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(874), - BITFIELD(33, 2) /* index 874 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(879), - BITFIELD(35, 2) /* index 879 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(884), - BITFIELD(37, 2) /* index 884 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(889), - BITFIELD(39, 2) /* index 889 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(894), - BITFIELD(41, 2) /* index 894 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_INFO, - BITFIELD(51, 3) /* index 899 */, - TILEPRO_OPC_MINIB_U, TILEPRO_OPC_MINIH, TILEPRO_OPC_MTSPR, CHILD(908), - TILEPRO_OPC_SEQIB, TILEPRO_OPC_SEQIH, TILEPRO_OPC_SEQI, TILEPRO_OPC_SLTIB, - BITFIELD(37, 2) /* index 908 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(913), - BITFIELD(39, 2) /* index 913 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(918), - BITFIELD(41, 2) /* index 918 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_MOVEI, - BITFIELD(51, 3) /* index 923 */, - TILEPRO_OPC_SLTIB_U, TILEPRO_OPC_SLTIH, TILEPRO_OPC_SLTIH_U, - TILEPRO_OPC_SLTI, TILEPRO_OPC_SLTI_U, TILEPRO_OPC_XORI, TILEPRO_OPC_LBADD, - TILEPRO_OPC_LBADD_U, - BITFIELD(51, 3) /* index 932 */, - TILEPRO_OPC_LHADD, TILEPRO_OPC_LHADD_U, TILEPRO_OPC_LWADD, - TILEPRO_OPC_LWADD_NA, TILEPRO_OPC_SBADD, TILEPRO_OPC_SHADD, - TILEPRO_OPC_SWADD, TILEPRO_OPC_NONE, - BITFIELD(51, 3) /* index 941 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_ADDIB_SN, TILEPRO_OPC_ADDIH_SN, - TILEPRO_OPC_ADDI_SN, TILEPRO_OPC_ANDI_SN, TILEPRO_OPC_MAXIB_U_SN, - TILEPRO_OPC_MAXIH_SN, TILEPRO_OPC_MFSPR, - BITFIELD(51, 3) /* index 950 */, - TILEPRO_OPC_MINIB_U_SN, TILEPRO_OPC_MINIH_SN, TILEPRO_OPC_MTSPR, CHILD(959), - TILEPRO_OPC_SEQIB_SN, TILEPRO_OPC_SEQIH_SN, TILEPRO_OPC_SEQI_SN, - TILEPRO_OPC_SLTIB_SN, - BITFIELD(37, 2) /* index 959 */, - TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, CHILD(964), - BITFIELD(39, 2) /* index 964 */, - TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, CHILD(969), - BITFIELD(41, 2) /* index 969 */, - TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, TILEPRO_OPC_ORI_SN, - TILEPRO_OPC_MOVEI_SN, - BITFIELD(51, 3) /* index 974 */, - TILEPRO_OPC_SLTIB_U_SN, TILEPRO_OPC_SLTIH_SN, TILEPRO_OPC_SLTIH_U_SN, - TILEPRO_OPC_SLTI_SN, TILEPRO_OPC_SLTI_U_SN, TILEPRO_OPC_XORI_SN, - TILEPRO_OPC_LBADD_SN, TILEPRO_OPC_LBADD_U_SN, - BITFIELD(51, 3) /* index 983 */, - TILEPRO_OPC_LHADD_SN, TILEPRO_OPC_LHADD_U_SN, TILEPRO_OPC_LWADD_SN, - TILEPRO_OPC_LWADD_NA_SN, TILEPRO_OPC_SBADD, TILEPRO_OPC_SHADD, - TILEPRO_OPC_SWADD, TILEPRO_OPC_NONE, - BITFIELD(46, 7) /* index 992 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - CHILD(1121), CHILD(1121), CHILD(1121), CHILD(1121), CHILD(1124), - CHILD(1124), CHILD(1124), CHILD(1124), CHILD(1127), CHILD(1127), - CHILD(1127), CHILD(1127), CHILD(1130), CHILD(1130), CHILD(1130), - CHILD(1130), CHILD(1133), CHILD(1133), CHILD(1133), CHILD(1133), - CHILD(1136), CHILD(1136), CHILD(1136), CHILD(1136), CHILD(1139), - CHILD(1139), CHILD(1139), CHILD(1139), CHILD(1142), CHILD(1142), - CHILD(1142), CHILD(1142), CHILD(1145), CHILD(1145), CHILD(1145), - CHILD(1145), CHILD(1148), CHILD(1148), CHILD(1148), CHILD(1148), - CHILD(1151), CHILD(1242), CHILD(1290), CHILD(1323), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1121 */, - TILEPRO_OPC_RLI, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1124 */, - TILEPRO_OPC_SHLIB, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1127 */, - TILEPRO_OPC_SHLIH, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1130 */, - TILEPRO_OPC_SHLI, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1133 */, - TILEPRO_OPC_SHRIB, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1136 */, - TILEPRO_OPC_SHRIH, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1139 */, - TILEPRO_OPC_SHRI, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1142 */, - TILEPRO_OPC_SRAIB, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1145 */, - TILEPRO_OPC_SRAIH, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1148 */, - TILEPRO_OPC_SRAI, TILEPRO_OPC_NONE, - BITFIELD(43, 3) /* index 1151 */, - TILEPRO_OPC_NONE, CHILD(1160), CHILD(1163), CHILD(1166), CHILD(1169), - CHILD(1172), CHILD(1175), CHILD(1178), - BITFIELD(53, 1) /* index 1160 */, - TILEPRO_OPC_DRAIN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1163 */, - TILEPRO_OPC_DTLBPR, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1166 */, - TILEPRO_OPC_FINV, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1169 */, - TILEPRO_OPC_FLUSH, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1172 */, - TILEPRO_OPC_FNOP, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1175 */, - TILEPRO_OPC_ICOH, TILEPRO_OPC_NONE, - BITFIELD(31, 2) /* index 1178 */, - CHILD(1183), CHILD(1211), CHILD(1239), CHILD(1239), - BITFIELD(53, 1) /* index 1183 */, - CHILD(1186), TILEPRO_OPC_NONE, - BITFIELD(33, 2) /* index 1186 */, - TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, CHILD(1191), - BITFIELD(35, 2) /* index 1191 */, - TILEPRO_OPC_ILL, CHILD(1196), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, - BITFIELD(37, 2) /* index 1196 */, - TILEPRO_OPC_ILL, CHILD(1201), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, - BITFIELD(39, 2) /* index 1201 */, - TILEPRO_OPC_ILL, CHILD(1206), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, - BITFIELD(41, 2) /* index 1206 */, - TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, TILEPRO_OPC_BPT, TILEPRO_OPC_ILL, - BITFIELD(53, 1) /* index 1211 */, - CHILD(1214), TILEPRO_OPC_NONE, - BITFIELD(33, 2) /* index 1214 */, - TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, CHILD(1219), - BITFIELD(35, 2) /* index 1219 */, - TILEPRO_OPC_ILL, CHILD(1224), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, - BITFIELD(37, 2) /* index 1224 */, - TILEPRO_OPC_ILL, CHILD(1229), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, - BITFIELD(39, 2) /* index 1229 */, - TILEPRO_OPC_ILL, CHILD(1234), TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, - BITFIELD(41, 2) /* index 1234 */, - TILEPRO_OPC_ILL, TILEPRO_OPC_ILL, TILEPRO_OPC_RAISE, TILEPRO_OPC_ILL, - BITFIELD(53, 1) /* index 1239 */, - TILEPRO_OPC_ILL, TILEPRO_OPC_NONE, - BITFIELD(43, 3) /* index 1242 */, - CHILD(1251), CHILD(1254), CHILD(1257), CHILD(1275), CHILD(1278), - CHILD(1281), CHILD(1284), CHILD(1287), - BITFIELD(53, 1) /* index 1251 */, - TILEPRO_OPC_INV, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1254 */, - TILEPRO_OPC_IRET, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1257 */, - CHILD(1260), TILEPRO_OPC_NONE, - BITFIELD(31, 2) /* index 1260 */, - TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, CHILD(1265), - BITFIELD(33, 2) /* index 1265 */, - TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, CHILD(1270), - BITFIELD(35, 2) /* index 1270 */, - TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_PREFETCH, - BITFIELD(53, 1) /* index 1275 */, - TILEPRO_OPC_LB_U, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1278 */, - TILEPRO_OPC_LH, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1281 */, - TILEPRO_OPC_LH_U, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1284 */, - TILEPRO_OPC_LW, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1287 */, - TILEPRO_OPC_MF, TILEPRO_OPC_NONE, - BITFIELD(43, 3) /* index 1290 */, - CHILD(1299), CHILD(1302), CHILD(1305), CHILD(1308), CHILD(1311), - CHILD(1314), CHILD(1317), CHILD(1320), - BITFIELD(53, 1) /* index 1299 */, - TILEPRO_OPC_NAP, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1302 */, - TILEPRO_OPC_NOP, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1305 */, - TILEPRO_OPC_SWINT0, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1308 */, - TILEPRO_OPC_SWINT1, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1311 */, - TILEPRO_OPC_SWINT2, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1314 */, - TILEPRO_OPC_SWINT3, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1317 */, - TILEPRO_OPC_TNS, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1320 */, - TILEPRO_OPC_WH64, TILEPRO_OPC_NONE, - BITFIELD(43, 2) /* index 1323 */, - CHILD(1328), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(45, 1) /* index 1328 */, - CHILD(1331), TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1331 */, - TILEPRO_OPC_LW_NA, TILEPRO_OPC_NONE, - BITFIELD(46, 7) /* index 1334 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - CHILD(1463), CHILD(1463), CHILD(1463), CHILD(1463), CHILD(1466), - CHILD(1466), CHILD(1466), CHILD(1466), CHILD(1469), CHILD(1469), - CHILD(1469), CHILD(1469), CHILD(1472), CHILD(1472), CHILD(1472), - CHILD(1472), CHILD(1475), CHILD(1475), CHILD(1475), CHILD(1475), - CHILD(1478), CHILD(1478), CHILD(1478), CHILD(1478), CHILD(1481), - CHILD(1481), CHILD(1481), CHILD(1481), CHILD(1484), CHILD(1484), - CHILD(1484), CHILD(1484), CHILD(1487), CHILD(1487), CHILD(1487), - CHILD(1487), CHILD(1490), CHILD(1490), CHILD(1490), CHILD(1490), - CHILD(1151), CHILD(1493), CHILD(1517), CHILD(1529), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1463 */, - TILEPRO_OPC_RLI_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1466 */, - TILEPRO_OPC_SHLIB_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1469 */, - TILEPRO_OPC_SHLIH_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1472 */, - TILEPRO_OPC_SHLI_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1475 */, - TILEPRO_OPC_SHRIB_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1478 */, - TILEPRO_OPC_SHRIH_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1481 */, - TILEPRO_OPC_SHRI_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1484 */, - TILEPRO_OPC_SRAIB_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1487 */, - TILEPRO_OPC_SRAIH_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1490 */, - TILEPRO_OPC_SRAI_SN, TILEPRO_OPC_NONE, - BITFIELD(43, 3) /* index 1493 */, - CHILD(1251), CHILD(1254), CHILD(1502), CHILD(1505), CHILD(1508), - CHILD(1511), CHILD(1514), CHILD(1287), - BITFIELD(53, 1) /* index 1502 */, - TILEPRO_OPC_LB_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1505 */, - TILEPRO_OPC_LB_U_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1508 */, - TILEPRO_OPC_LH_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1511 */, - TILEPRO_OPC_LH_U_SN, TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1514 */, - TILEPRO_OPC_LW_SN, TILEPRO_OPC_NONE, - BITFIELD(43, 3) /* index 1517 */, - CHILD(1299), CHILD(1302), CHILD(1305), CHILD(1308), CHILD(1311), - CHILD(1314), CHILD(1526), CHILD(1320), - BITFIELD(53, 1) /* index 1526 */, - TILEPRO_OPC_TNS_SN, TILEPRO_OPC_NONE, - BITFIELD(43, 2) /* index 1529 */, - CHILD(1534), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(45, 1) /* index 1534 */, - CHILD(1537), TILEPRO_OPC_NONE, - BITFIELD(53, 1) /* index 1537 */, - TILEPRO_OPC_LW_NA_SN, TILEPRO_OPC_NONE, -}; - -static const unsigned short decode_Y0_fsm[168] = -{ - BITFIELD(27, 4) /* index 0 */, - TILEPRO_OPC_NONE, CHILD(17), CHILD(22), CHILD(27), CHILD(47), CHILD(52), - CHILD(57), CHILD(62), CHILD(67), TILEPRO_OPC_ADDI, CHILD(72), CHILD(102), - TILEPRO_OPC_SEQI, CHILD(117), TILEPRO_OPC_SLTI, TILEPRO_OPC_SLTI_U, - BITFIELD(18, 2) /* index 17 */, - TILEPRO_OPC_ADD, TILEPRO_OPC_S1A, TILEPRO_OPC_S2A, TILEPRO_OPC_SUB, - BITFIELD(18, 2) /* index 22 */, - TILEPRO_OPC_MNZ, TILEPRO_OPC_MVNZ, TILEPRO_OPC_MVZ, TILEPRO_OPC_MZ, - BITFIELD(18, 2) /* index 27 */, - TILEPRO_OPC_AND, TILEPRO_OPC_NOR, CHILD(32), TILEPRO_OPC_XOR, - BITFIELD(12, 2) /* index 32 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(37), - BITFIELD(14, 2) /* index 37 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(42), - BITFIELD(16, 2) /* index 42 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_MOVE, - BITFIELD(18, 2) /* index 47 */, - TILEPRO_OPC_RL, TILEPRO_OPC_SHL, TILEPRO_OPC_SHR, TILEPRO_OPC_SRA, - BITFIELD(18, 2) /* index 52 */, - TILEPRO_OPC_SLTE, TILEPRO_OPC_SLTE_U, TILEPRO_OPC_SLT, TILEPRO_OPC_SLT_U, - BITFIELD(18, 2) /* index 57 */, - TILEPRO_OPC_MULHLSA_UU, TILEPRO_OPC_S3A, TILEPRO_OPC_SEQ, TILEPRO_OPC_SNE, - BITFIELD(18, 2) /* index 62 */, - TILEPRO_OPC_MULHH_SS, TILEPRO_OPC_MULHH_UU, TILEPRO_OPC_MULLL_SS, - TILEPRO_OPC_MULLL_UU, - BITFIELD(18, 2) /* index 67 */, - TILEPRO_OPC_MULHHA_SS, TILEPRO_OPC_MULHHA_UU, TILEPRO_OPC_MULLLA_SS, - TILEPRO_OPC_MULLLA_UU, - BITFIELD(0, 2) /* index 72 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(77), - BITFIELD(2, 2) /* index 77 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(82), - BITFIELD(4, 2) /* index 82 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(87), - BITFIELD(6, 2) /* index 87 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(92), - BITFIELD(8, 2) /* index 92 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(97), - BITFIELD(10, 2) /* index 97 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_INFO, - BITFIELD(6, 2) /* index 102 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(107), - BITFIELD(8, 2) /* index 107 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(112), - BITFIELD(10, 2) /* index 112 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_MOVEI, - BITFIELD(15, 5) /* index 117 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_RLI, TILEPRO_OPC_RLI, TILEPRO_OPC_RLI, TILEPRO_OPC_RLI, - TILEPRO_OPC_SHLI, TILEPRO_OPC_SHLI, TILEPRO_OPC_SHLI, TILEPRO_OPC_SHLI, - TILEPRO_OPC_SHRI, TILEPRO_OPC_SHRI, TILEPRO_OPC_SHRI, TILEPRO_OPC_SHRI, - TILEPRO_OPC_SRAI, TILEPRO_OPC_SRAI, TILEPRO_OPC_SRAI, TILEPRO_OPC_SRAI, - CHILD(150), CHILD(159), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(12, 3) /* index 150 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_BITX, TILEPRO_OPC_BYTEX, TILEPRO_OPC_CLZ, - TILEPRO_OPC_CTZ, TILEPRO_OPC_FNOP, TILEPRO_OPC_NOP, TILEPRO_OPC_PCNT, - BITFIELD(12, 3) /* index 159 */, - TILEPRO_OPC_TBLIDXB0, TILEPRO_OPC_TBLIDXB1, TILEPRO_OPC_TBLIDXB2, - TILEPRO_OPC_TBLIDXB3, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, -}; - -static const unsigned short decode_Y1_fsm[140] = -{ - BITFIELD(59, 4) /* index 0 */, - TILEPRO_OPC_NONE, CHILD(17), CHILD(22), CHILD(27), CHILD(47), CHILD(52), - CHILD(57), TILEPRO_OPC_ADDI, CHILD(62), CHILD(92), TILEPRO_OPC_SEQI, - CHILD(107), TILEPRO_OPC_SLTI, TILEPRO_OPC_SLTI_U, TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, - BITFIELD(49, 2) /* index 17 */, - TILEPRO_OPC_ADD, TILEPRO_OPC_S1A, TILEPRO_OPC_S2A, TILEPRO_OPC_SUB, - BITFIELD(49, 2) /* index 22 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_MNZ, TILEPRO_OPC_MZ, TILEPRO_OPC_NONE, - BITFIELD(49, 2) /* index 27 */, - TILEPRO_OPC_AND, TILEPRO_OPC_NOR, CHILD(32), TILEPRO_OPC_XOR, - BITFIELD(43, 2) /* index 32 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(37), - BITFIELD(45, 2) /* index 37 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, CHILD(42), - BITFIELD(47, 2) /* index 42 */, - TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_OR, TILEPRO_OPC_MOVE, - BITFIELD(49, 2) /* index 47 */, - TILEPRO_OPC_RL, TILEPRO_OPC_SHL, TILEPRO_OPC_SHR, TILEPRO_OPC_SRA, - BITFIELD(49, 2) /* index 52 */, - TILEPRO_OPC_SLTE, TILEPRO_OPC_SLTE_U, TILEPRO_OPC_SLT, TILEPRO_OPC_SLT_U, - BITFIELD(49, 2) /* index 57 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_S3A, TILEPRO_OPC_SEQ, TILEPRO_OPC_SNE, - BITFIELD(31, 2) /* index 62 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(67), - BITFIELD(33, 2) /* index 67 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(72), - BITFIELD(35, 2) /* index 72 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(77), - BITFIELD(37, 2) /* index 77 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(82), - BITFIELD(39, 2) /* index 82 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, CHILD(87), - BITFIELD(41, 2) /* index 87 */, - TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_ANDI, TILEPRO_OPC_INFO, - BITFIELD(37, 2) /* index 92 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(97), - BITFIELD(39, 2) /* index 97 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, CHILD(102), - BITFIELD(41, 2) /* index 102 */, - TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_ORI, TILEPRO_OPC_MOVEI, - BITFIELD(48, 3) /* index 107 */, - TILEPRO_OPC_NONE, TILEPRO_OPC_RLI, TILEPRO_OPC_SHLI, TILEPRO_OPC_SHRI, - TILEPRO_OPC_SRAI, CHILD(116), TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(43, 3) /* index 116 */, - TILEPRO_OPC_NONE, CHILD(125), CHILD(130), CHILD(135), TILEPRO_OPC_NONE, - TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(46, 2) /* index 125 */, - TILEPRO_OPC_FNOP, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(46, 2) /* index 130 */, - TILEPRO_OPC_ILL, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, - BITFIELD(46, 2) /* index 135 */, - TILEPRO_OPC_NOP, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, TILEPRO_OPC_NONE, -}; - -static const unsigned short decode_Y2_fsm[24] = -{ - BITFIELD(56, 3) /* index 0 */, - CHILD(9), TILEPRO_OPC_LB_U, TILEPRO_OPC_LH, TILEPRO_OPC_LH_U, - TILEPRO_OPC_LW, TILEPRO_OPC_SB, TILEPRO_OPC_SH, TILEPRO_OPC_SW, - BITFIELD(20, 2) /* index 9 */, - TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, CHILD(14), - BITFIELD(22, 2) /* index 14 */, - TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, CHILD(19), - BITFIELD(24, 2) /* index 19 */, - TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_LB, TILEPRO_OPC_PREFETCH, -}; - -#undef BITFIELD -#undef CHILD -const unsigned short * const -tilepro_bundle_decoder_fsms[TILEPRO_NUM_PIPELINE_ENCODINGS] = -{ - decode_X0_fsm, - decode_X1_fsm, - decode_Y0_fsm, - decode_Y1_fsm, - decode_Y2_fsm -}; -const struct tilepro_operand tilepro_operands[43] = -{ - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM8_X0), - 8, 1, 0, 0, 0, 0, - create_Imm8_X0, get_Imm8_X0 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM8_X1), - 8, 1, 0, 0, 0, 0, - create_Imm8_X1, get_Imm8_X1 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM8_Y0), - 8, 1, 0, 0, 0, 0, - create_Imm8_Y0, get_Imm8_Y0 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM8_Y1), - 8, 1, 0, 0, 0, 0, - create_Imm8_Y1, get_Imm8_Y1 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM16_X0), - 16, 1, 0, 0, 0, 0, - create_Imm16_X0, get_Imm16_X0 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_IMM16_X1), - 16, 1, 0, 0, 0, 0, - create_Imm16_X1, get_Imm16_X1 - }, - { - TILEPRO_OP_TYPE_ADDRESS, BFD_RELOC(TILEPRO_JOFFLONG_X1), - 29, 1, 0, 0, 1, TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, - create_JOffLong_X1, get_JOffLong_X1 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 0, 1, 0, 0, - create_Dest_X0, get_Dest_X0 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcA_X0, get_SrcA_X0 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 0, 1, 0, 0, - create_Dest_X1, get_Dest_X1 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcA_X1, get_SrcA_X1 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 0, 1, 0, 0, - create_Dest_Y0, get_Dest_Y0 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcA_Y0, get_SrcA_Y0 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 0, 1, 0, 0, - create_Dest_Y1, get_Dest_Y1 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcA_Y1, get_SrcA_Y1 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcA_Y2, get_SrcA_Y2 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcB_X0, get_SrcB_X0 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcB_X1, get_SrcB_X1 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcB_Y0, get_SrcB_Y0 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcB_Y1, get_SrcB_Y1 - }, - { - TILEPRO_OP_TYPE_ADDRESS, BFD_RELOC(TILEPRO_BROFF_X1), - 17, 1, 0, 0, 1, TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, - create_BrOff_X1, get_BrOff_X1 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 1, 0, 0, - create_Dest_X0, get_Dest_X0 - }, - { - TILEPRO_OP_TYPE_ADDRESS, BFD_RELOC(NONE), - 28, 1, 0, 0, 1, TILEPRO_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, - create_JOff_X1, get_JOff_X1 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 0, 1, 0, 0, - create_SrcBDest_Y2, get_SrcBDest_Y2 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 1, 0, 0, - create_SrcA_X1, get_SrcA_X1 - }, - { - TILEPRO_OP_TYPE_SPR, BFD_RELOC(TILEPRO_MF_IMM15_X1), - 15, 0, 0, 0, 0, 0, - create_MF_Imm15_X1, get_MF_Imm15_X1 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_MMSTART_X0), - 5, 0, 0, 0, 0, 0, - create_MMStart_X0, get_MMStart_X0 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_MMEND_X0), - 5, 0, 0, 0, 0, 0, - create_MMEnd_X0, get_MMEnd_X0 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_MMSTART_X1), - 5, 0, 0, 0, 0, 0, - create_MMStart_X1, get_MMStart_X1 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_MMEND_X1), - 5, 0, 0, 0, 0, 0, - create_MMEnd_X1, get_MMEnd_X1 - }, - { - TILEPRO_OP_TYPE_SPR, BFD_RELOC(TILEPRO_MT_IMM15_X1), - 15, 0, 0, 0, 0, 0, - create_MT_Imm15_X1, get_MT_Imm15_X1 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 1, 0, 0, - create_Dest_Y0, get_Dest_Y0 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_SHAMT_X0), - 5, 0, 0, 0, 0, 0, - create_ShAmt_X0, get_ShAmt_X0 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_SHAMT_X1), - 5, 0, 0, 0, 0, 0, - create_ShAmt_X1, get_ShAmt_X1 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_SHAMT_Y0), - 5, 0, 0, 0, 0, 0, - create_ShAmt_Y0, get_ShAmt_Y0 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_SHAMT_Y1), - 5, 0, 0, 0, 0, 0, - create_ShAmt_Y1, get_ShAmt_Y1 - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcBDest_Y2, get_SrcBDest_Y2 - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEPRO_DEST_IMM8_X1), - 8, 1, 0, 0, 0, 0, - create_Dest_Imm8_X1, get_Dest_Imm8_X1 - }, - { - TILEPRO_OP_TYPE_ADDRESS, BFD_RELOC(NONE), - 10, 1, 0, 0, 1, TILEPRO_LOG2_SN_INSTRUCTION_SIZE_IN_BYTES, - create_BrOff_SN, get_BrOff_SN - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE), - 8, 0, 0, 0, 0, 0, - create_Imm8_SN, get_Imm8_SN - }, - { - TILEPRO_OP_TYPE_IMMEDIATE, BFD_RELOC(NONE), - 8, 1, 0, 0, 0, 0, - create_Imm8_SN, get_Imm8_SN - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 2, 0, 0, 1, 0, 0, - create_Dest_SN, get_Dest_SN - }, - { - TILEPRO_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 2, 0, 1, 0, 0, 0, - create_Src_SN, get_Src_SN - } -}; - - - - -/* Given a set of bundle bits and a specific pipe, returns which - * instruction the bundle contains in that pipe. - */ -const struct tilepro_opcode * -find_opcode(tilepro_bundle_bits bits, tilepro_pipeline pipe) -{ - const unsigned short *table = tilepro_bundle_decoder_fsms[pipe]; - int index = 0; - - while (1) - { - unsigned short bitspec = table[index]; - unsigned int bitfield = - ((unsigned int)(bits >> (bitspec & 63))) & (bitspec >> 6); - - unsigned short next = table[index + 1 + bitfield]; - if (next <= TILEPRO_OPC_NONE) - return &tilepro_opcodes[next]; - - index = next - TILEPRO_OPC_NONE; - } -} - - -int -parse_insn_tilepro(tilepro_bundle_bits bits, - unsigned int pc, - struct tilepro_decoded_instruction - decoded[TILEPRO_MAX_INSTRUCTIONS_PER_BUNDLE]) -{ - int num_instructions = 0; - int pipe; - - int min_pipe, max_pipe; - if ((bits & TILEPRO_BUNDLE_Y_ENCODING_MASK) == 0) - { - min_pipe = TILEPRO_PIPELINE_X0; - max_pipe = TILEPRO_PIPELINE_X1; - } - else - { - min_pipe = TILEPRO_PIPELINE_Y0; - max_pipe = TILEPRO_PIPELINE_Y2; - } - - /* For each pipe, find an instruction that fits. */ - for (pipe = min_pipe; pipe <= max_pipe; pipe++) - { - const struct tilepro_opcode *opc; - struct tilepro_decoded_instruction *d; - int i; - - d = &decoded[num_instructions++]; - opc = find_opcode (bits, (tilepro_pipeline)pipe); - d->opcode = opc; - - /* Decode each operand, sign extending, etc. as appropriate. */ - for (i = 0; i < opc->num_operands; i++) - { - const struct tilepro_operand *op = - &tilepro_operands[opc->operands[pipe][i]]; - int opval = op->extract (bits); - if (op->is_signed) - { - /* Sign-extend the operand. */ - int shift = (int)((sizeof(int) * 8) - op->num_bits); - opval = (opval << shift) >> shift; - } - - /* Adjust PC-relative scaled branch offsets. */ - if (op->type == TILEPRO_OP_TYPE_ADDRESS) - { - opval *= TILEPRO_BUNDLE_SIZE_IN_BYTES; - opval += (int)pc; - } - - /* Record the final value. */ - d->operands[i] = op; - d->operand_values[i] = opval; - } - } - - return num_instructions; -} diff --git a/arch/tile/kernel/tile-desc_64.c b/arch/tile/kernel/tile-desc_64.c deleted file mode 100644 index 65b5f8aca706..000000000000 --- a/arch/tile/kernel/tile-desc_64.c +++ /dev/null @@ -1,2218 +0,0 @@ -/* TILE-Gx opcode information. - * - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * - * - * - * - */ - -/* This define is BFD_RELOC_##x for real bfd, or -1 for everyone else. */ -#define BFD_RELOC(x) -1 - -/* Special registers. */ -#define TREG_LR 55 -#define TREG_SN 56 -#define TREG_ZERO 63 - -#include -#include - -const struct tilegx_opcode tilegx_opcodes[334] = -{ - { "bpt", TILEGX_OPC_BPT, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "info", TILEGX_OPC_INFO, 0xf, 1, TREG_ZERO, 1, - { { 0 }, { 1 }, { 2 }, { 3 }, { 0, } }, - }, - { "infol", TILEGX_OPC_INFOL, 0x3, 1, TREG_ZERO, 1, - { { 4 }, { 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "move", TILEGX_OPC_MOVE, 0xf, 2, TREG_ZERO, 1, - { { 6, 7 }, { 8, 9 }, { 10, 11 }, { 12, 13 }, { 0, } }, - }, - { "movei", TILEGX_OPC_MOVEI, 0xf, 2, TREG_ZERO, 1, - { { 6, 0 }, { 8, 1 }, { 10, 2 }, { 12, 3 }, { 0, } }, - }, - { "moveli", TILEGX_OPC_MOVELI, 0x3, 2, TREG_ZERO, 1, - { { 6, 4 }, { 8, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "prefetch", TILEGX_OPC_PREFETCH, 0x12, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } }, - }, - { "prefetch_add_l1", TILEGX_OPC_PREFETCH_ADD_L1, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "prefetch_add_l1_fault", TILEGX_OPC_PREFETCH_ADD_L1_FAULT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "prefetch_add_l2", TILEGX_OPC_PREFETCH_ADD_L2, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "prefetch_add_l2_fault", TILEGX_OPC_PREFETCH_ADD_L2_FAULT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "prefetch_add_l3", TILEGX_OPC_PREFETCH_ADD_L3, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "prefetch_add_l3_fault", TILEGX_OPC_PREFETCH_ADD_L3_FAULT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "prefetch_l1", TILEGX_OPC_PREFETCH_L1, 0x12, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } }, - }, - { "prefetch_l1_fault", TILEGX_OPC_PREFETCH_L1_FAULT, 0x12, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } }, - }, - { "prefetch_l2", TILEGX_OPC_PREFETCH_L2, 0x12, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } }, - }, - { "prefetch_l2_fault", TILEGX_OPC_PREFETCH_L2_FAULT, 0x12, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } }, - }, - { "prefetch_l3", TILEGX_OPC_PREFETCH_L3, 0x12, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } }, - }, - { "prefetch_l3_fault", TILEGX_OPC_PREFETCH_L3_FAULT, 0x12, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 14 } }, - }, - { "raise", TILEGX_OPC_RAISE, 0x2, 0, TREG_ZERO, 1, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "add", TILEGX_OPC_ADD, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "addi", TILEGX_OPC_ADDI, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } }, - }, - { "addli", TILEGX_OPC_ADDLI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "addx", TILEGX_OPC_ADDX, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "addxi", TILEGX_OPC_ADDXI, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } }, - }, - { "addxli", TILEGX_OPC_ADDXLI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "addxsc", TILEGX_OPC_ADDXSC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "and", TILEGX_OPC_AND, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "andi", TILEGX_OPC_ANDI, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } }, - }, - { "beqz", TILEGX_OPC_BEQZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "beqzt", TILEGX_OPC_BEQZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bfexts", TILEGX_OPC_BFEXTS, 0x1, 4, TREG_ZERO, 1, - { { 6, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "bfextu", TILEGX_OPC_BFEXTU, 0x1, 4, TREG_ZERO, 1, - { { 6, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "bfins", TILEGX_OPC_BFINS, 0x1, 4, TREG_ZERO, 1, - { { 23, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "bgez", TILEGX_OPC_BGEZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgezt", TILEGX_OPC_BGEZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgtz", TILEGX_OPC_BGTZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bgtzt", TILEGX_OPC_BGTZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blbc", TILEGX_OPC_BLBC, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blbct", TILEGX_OPC_BLBCT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blbs", TILEGX_OPC_BLBS, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blbst", TILEGX_OPC_BLBST, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blez", TILEGX_OPC_BLEZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "blezt", TILEGX_OPC_BLEZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bltz", TILEGX_OPC_BLTZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bltzt", TILEGX_OPC_BLTZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bnez", TILEGX_OPC_BNEZ, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "bnezt", TILEGX_OPC_BNEZT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 20 }, { 0, }, { 0, }, { 0, } }, - }, - { "clz", TILEGX_OPC_CLZ, 0x5, 2, TREG_ZERO, 1, - { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } }, - }, - { "cmoveqz", TILEGX_OPC_CMOVEQZ, 0x5, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } }, - }, - { "cmovnez", TILEGX_OPC_CMOVNEZ, 0x5, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } }, - }, - { "cmpeq", TILEGX_OPC_CMPEQ, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "cmpeqi", TILEGX_OPC_CMPEQI, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } }, - }, - { "cmpexch", TILEGX_OPC_CMPEXCH, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "cmpexch4", TILEGX_OPC_CMPEXCH4, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "cmples", TILEGX_OPC_CMPLES, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "cmpleu", TILEGX_OPC_CMPLEU, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "cmplts", TILEGX_OPC_CMPLTS, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "cmpltsi", TILEGX_OPC_CMPLTSI, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 10, 11, 2 }, { 12, 13, 3 }, { 0, } }, - }, - { "cmpltu", TILEGX_OPC_CMPLTU, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "cmpltui", TILEGX_OPC_CMPLTUI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "cmpne", TILEGX_OPC_CMPNE, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "cmul", TILEGX_OPC_CMUL, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "cmula", TILEGX_OPC_CMULA, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "cmulaf", TILEGX_OPC_CMULAF, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "cmulf", TILEGX_OPC_CMULF, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "cmulfr", TILEGX_OPC_CMULFR, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "cmulh", TILEGX_OPC_CMULH, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "cmulhr", TILEGX_OPC_CMULHR, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "crc32_32", TILEGX_OPC_CRC32_32, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "crc32_8", TILEGX_OPC_CRC32_8, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "ctz", TILEGX_OPC_CTZ, 0x5, 2, TREG_ZERO, 1, - { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } }, - }, - { "dblalign", TILEGX_OPC_DBLALIGN, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "dblalign2", TILEGX_OPC_DBLALIGN2, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "dblalign4", TILEGX_OPC_DBLALIGN4, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "dblalign6", TILEGX_OPC_DBLALIGN6, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "drain", TILEGX_OPC_DRAIN, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "dtlbpr", TILEGX_OPC_DTLBPR, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "exch", TILEGX_OPC_EXCH, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "exch4", TILEGX_OPC_EXCH4, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "fdouble_add_flags", TILEGX_OPC_FDOUBLE_ADD_FLAGS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fdouble_addsub", TILEGX_OPC_FDOUBLE_ADDSUB, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fdouble_mul_flags", TILEGX_OPC_FDOUBLE_MUL_FLAGS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fdouble_pack1", TILEGX_OPC_FDOUBLE_PACK1, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fdouble_pack2", TILEGX_OPC_FDOUBLE_PACK2, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fdouble_sub_flags", TILEGX_OPC_FDOUBLE_SUB_FLAGS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fdouble_unpack_max", TILEGX_OPC_FDOUBLE_UNPACK_MAX, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fdouble_unpack_min", TILEGX_OPC_FDOUBLE_UNPACK_MIN, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fetchadd", TILEGX_OPC_FETCHADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "fetchadd4", TILEGX_OPC_FETCHADD4, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "fetchaddgez", TILEGX_OPC_FETCHADDGEZ, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "fetchaddgez4", TILEGX_OPC_FETCHADDGEZ4, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "fetchand", TILEGX_OPC_FETCHAND, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "fetchand4", TILEGX_OPC_FETCHAND4, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "fetchor", TILEGX_OPC_FETCHOR, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "fetchor4", TILEGX_OPC_FETCHOR4, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "finv", TILEGX_OPC_FINV, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "flush", TILEGX_OPC_FLUSH, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "flushwb", TILEGX_OPC_FLUSHWB, 0x2, 0, TREG_ZERO, 1, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "fnop", TILEGX_OPC_FNOP, 0xf, 0, TREG_ZERO, 1, - { { }, { }, { }, { }, { 0, } }, - }, - { "fsingle_add1", TILEGX_OPC_FSINGLE_ADD1, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fsingle_addsub2", TILEGX_OPC_FSINGLE_ADDSUB2, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fsingle_mul1", TILEGX_OPC_FSINGLE_MUL1, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fsingle_mul2", TILEGX_OPC_FSINGLE_MUL2, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fsingle_pack1", TILEGX_OPC_FSINGLE_PACK1, 0x5, 2, TREG_ZERO, 1, - { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } }, - }, - { "fsingle_pack2", TILEGX_OPC_FSINGLE_PACK2, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "fsingle_sub1", TILEGX_OPC_FSINGLE_SUB1, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "icoh", TILEGX_OPC_ICOH, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "ill", TILEGX_OPC_ILL, 0xa, 0, TREG_ZERO, 1, - { { 0, }, { }, { 0, }, { }, { 0, } }, - }, - { "inv", TILEGX_OPC_INV, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "iret", TILEGX_OPC_IRET, 0x2, 0, TREG_ZERO, 1, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "j", TILEGX_OPC_J, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 25 }, { 0, }, { 0, }, { 0, } }, - }, - { "jal", TILEGX_OPC_JAL, 0x2, 1, TREG_LR, 1, - { { 0, }, { 25 }, { 0, }, { 0, }, { 0, } }, - }, - { "jalr", TILEGX_OPC_JALR, 0xa, 1, TREG_LR, 1, - { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } }, - }, - { "jalrp", TILEGX_OPC_JALRP, 0xa, 1, TREG_LR, 1, - { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } }, - }, - { "jr", TILEGX_OPC_JR, 0xa, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } }, - }, - { "jrp", TILEGX_OPC_JRP, 0xa, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 13 }, { 0, } }, - }, - { "ld", TILEGX_OPC_LD, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } }, - }, - { "ld1s", TILEGX_OPC_LD1S, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } }, - }, - { "ld1s_add", TILEGX_OPC_LD1S_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ld1u", TILEGX_OPC_LD1U, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } }, - }, - { "ld1u_add", TILEGX_OPC_LD1U_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ld2s", TILEGX_OPC_LD2S, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } }, - }, - { "ld2s_add", TILEGX_OPC_LD2S_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ld2u", TILEGX_OPC_LD2U, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } }, - }, - { "ld2u_add", TILEGX_OPC_LD2U_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ld4s", TILEGX_OPC_LD4S, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } }, - }, - { "ld4s_add", TILEGX_OPC_LD4S_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ld4u", TILEGX_OPC_LD4U, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 26, 14 } }, - }, - { "ld4u_add", TILEGX_OPC_LD4U_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ld_add", TILEGX_OPC_LD_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldna", TILEGX_OPC_LDNA, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldna_add", TILEGX_OPC_LDNA_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt", TILEGX_OPC_LDNT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt1s", TILEGX_OPC_LDNT1S, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt1s_add", TILEGX_OPC_LDNT1S_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt1u", TILEGX_OPC_LDNT1U, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt1u_add", TILEGX_OPC_LDNT1U_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt2s", TILEGX_OPC_LDNT2S, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt2s_add", TILEGX_OPC_LDNT2S_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt2u", TILEGX_OPC_LDNT2U, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt2u_add", TILEGX_OPC_LDNT2U_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt4s", TILEGX_OPC_LDNT4S, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt4s_add", TILEGX_OPC_LDNT4S_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt4u", TILEGX_OPC_LDNT4U, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 8, 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt4u_add", TILEGX_OPC_LDNT4U_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "ldnt_add", TILEGX_OPC_LDNT_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 8, 15, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "lnk", TILEGX_OPC_LNK, 0xa, 1, TREG_ZERO, 1, - { { 0, }, { 8 }, { 0, }, { 12 }, { 0, } }, - }, - { "mf", TILEGX_OPC_MF, 0x2, 0, TREG_ZERO, 1, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "mfspr", TILEGX_OPC_MFSPR, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 8, 27 }, { 0, }, { 0, }, { 0, } }, - }, - { "mm", TILEGX_OPC_MM, 0x1, 4, TREG_ZERO, 1, - { { 23, 7, 21, 22 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mnz", TILEGX_OPC_MNZ, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "mtspr", TILEGX_OPC_MTSPR, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 28, 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "mul_hs_hs", TILEGX_OPC_MUL_HS_HS, 0x5, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } }, - }, - { "mul_hs_hu", TILEGX_OPC_MUL_HS_HU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mul_hs_ls", TILEGX_OPC_MUL_HS_LS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mul_hs_lu", TILEGX_OPC_MUL_HS_LU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mul_hu_hu", TILEGX_OPC_MUL_HU_HU, 0x5, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } }, - }, - { "mul_hu_ls", TILEGX_OPC_MUL_HU_LS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mul_hu_lu", TILEGX_OPC_MUL_HU_LU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mul_ls_ls", TILEGX_OPC_MUL_LS_LS, 0x5, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } }, - }, - { "mul_ls_lu", TILEGX_OPC_MUL_LS_LU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mul_lu_lu", TILEGX_OPC_MUL_LU_LU, 0x5, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } }, - }, - { "mula_hs_hs", TILEGX_OPC_MULA_HS_HS, 0x5, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } }, - }, - { "mula_hs_hu", TILEGX_OPC_MULA_HS_HU, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mula_hs_ls", TILEGX_OPC_MULA_HS_LS, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mula_hs_lu", TILEGX_OPC_MULA_HS_LU, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mula_hu_hu", TILEGX_OPC_MULA_HU_HU, 0x5, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } }, - }, - { "mula_hu_ls", TILEGX_OPC_MULA_HU_LS, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mula_hu_lu", TILEGX_OPC_MULA_HU_LU, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mula_ls_ls", TILEGX_OPC_MULA_LS_LS, 0x5, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } }, - }, - { "mula_ls_lu", TILEGX_OPC_MULA_LS_LU, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "mula_lu_lu", TILEGX_OPC_MULA_LU_LU, 0x5, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } }, - }, - { "mulax", TILEGX_OPC_MULAX, 0x5, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 24, 11, 18 }, { 0, }, { 0, } }, - }, - { "mulx", TILEGX_OPC_MULX, 0x5, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 10, 11, 18 }, { 0, }, { 0, } }, - }, - { "mz", TILEGX_OPC_MZ, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "nap", TILEGX_OPC_NAP, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "nop", TILEGX_OPC_NOP, 0xf, 0, TREG_ZERO, 1, - { { }, { }, { }, { }, { 0, } }, - }, - { "nor", TILEGX_OPC_NOR, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "or", TILEGX_OPC_OR, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "ori", TILEGX_OPC_ORI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "pcnt", TILEGX_OPC_PCNT, 0x5, 2, TREG_ZERO, 1, - { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } }, - }, - { "revbits", TILEGX_OPC_REVBITS, 0x5, 2, TREG_ZERO, 1, - { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } }, - }, - { "revbytes", TILEGX_OPC_REVBYTES, 0x5, 2, TREG_ZERO, 1, - { { 6, 7 }, { 0, }, { 10, 11 }, { 0, }, { 0, } }, - }, - { "rotl", TILEGX_OPC_ROTL, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "rotli", TILEGX_OPC_ROTLI, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } }, - }, - { "shl", TILEGX_OPC_SHL, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "shl16insli", TILEGX_OPC_SHL16INSLI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 4 }, { 8, 9, 5 }, { 0, }, { 0, }, { 0, } }, - }, - { "shl1add", TILEGX_OPC_SHL1ADD, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "shl1addx", TILEGX_OPC_SHL1ADDX, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "shl2add", TILEGX_OPC_SHL2ADD, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "shl2addx", TILEGX_OPC_SHL2ADDX, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "shl3add", TILEGX_OPC_SHL3ADD, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "shl3addx", TILEGX_OPC_SHL3ADDX, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "shli", TILEGX_OPC_SHLI, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } }, - }, - { "shlx", TILEGX_OPC_SHLX, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shlxi", TILEGX_OPC_SHLXI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } }, - }, - { "shrs", TILEGX_OPC_SHRS, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "shrsi", TILEGX_OPC_SHRSI, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } }, - }, - { "shru", TILEGX_OPC_SHRU, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "shrui", TILEGX_OPC_SHRUI, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 10, 11, 31 }, { 12, 13, 32 }, { 0, } }, - }, - { "shrux", TILEGX_OPC_SHRUX, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "shruxi", TILEGX_OPC_SHRUXI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } }, - }, - { "shufflebytes", TILEGX_OPC_SHUFFLEBYTES, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "st", TILEGX_OPC_ST, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } }, - }, - { "st1", TILEGX_OPC_ST1, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } }, - }, - { "st1_add", TILEGX_OPC_ST1_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } }, - }, - { "st2", TILEGX_OPC_ST2, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } }, - }, - { "st2_add", TILEGX_OPC_ST2_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } }, - }, - { "st4", TILEGX_OPC_ST4, 0x12, 2, TREG_ZERO, 1, - { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 14, 33 } }, - }, - { "st4_add", TILEGX_OPC_ST4_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } }, - }, - { "st_add", TILEGX_OPC_ST_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } }, - }, - { "stnt", TILEGX_OPC_STNT, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "stnt1", TILEGX_OPC_STNT1, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "stnt1_add", TILEGX_OPC_STNT1_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } }, - }, - { "stnt2", TILEGX_OPC_STNT2, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "stnt2_add", TILEGX_OPC_STNT2_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } }, - }, - { "stnt4", TILEGX_OPC_STNT4, 0x2, 2, TREG_ZERO, 1, - { { 0, }, { 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "stnt4_add", TILEGX_OPC_STNT4_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } }, - }, - { "stnt_add", TILEGX_OPC_STNT_ADD, 0x2, 3, TREG_ZERO, 1, - { { 0, }, { 15, 17, 34 }, { 0, }, { 0, }, { 0, } }, - }, - { "sub", TILEGX_OPC_SUB, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "subx", TILEGX_OPC_SUBX, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "subxsc", TILEGX_OPC_SUBXSC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "swint0", TILEGX_OPC_SWINT0, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "swint1", TILEGX_OPC_SWINT1, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "swint2", TILEGX_OPC_SWINT2, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "swint3", TILEGX_OPC_SWINT3, 0x2, 0, TREG_ZERO, 0, - { { 0, }, { }, { 0, }, { 0, }, { 0, } }, - }, - { "tblidxb0", TILEGX_OPC_TBLIDXB0, 0x5, 2, TREG_ZERO, 1, - { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } }, - }, - { "tblidxb1", TILEGX_OPC_TBLIDXB1, 0x5, 2, TREG_ZERO, 1, - { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } }, - }, - { "tblidxb2", TILEGX_OPC_TBLIDXB2, 0x5, 2, TREG_ZERO, 1, - { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } }, - }, - { "tblidxb3", TILEGX_OPC_TBLIDXB3, 0x5, 2, TREG_ZERO, 1, - { { 23, 7 }, { 0, }, { 24, 11 }, { 0, }, { 0, } }, - }, - { "v1add", TILEGX_OPC_V1ADD, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1addi", TILEGX_OPC_V1ADDI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1adduc", TILEGX_OPC_V1ADDUC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1adiffu", TILEGX_OPC_V1ADIFFU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1avgu", TILEGX_OPC_V1AVGU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1cmpeq", TILEGX_OPC_V1CMPEQ, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1cmpeqi", TILEGX_OPC_V1CMPEQI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1cmples", TILEGX_OPC_V1CMPLES, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1cmpleu", TILEGX_OPC_V1CMPLEU, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1cmplts", TILEGX_OPC_V1CMPLTS, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1cmpltsi", TILEGX_OPC_V1CMPLTSI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1cmpltu", TILEGX_OPC_V1CMPLTU, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1cmpltui", TILEGX_OPC_V1CMPLTUI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1cmpne", TILEGX_OPC_V1CMPNE, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1ddotpu", TILEGX_OPC_V1DDOTPU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1ddotpua", TILEGX_OPC_V1DDOTPUA, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1ddotpus", TILEGX_OPC_V1DDOTPUS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1ddotpusa", TILEGX_OPC_V1DDOTPUSA, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1dotp", TILEGX_OPC_V1DOTP, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1dotpa", TILEGX_OPC_V1DOTPA, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1dotpu", TILEGX_OPC_V1DOTPU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1dotpua", TILEGX_OPC_V1DOTPUA, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1dotpus", TILEGX_OPC_V1DOTPUS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1dotpusa", TILEGX_OPC_V1DOTPUSA, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1int_h", TILEGX_OPC_V1INT_H, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1int_l", TILEGX_OPC_V1INT_L, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1maxu", TILEGX_OPC_V1MAXU, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1maxui", TILEGX_OPC_V1MAXUI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1minu", TILEGX_OPC_V1MINU, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1minui", TILEGX_OPC_V1MINUI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1mnz", TILEGX_OPC_V1MNZ, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1multu", TILEGX_OPC_V1MULTU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1mulu", TILEGX_OPC_V1MULU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1mulus", TILEGX_OPC_V1MULUS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1mz", TILEGX_OPC_V1MZ, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1sadau", TILEGX_OPC_V1SADAU, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1sadu", TILEGX_OPC_V1SADU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v1shl", TILEGX_OPC_V1SHL, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1shli", TILEGX_OPC_V1SHLI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1shrs", TILEGX_OPC_V1SHRS, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1shrsi", TILEGX_OPC_V1SHRSI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1shru", TILEGX_OPC_V1SHRU, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1shrui", TILEGX_OPC_V1SHRUI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1sub", TILEGX_OPC_V1SUB, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v1subuc", TILEGX_OPC_V1SUBUC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2add", TILEGX_OPC_V2ADD, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2addi", TILEGX_OPC_V2ADDI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2addsc", TILEGX_OPC_V2ADDSC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2adiffs", TILEGX_OPC_V2ADIFFS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2avgs", TILEGX_OPC_V2AVGS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2cmpeq", TILEGX_OPC_V2CMPEQ, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2cmpeqi", TILEGX_OPC_V2CMPEQI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2cmples", TILEGX_OPC_V2CMPLES, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2cmpleu", TILEGX_OPC_V2CMPLEU, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2cmplts", TILEGX_OPC_V2CMPLTS, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2cmpltsi", TILEGX_OPC_V2CMPLTSI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2cmpltu", TILEGX_OPC_V2CMPLTU, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2cmpltui", TILEGX_OPC_V2CMPLTUI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2cmpne", TILEGX_OPC_V2CMPNE, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2dotp", TILEGX_OPC_V2DOTP, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2dotpa", TILEGX_OPC_V2DOTPA, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2int_h", TILEGX_OPC_V2INT_H, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2int_l", TILEGX_OPC_V2INT_L, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2maxs", TILEGX_OPC_V2MAXS, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2maxsi", TILEGX_OPC_V2MAXSI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2mins", TILEGX_OPC_V2MINS, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2minsi", TILEGX_OPC_V2MINSI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2mnz", TILEGX_OPC_V2MNZ, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2mulfsc", TILEGX_OPC_V2MULFSC, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2muls", TILEGX_OPC_V2MULS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2mults", TILEGX_OPC_V2MULTS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2mz", TILEGX_OPC_V2MZ, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2packh", TILEGX_OPC_V2PACKH, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2packl", TILEGX_OPC_V2PACKL, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2packuc", TILEGX_OPC_V2PACKUC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2sadas", TILEGX_OPC_V2SADAS, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2sadau", TILEGX_OPC_V2SADAU, 0x1, 3, TREG_ZERO, 1, - { { 23, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2sads", TILEGX_OPC_V2SADS, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2sadu", TILEGX_OPC_V2SADU, 0x1, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 0, }, { 0, }, { 0, }, { 0, } }, - }, - { "v2shl", TILEGX_OPC_V2SHL, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2shli", TILEGX_OPC_V2SHLI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2shlsc", TILEGX_OPC_V2SHLSC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2shrs", TILEGX_OPC_V2SHRS, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2shrsi", TILEGX_OPC_V2SHRSI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2shru", TILEGX_OPC_V2SHRU, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2shrui", TILEGX_OPC_V2SHRUI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 29 }, { 8, 9, 30 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2sub", TILEGX_OPC_V2SUB, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v2subsc", TILEGX_OPC_V2SUBSC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4add", TILEGX_OPC_V4ADD, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4addsc", TILEGX_OPC_V4ADDSC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4int_h", TILEGX_OPC_V4INT_H, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4int_l", TILEGX_OPC_V4INT_L, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4packsc", TILEGX_OPC_V4PACKSC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4shl", TILEGX_OPC_V4SHL, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4shlsc", TILEGX_OPC_V4SHLSC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4shrs", TILEGX_OPC_V4SHRS, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4shru", TILEGX_OPC_V4SHRU, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4sub", TILEGX_OPC_V4SUB, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "v4subsc", TILEGX_OPC_V4SUBSC, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 0, }, { 0, }, { 0, } }, - }, - { "wh64", TILEGX_OPC_WH64, 0x2, 1, TREG_ZERO, 1, - { { 0, }, { 9 }, { 0, }, { 0, }, { 0, } }, - }, - { "xor", TILEGX_OPC_XOR, 0xf, 3, TREG_ZERO, 1, - { { 6, 7, 16 }, { 8, 9, 17 }, { 10, 11, 18 }, { 12, 13, 19 }, { 0, } }, - }, - { "xori", TILEGX_OPC_XORI, 0x3, 3, TREG_ZERO, 1, - { { 6, 7, 0 }, { 8, 9, 1 }, { 0, }, { 0, }, { 0, } }, - }, - { NULL, TILEGX_OPC_NONE, 0, 0, TREG_ZERO, 0, { { 0, } }, - } -}; -#define BITFIELD(start, size) ((start) | (((1 << (size)) - 1) << 6)) -#define CHILD(array_index) (TILEGX_OPC_NONE + (array_index)) - -static const unsigned short decode_X0_fsm[936] = -{ - BITFIELD(22, 9) /* index 0 */, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_BFEXTS, - TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTS, TILEGX_OPC_BFEXTU, - TILEGX_OPC_BFEXTU, TILEGX_OPC_BFEXTU, TILEGX_OPC_BFEXTU, TILEGX_OPC_BFINS, - TILEGX_OPC_BFINS, TILEGX_OPC_BFINS, TILEGX_OPC_BFINS, TILEGX_OPC_MM, - TILEGX_OPC_MM, TILEGX_OPC_MM, TILEGX_OPC_MM, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(528), CHILD(578), - CHILD(583), CHILD(588), CHILD(593), CHILD(598), TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, CHILD(603), CHILD(620), CHILD(637), CHILD(654), CHILD(671), - CHILD(703), CHILD(797), CHILD(814), CHILD(831), CHILD(848), CHILD(865), - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, CHILD(889), TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - CHILD(906), CHILD(906), CHILD(906), CHILD(906), CHILD(906), - BITFIELD(6, 2) /* index 513 */, - TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(518), - BITFIELD(8, 2) /* index 518 */, - TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(523), - BITFIELD(10, 2) /* index 523 */, - TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_MOVELI, - BITFIELD(20, 2) /* index 528 */, - TILEGX_OPC_NONE, CHILD(533), TILEGX_OPC_ADDXI, CHILD(548), - BITFIELD(6, 2) /* index 533 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(538), - BITFIELD(8, 2) /* index 538 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(543), - BITFIELD(10, 2) /* index 543 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI, - BITFIELD(0, 2) /* index 548 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(553), - BITFIELD(2, 2) /* index 553 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(558), - BITFIELD(4, 2) /* index 558 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(563), - BITFIELD(6, 2) /* index 563 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(568), - BITFIELD(8, 2) /* index 568 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(573), - BITFIELD(10, 2) /* index 573 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO, - BITFIELD(20, 2) /* index 578 */, - TILEGX_OPC_CMPEQI, TILEGX_OPC_CMPLTSI, TILEGX_OPC_CMPLTUI, TILEGX_OPC_ORI, - BITFIELD(20, 2) /* index 583 */, - TILEGX_OPC_V1ADDI, TILEGX_OPC_V1CMPEQI, TILEGX_OPC_V1CMPLTSI, - TILEGX_OPC_V1CMPLTUI, - BITFIELD(20, 2) /* index 588 */, - TILEGX_OPC_V1MAXUI, TILEGX_OPC_V1MINUI, TILEGX_OPC_V2ADDI, - TILEGX_OPC_V2CMPEQI, - BITFIELD(20, 2) /* index 593 */, - TILEGX_OPC_V2CMPLTSI, TILEGX_OPC_V2CMPLTUI, TILEGX_OPC_V2MAXSI, - TILEGX_OPC_V2MINSI, - BITFIELD(20, 2) /* index 598 */, - TILEGX_OPC_XORI, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(18, 4) /* index 603 */, - TILEGX_OPC_NONE, TILEGX_OPC_ADDXSC, TILEGX_OPC_ADDX, TILEGX_OPC_ADD, - TILEGX_OPC_AND, TILEGX_OPC_CMOVEQZ, TILEGX_OPC_CMOVNEZ, TILEGX_OPC_CMPEQ, - TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU, - TILEGX_OPC_CMPNE, TILEGX_OPC_CMULAF, TILEGX_OPC_CMULA, TILEGX_OPC_CMULFR, - BITFIELD(18, 4) /* index 620 */, - TILEGX_OPC_CMULF, TILEGX_OPC_CMULHR, TILEGX_OPC_CMULH, TILEGX_OPC_CMUL, - TILEGX_OPC_CRC32_32, TILEGX_OPC_CRC32_8, TILEGX_OPC_DBLALIGN2, - TILEGX_OPC_DBLALIGN4, TILEGX_OPC_DBLALIGN6, TILEGX_OPC_DBLALIGN, - TILEGX_OPC_FDOUBLE_ADDSUB, TILEGX_OPC_FDOUBLE_ADD_FLAGS, - TILEGX_OPC_FDOUBLE_MUL_FLAGS, TILEGX_OPC_FDOUBLE_PACK1, - TILEGX_OPC_FDOUBLE_PACK2, TILEGX_OPC_FDOUBLE_SUB_FLAGS, - BITFIELD(18, 4) /* index 637 */, - TILEGX_OPC_FDOUBLE_UNPACK_MAX, TILEGX_OPC_FDOUBLE_UNPACK_MIN, - TILEGX_OPC_FSINGLE_ADD1, TILEGX_OPC_FSINGLE_ADDSUB2, - TILEGX_OPC_FSINGLE_MUL1, TILEGX_OPC_FSINGLE_MUL2, TILEGX_OPC_FSINGLE_PACK2, - TILEGX_OPC_FSINGLE_SUB1, TILEGX_OPC_MNZ, TILEGX_OPC_MULAX, - TILEGX_OPC_MULA_HS_HS, TILEGX_OPC_MULA_HS_HU, TILEGX_OPC_MULA_HS_LS, - TILEGX_OPC_MULA_HS_LU, TILEGX_OPC_MULA_HU_HU, TILEGX_OPC_MULA_HU_LS, - BITFIELD(18, 4) /* index 654 */, - TILEGX_OPC_MULA_HU_LU, TILEGX_OPC_MULA_LS_LS, TILEGX_OPC_MULA_LS_LU, - TILEGX_OPC_MULA_LU_LU, TILEGX_OPC_MULX, TILEGX_OPC_MUL_HS_HS, - TILEGX_OPC_MUL_HS_HU, TILEGX_OPC_MUL_HS_LS, TILEGX_OPC_MUL_HS_LU, - TILEGX_OPC_MUL_HU_HU, TILEGX_OPC_MUL_HU_LS, TILEGX_OPC_MUL_HU_LU, - TILEGX_OPC_MUL_LS_LS, TILEGX_OPC_MUL_LS_LU, TILEGX_OPC_MUL_LU_LU, - TILEGX_OPC_MZ, - BITFIELD(18, 4) /* index 671 */, - TILEGX_OPC_NOR, CHILD(688), TILEGX_OPC_ROTL, TILEGX_OPC_SHL1ADDX, - TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADDX, TILEGX_OPC_SHL2ADD, - TILEGX_OPC_SHL3ADDX, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHLX, TILEGX_OPC_SHL, - TILEGX_OPC_SHRS, TILEGX_OPC_SHRUX, TILEGX_OPC_SHRU, TILEGX_OPC_SHUFFLEBYTES, - TILEGX_OPC_SUBXSC, - BITFIELD(12, 2) /* index 688 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(693), - BITFIELD(14, 2) /* index 693 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(698), - BITFIELD(16, 2) /* index 698 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE, - BITFIELD(18, 4) /* index 703 */, - TILEGX_OPC_SUBX, TILEGX_OPC_SUB, CHILD(720), TILEGX_OPC_V1ADDUC, - TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADIFFU, TILEGX_OPC_V1AVGU, - TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLEU, - TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPNE, - TILEGX_OPC_V1DDOTPUSA, TILEGX_OPC_V1DDOTPUS, TILEGX_OPC_V1DOTPA, - BITFIELD(12, 4) /* index 720 */, - TILEGX_OPC_NONE, CHILD(737), CHILD(742), CHILD(747), CHILD(752), CHILD(757), - CHILD(762), CHILD(767), CHILD(772), CHILD(777), CHILD(782), CHILD(787), - CHILD(792), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 737 */, - TILEGX_OPC_CLZ, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 742 */, - TILEGX_OPC_CTZ, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 747 */, - TILEGX_OPC_FNOP, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 752 */, - TILEGX_OPC_FSINGLE_PACK1, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 757 */, - TILEGX_OPC_NOP, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 762 */, - TILEGX_OPC_PCNT, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 767 */, - TILEGX_OPC_REVBITS, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 772 */, - TILEGX_OPC_REVBYTES, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 777 */, - TILEGX_OPC_TBLIDXB0, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 782 */, - TILEGX_OPC_TBLIDXB1, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 787 */, - TILEGX_OPC_TBLIDXB2, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(16, 2) /* index 792 */, - TILEGX_OPC_TBLIDXB3, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(18, 4) /* index 797 */, - TILEGX_OPC_V1DOTPUSA, TILEGX_OPC_V1DOTPUS, TILEGX_OPC_V1DOTP, - TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1MAXU, - TILEGX_OPC_V1MINU, TILEGX_OPC_V1MNZ, TILEGX_OPC_V1MULTU, TILEGX_OPC_V1MULUS, - TILEGX_OPC_V1MULU, TILEGX_OPC_V1MZ, TILEGX_OPC_V1SADAU, TILEGX_OPC_V1SADU, - TILEGX_OPC_V1SHL, TILEGX_OPC_V1SHRS, - BITFIELD(18, 4) /* index 814 */, - TILEGX_OPC_V1SHRU, TILEGX_OPC_V1SUBUC, TILEGX_OPC_V1SUB, TILEGX_OPC_V2ADDSC, - TILEGX_OPC_V2ADD, TILEGX_OPC_V2ADIFFS, TILEGX_OPC_V2AVGS, - TILEGX_OPC_V2CMPEQ, TILEGX_OPC_V2CMPLES, TILEGX_OPC_V2CMPLEU, - TILEGX_OPC_V2CMPLTS, TILEGX_OPC_V2CMPLTU, TILEGX_OPC_V2CMPNE, - TILEGX_OPC_V2DOTPA, TILEGX_OPC_V2DOTP, TILEGX_OPC_V2INT_H, - BITFIELD(18, 4) /* index 831 */, - TILEGX_OPC_V2INT_L, TILEGX_OPC_V2MAXS, TILEGX_OPC_V2MINS, TILEGX_OPC_V2MNZ, - TILEGX_OPC_V2MULFSC, TILEGX_OPC_V2MULS, TILEGX_OPC_V2MULTS, TILEGX_OPC_V2MZ, - TILEGX_OPC_V2PACKH, TILEGX_OPC_V2PACKL, TILEGX_OPC_V2PACKUC, - TILEGX_OPC_V2SADAS, TILEGX_OPC_V2SADAU, TILEGX_OPC_V2SADS, - TILEGX_OPC_V2SADU, TILEGX_OPC_V2SHLSC, - BITFIELD(18, 4) /* index 848 */, - TILEGX_OPC_V2SHL, TILEGX_OPC_V2SHRS, TILEGX_OPC_V2SHRU, TILEGX_OPC_V2SUBSC, - TILEGX_OPC_V2SUB, TILEGX_OPC_V4ADDSC, TILEGX_OPC_V4ADD, TILEGX_OPC_V4INT_H, - TILEGX_OPC_V4INT_L, TILEGX_OPC_V4PACKSC, TILEGX_OPC_V4SHLSC, - TILEGX_OPC_V4SHL, TILEGX_OPC_V4SHRS, TILEGX_OPC_V4SHRU, TILEGX_OPC_V4SUBSC, - TILEGX_OPC_V4SUB, - BITFIELD(18, 3) /* index 865 */, - CHILD(874), CHILD(877), CHILD(880), CHILD(883), CHILD(886), TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(21, 1) /* index 874 */, - TILEGX_OPC_XOR, TILEGX_OPC_NONE, - BITFIELD(21, 1) /* index 877 */, - TILEGX_OPC_V1DDOTPUA, TILEGX_OPC_NONE, - BITFIELD(21, 1) /* index 880 */, - TILEGX_OPC_V1DDOTPU, TILEGX_OPC_NONE, - BITFIELD(21, 1) /* index 883 */, - TILEGX_OPC_V1DOTPUA, TILEGX_OPC_NONE, - BITFIELD(21, 1) /* index 886 */, - TILEGX_OPC_V1DOTPU, TILEGX_OPC_NONE, - BITFIELD(18, 4) /* index 889 */, - TILEGX_OPC_NONE, TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHLXI, - TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, TILEGX_OPC_SHRUXI, TILEGX_OPC_V1SHLI, - TILEGX_OPC_V1SHRSI, TILEGX_OPC_V1SHRUI, TILEGX_OPC_V2SHLI, - TILEGX_OPC_V2SHRSI, TILEGX_OPC_V2SHRUI, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, - BITFIELD(0, 2) /* index 906 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - CHILD(911), - BITFIELD(2, 2) /* index 911 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - CHILD(916), - BITFIELD(4, 2) /* index 916 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - CHILD(921), - BITFIELD(6, 2) /* index 921 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - CHILD(926), - BITFIELD(8, 2) /* index 926 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - CHILD(931), - BITFIELD(10, 2) /* index 931 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - TILEGX_OPC_INFOL, -}; - -static const unsigned short decode_X1_fsm[1206] = -{ - BITFIELD(53, 9) /* index 0 */, - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), CHILD(513), - CHILD(513), CHILD(513), CHILD(513), CHILD(513), TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, - TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_ADDXLI, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_BEQZT, - TILEGX_OPC_BEQZT, TILEGX_OPC_BEQZ, TILEGX_OPC_BEQZ, TILEGX_OPC_BGEZT, - TILEGX_OPC_BGEZT, TILEGX_OPC_BGEZ, TILEGX_OPC_BGEZ, TILEGX_OPC_BGTZT, - TILEGX_OPC_BGTZT, TILEGX_OPC_BGTZ, TILEGX_OPC_BGTZ, TILEGX_OPC_BLBCT, - TILEGX_OPC_BLBCT, TILEGX_OPC_BLBC, TILEGX_OPC_BLBC, TILEGX_OPC_BLBST, - TILEGX_OPC_BLBST, TILEGX_OPC_BLBS, TILEGX_OPC_BLBS, TILEGX_OPC_BLEZT, - TILEGX_OPC_BLEZT, TILEGX_OPC_BLEZ, TILEGX_OPC_BLEZ, TILEGX_OPC_BLTZT, - TILEGX_OPC_BLTZT, TILEGX_OPC_BLTZ, TILEGX_OPC_BLTZ, TILEGX_OPC_BNEZT, - TILEGX_OPC_BNEZT, TILEGX_OPC_BNEZ, TILEGX_OPC_BNEZ, CHILD(528), CHILD(578), - CHILD(598), CHILD(663), CHILD(683), CHILD(688), CHILD(693), CHILD(698), - CHILD(703), CHILD(708), CHILD(713), CHILD(718), TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_JAL, - TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, - TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, - TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, - TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, - TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, - TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, - TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, - TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_JAL, TILEGX_OPC_J, TILEGX_OPC_J, - TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, - TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, - TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, - TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, - TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, - TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, TILEGX_OPC_J, - CHILD(723), CHILD(740), CHILD(772), CHILD(789), CHILD(1108), CHILD(1125), - CHILD(1142), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(1159), TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), CHILD(1176), - CHILD(1176), - BITFIELD(37, 2) /* index 513 */, - TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(518), - BITFIELD(39, 2) /* index 518 */, - TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, CHILD(523), - BITFIELD(41, 2) /* index 523 */, - TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_ADDLI, TILEGX_OPC_MOVELI, - BITFIELD(51, 2) /* index 528 */, - TILEGX_OPC_NONE, CHILD(533), TILEGX_OPC_ADDXI, CHILD(548), - BITFIELD(37, 2) /* index 533 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(538), - BITFIELD(39, 2) /* index 538 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(543), - BITFIELD(41, 2) /* index 543 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI, - BITFIELD(31, 2) /* index 548 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(553), - BITFIELD(33, 2) /* index 553 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(558), - BITFIELD(35, 2) /* index 558 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(563), - BITFIELD(37, 2) /* index 563 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(568), - BITFIELD(39, 2) /* index 568 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(573), - BITFIELD(41, 2) /* index 573 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO, - BITFIELD(51, 2) /* index 578 */, - TILEGX_OPC_CMPEQI, TILEGX_OPC_CMPLTSI, TILEGX_OPC_CMPLTUI, CHILD(583), - BITFIELD(31, 2) /* index 583 */, - TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, CHILD(588), - BITFIELD(33, 2) /* index 588 */, - TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, CHILD(593), - BITFIELD(35, 2) /* index 593 */, - TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, TILEGX_OPC_LD1S_ADD, - TILEGX_OPC_PREFETCH_ADD_L1_FAULT, - BITFIELD(51, 2) /* index 598 */, - CHILD(603), CHILD(618), CHILD(633), CHILD(648), - BITFIELD(31, 2) /* index 603 */, - TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, CHILD(608), - BITFIELD(33, 2) /* index 608 */, - TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, CHILD(613), - BITFIELD(35, 2) /* index 613 */, - TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, TILEGX_OPC_LD1U_ADD, - TILEGX_OPC_PREFETCH_ADD_L1, - BITFIELD(31, 2) /* index 618 */, - TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, CHILD(623), - BITFIELD(33, 2) /* index 623 */, - TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, CHILD(628), - BITFIELD(35, 2) /* index 628 */, - TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, TILEGX_OPC_LD2S_ADD, - TILEGX_OPC_PREFETCH_ADD_L2_FAULT, - BITFIELD(31, 2) /* index 633 */, - TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, CHILD(638), - BITFIELD(33, 2) /* index 638 */, - TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, CHILD(643), - BITFIELD(35, 2) /* index 643 */, - TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, TILEGX_OPC_LD2U_ADD, - TILEGX_OPC_PREFETCH_ADD_L2, - BITFIELD(31, 2) /* index 648 */, - TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, CHILD(653), - BITFIELD(33, 2) /* index 653 */, - TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, CHILD(658), - BITFIELD(35, 2) /* index 658 */, - TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, TILEGX_OPC_LD4S_ADD, - TILEGX_OPC_PREFETCH_ADD_L3_FAULT, - BITFIELD(51, 2) /* index 663 */, - CHILD(668), TILEGX_OPC_LDNT1S_ADD, TILEGX_OPC_LDNT1U_ADD, - TILEGX_OPC_LDNT2S_ADD, - BITFIELD(31, 2) /* index 668 */, - TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, CHILD(673), - BITFIELD(33, 2) /* index 673 */, - TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, CHILD(678), - BITFIELD(35, 2) /* index 678 */, - TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, TILEGX_OPC_LD4U_ADD, - TILEGX_OPC_PREFETCH_ADD_L3, - BITFIELD(51, 2) /* index 683 */, - TILEGX_OPC_LDNT2U_ADD, TILEGX_OPC_LDNT4S_ADD, TILEGX_OPC_LDNT4U_ADD, - TILEGX_OPC_LDNT_ADD, - BITFIELD(51, 2) /* index 688 */, - TILEGX_OPC_LD_ADD, TILEGX_OPC_LDNA_ADD, TILEGX_OPC_MFSPR, TILEGX_OPC_MTSPR, - BITFIELD(51, 2) /* index 693 */, - TILEGX_OPC_ORI, TILEGX_OPC_ST1_ADD, TILEGX_OPC_ST2_ADD, TILEGX_OPC_ST4_ADD, - BITFIELD(51, 2) /* index 698 */, - TILEGX_OPC_STNT1_ADD, TILEGX_OPC_STNT2_ADD, TILEGX_OPC_STNT4_ADD, - TILEGX_OPC_STNT_ADD, - BITFIELD(51, 2) /* index 703 */, - TILEGX_OPC_ST_ADD, TILEGX_OPC_V1ADDI, TILEGX_OPC_V1CMPEQI, - TILEGX_OPC_V1CMPLTSI, - BITFIELD(51, 2) /* index 708 */, - TILEGX_OPC_V1CMPLTUI, TILEGX_OPC_V1MAXUI, TILEGX_OPC_V1MINUI, - TILEGX_OPC_V2ADDI, - BITFIELD(51, 2) /* index 713 */, - TILEGX_OPC_V2CMPEQI, TILEGX_OPC_V2CMPLTSI, TILEGX_OPC_V2CMPLTUI, - TILEGX_OPC_V2MAXSI, - BITFIELD(51, 2) /* index 718 */, - TILEGX_OPC_V2MINSI, TILEGX_OPC_XORI, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(49, 4) /* index 723 */, - TILEGX_OPC_NONE, TILEGX_OPC_ADDXSC, TILEGX_OPC_ADDX, TILEGX_OPC_ADD, - TILEGX_OPC_AND, TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPEXCH4, TILEGX_OPC_CMPEXCH, - TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU, - TILEGX_OPC_CMPNE, TILEGX_OPC_DBLALIGN2, TILEGX_OPC_DBLALIGN4, - TILEGX_OPC_DBLALIGN6, - BITFIELD(49, 4) /* index 740 */, - TILEGX_OPC_EXCH4, TILEGX_OPC_EXCH, TILEGX_OPC_FETCHADD4, - TILEGX_OPC_FETCHADDGEZ4, TILEGX_OPC_FETCHADDGEZ, TILEGX_OPC_FETCHADD, - TILEGX_OPC_FETCHAND4, TILEGX_OPC_FETCHAND, TILEGX_OPC_FETCHOR4, - TILEGX_OPC_FETCHOR, TILEGX_OPC_MNZ, TILEGX_OPC_MZ, TILEGX_OPC_NOR, - CHILD(757), TILEGX_OPC_ROTL, TILEGX_OPC_SHL1ADDX, - BITFIELD(43, 2) /* index 757 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(762), - BITFIELD(45, 2) /* index 762 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(767), - BITFIELD(47, 2) /* index 767 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE, - BITFIELD(49, 4) /* index 772 */, - TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADDX, TILEGX_OPC_SHL2ADD, - TILEGX_OPC_SHL3ADDX, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHLX, TILEGX_OPC_SHL, - TILEGX_OPC_SHRS, TILEGX_OPC_SHRUX, TILEGX_OPC_SHRU, TILEGX_OPC_ST1, - TILEGX_OPC_ST2, TILEGX_OPC_ST4, TILEGX_OPC_STNT1, TILEGX_OPC_STNT2, - TILEGX_OPC_STNT4, - BITFIELD(46, 7) /* index 789 */, - TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, - TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, TILEGX_OPC_STNT, - TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, - TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_ST, TILEGX_OPC_SUBXSC, - TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, - TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBXSC, TILEGX_OPC_SUBX, - TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, - TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUBX, TILEGX_OPC_SUB, - TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, - TILEGX_OPC_SUB, TILEGX_OPC_SUB, TILEGX_OPC_SUB, CHILD(918), CHILD(927), - CHILD(1006), CHILD(1090), CHILD(1099), TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, - TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, - TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADDUC, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, - TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, - TILEGX_OPC_V1ADD, TILEGX_OPC_V1ADD, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, - TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, - TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, TILEGX_OPC_V1CMPEQ, - TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, - TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, - TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLES, TILEGX_OPC_V1CMPLEU, - TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, - TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLEU, - TILEGX_OPC_V1CMPLEU, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, - TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, - TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, TILEGX_OPC_V1CMPLTS, - TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, - TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, - TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPLTU, TILEGX_OPC_V1CMPNE, - TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, - TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1CMPNE, - TILEGX_OPC_V1CMPNE, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, - TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, - TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, TILEGX_OPC_V1INT_H, - TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, - TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, - TILEGX_OPC_V1INT_L, TILEGX_OPC_V1INT_L, - BITFIELD(43, 3) /* index 918 */, - TILEGX_OPC_NONE, TILEGX_OPC_DRAIN, TILEGX_OPC_DTLBPR, TILEGX_OPC_FINV, - TILEGX_OPC_FLUSHWB, TILEGX_OPC_FLUSH, TILEGX_OPC_FNOP, TILEGX_OPC_ICOH, - BITFIELD(43, 3) /* index 927 */, - CHILD(936), TILEGX_OPC_INV, TILEGX_OPC_IRET, TILEGX_OPC_JALRP, - TILEGX_OPC_JALR, TILEGX_OPC_JRP, TILEGX_OPC_JR, CHILD(991), - BITFIELD(31, 2) /* index 936 */, - CHILD(941), CHILD(966), TILEGX_OPC_ILL, TILEGX_OPC_ILL, - BITFIELD(33, 2) /* index 941 */, - TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_ILL, CHILD(946), - BITFIELD(35, 2) /* index 946 */, - TILEGX_OPC_ILL, CHILD(951), TILEGX_OPC_ILL, TILEGX_OPC_ILL, - BITFIELD(37, 2) /* index 951 */, - TILEGX_OPC_ILL, CHILD(956), TILEGX_OPC_ILL, TILEGX_OPC_ILL, - BITFIELD(39, 2) /* index 956 */, - TILEGX_OPC_ILL, CHILD(961), TILEGX_OPC_ILL, TILEGX_OPC_ILL, - BITFIELD(41, 2) /* index 961 */, - TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_BPT, TILEGX_OPC_ILL, - BITFIELD(33, 2) /* index 966 */, - TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_ILL, CHILD(971), - BITFIELD(35, 2) /* index 971 */, - TILEGX_OPC_ILL, CHILD(976), TILEGX_OPC_ILL, TILEGX_OPC_ILL, - BITFIELD(37, 2) /* index 976 */, - TILEGX_OPC_ILL, CHILD(981), TILEGX_OPC_ILL, TILEGX_OPC_ILL, - BITFIELD(39, 2) /* index 981 */, - TILEGX_OPC_ILL, CHILD(986), TILEGX_OPC_ILL, TILEGX_OPC_ILL, - BITFIELD(41, 2) /* index 986 */, - TILEGX_OPC_ILL, TILEGX_OPC_ILL, TILEGX_OPC_RAISE, TILEGX_OPC_ILL, - BITFIELD(31, 2) /* index 991 */, - TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(996), - BITFIELD(33, 2) /* index 996 */, - TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(1001), - BITFIELD(35, 2) /* index 1001 */, - TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, - TILEGX_OPC_PREFETCH_L1_FAULT, - BITFIELD(43, 3) /* index 1006 */, - CHILD(1015), CHILD(1030), CHILD(1045), CHILD(1060), CHILD(1075), - TILEGX_OPC_LDNA, TILEGX_OPC_LDNT1S, TILEGX_OPC_LDNT1U, - BITFIELD(31, 2) /* index 1015 */, - TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(1020), - BITFIELD(33, 2) /* index 1020 */, - TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(1025), - BITFIELD(35, 2) /* index 1025 */, - TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_PREFETCH, - BITFIELD(31, 2) /* index 1030 */, - TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(1035), - BITFIELD(33, 2) /* index 1035 */, - TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(1040), - BITFIELD(35, 2) /* index 1040 */, - TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, - TILEGX_OPC_PREFETCH_L2_FAULT, - BITFIELD(31, 2) /* index 1045 */, - TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(1050), - BITFIELD(33, 2) /* index 1050 */, - TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(1055), - BITFIELD(35, 2) /* index 1055 */, - TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_PREFETCH_L2, - BITFIELD(31, 2) /* index 1060 */, - TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(1065), - BITFIELD(33, 2) /* index 1065 */, - TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(1070), - BITFIELD(35, 2) /* index 1070 */, - TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, - TILEGX_OPC_PREFETCH_L3_FAULT, - BITFIELD(31, 2) /* index 1075 */, - TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(1080), - BITFIELD(33, 2) /* index 1080 */, - TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(1085), - BITFIELD(35, 2) /* index 1085 */, - TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_PREFETCH_L3, - BITFIELD(43, 3) /* index 1090 */, - TILEGX_OPC_LDNT2S, TILEGX_OPC_LDNT2U, TILEGX_OPC_LDNT4S, TILEGX_OPC_LDNT4U, - TILEGX_OPC_LDNT, TILEGX_OPC_LD, TILEGX_OPC_LNK, TILEGX_OPC_MF, - BITFIELD(43, 3) /* index 1099 */, - TILEGX_OPC_NAP, TILEGX_OPC_NOP, TILEGX_OPC_SWINT0, TILEGX_OPC_SWINT1, - TILEGX_OPC_SWINT2, TILEGX_OPC_SWINT3, TILEGX_OPC_WH64, TILEGX_OPC_NONE, - BITFIELD(49, 4) /* index 1108 */, - TILEGX_OPC_V1MAXU, TILEGX_OPC_V1MINU, TILEGX_OPC_V1MNZ, TILEGX_OPC_V1MZ, - TILEGX_OPC_V1SHL, TILEGX_OPC_V1SHRS, TILEGX_OPC_V1SHRU, TILEGX_OPC_V1SUBUC, - TILEGX_OPC_V1SUB, TILEGX_OPC_V2ADDSC, TILEGX_OPC_V2ADD, TILEGX_OPC_V2CMPEQ, - TILEGX_OPC_V2CMPLES, TILEGX_OPC_V2CMPLEU, TILEGX_OPC_V2CMPLTS, - TILEGX_OPC_V2CMPLTU, - BITFIELD(49, 4) /* index 1125 */, - TILEGX_OPC_V2CMPNE, TILEGX_OPC_V2INT_H, TILEGX_OPC_V2INT_L, - TILEGX_OPC_V2MAXS, TILEGX_OPC_V2MINS, TILEGX_OPC_V2MNZ, TILEGX_OPC_V2MZ, - TILEGX_OPC_V2PACKH, TILEGX_OPC_V2PACKL, TILEGX_OPC_V2PACKUC, - TILEGX_OPC_V2SHLSC, TILEGX_OPC_V2SHL, TILEGX_OPC_V2SHRS, TILEGX_OPC_V2SHRU, - TILEGX_OPC_V2SUBSC, TILEGX_OPC_V2SUB, - BITFIELD(49, 4) /* index 1142 */, - TILEGX_OPC_V4ADDSC, TILEGX_OPC_V4ADD, TILEGX_OPC_V4INT_H, - TILEGX_OPC_V4INT_L, TILEGX_OPC_V4PACKSC, TILEGX_OPC_V4SHLSC, - TILEGX_OPC_V4SHL, TILEGX_OPC_V4SHRS, TILEGX_OPC_V4SHRU, TILEGX_OPC_V4SUBSC, - TILEGX_OPC_V4SUB, TILEGX_OPC_XOR, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(49, 4) /* index 1159 */, - TILEGX_OPC_NONE, TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHLXI, - TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, TILEGX_OPC_SHRUXI, TILEGX_OPC_V1SHLI, - TILEGX_OPC_V1SHRSI, TILEGX_OPC_V1SHRUI, TILEGX_OPC_V2SHLI, - TILEGX_OPC_V2SHRSI, TILEGX_OPC_V2SHRUI, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, - BITFIELD(31, 2) /* index 1176 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - CHILD(1181), - BITFIELD(33, 2) /* index 1181 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - CHILD(1186), - BITFIELD(35, 2) /* index 1186 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - CHILD(1191), - BITFIELD(37, 2) /* index 1191 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - CHILD(1196), - BITFIELD(39, 2) /* index 1196 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - CHILD(1201), - BITFIELD(41, 2) /* index 1201 */, - TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, TILEGX_OPC_SHL16INSLI, - TILEGX_OPC_INFOL, -}; - -static const unsigned short decode_Y0_fsm[178] = -{ - BITFIELD(27, 4) /* index 0 */, - CHILD(17), TILEGX_OPC_ADDXI, CHILD(32), TILEGX_OPC_CMPEQI, - TILEGX_OPC_CMPLTSI, CHILD(62), CHILD(67), CHILD(118), CHILD(123), - CHILD(128), CHILD(133), CHILD(153), CHILD(158), CHILD(163), CHILD(168), - CHILD(173), - BITFIELD(6, 2) /* index 17 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(22), - BITFIELD(8, 2) /* index 22 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(27), - BITFIELD(10, 2) /* index 27 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI, - BITFIELD(0, 2) /* index 32 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(37), - BITFIELD(2, 2) /* index 37 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(42), - BITFIELD(4, 2) /* index 42 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(47), - BITFIELD(6, 2) /* index 47 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(52), - BITFIELD(8, 2) /* index 52 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(57), - BITFIELD(10, 2) /* index 57 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO, - BITFIELD(18, 2) /* index 62 */, - TILEGX_OPC_ADDX, TILEGX_OPC_ADD, TILEGX_OPC_SUBX, TILEGX_OPC_SUB, - BITFIELD(15, 5) /* index 67 */, - TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, - TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, - TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADD, - TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, - TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, - TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, - TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, - TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, CHILD(100), - CHILD(109), TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(12, 3) /* index 100 */, - TILEGX_OPC_NONE, TILEGX_OPC_CLZ, TILEGX_OPC_CTZ, TILEGX_OPC_FNOP, - TILEGX_OPC_FSINGLE_PACK1, TILEGX_OPC_NOP, TILEGX_OPC_PCNT, - TILEGX_OPC_REVBITS, - BITFIELD(12, 3) /* index 109 */, - TILEGX_OPC_REVBYTES, TILEGX_OPC_TBLIDXB0, TILEGX_OPC_TBLIDXB1, - TILEGX_OPC_TBLIDXB2, TILEGX_OPC_TBLIDXB3, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - TILEGX_OPC_NONE, - BITFIELD(18, 2) /* index 118 */, - TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU, - BITFIELD(18, 2) /* index 123 */, - TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPNE, TILEGX_OPC_MULAX, TILEGX_OPC_MULX, - BITFIELD(18, 2) /* index 128 */, - TILEGX_OPC_CMOVEQZ, TILEGX_OPC_CMOVNEZ, TILEGX_OPC_MNZ, TILEGX_OPC_MZ, - BITFIELD(18, 2) /* index 133 */, - TILEGX_OPC_AND, TILEGX_OPC_NOR, CHILD(138), TILEGX_OPC_XOR, - BITFIELD(12, 2) /* index 138 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(143), - BITFIELD(14, 2) /* index 143 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(148), - BITFIELD(16, 2) /* index 148 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE, - BITFIELD(18, 2) /* index 153 */, - TILEGX_OPC_ROTL, TILEGX_OPC_SHL, TILEGX_OPC_SHRS, TILEGX_OPC_SHRU, - BITFIELD(18, 2) /* index 158 */, - TILEGX_OPC_NONE, TILEGX_OPC_SHL1ADDX, TILEGX_OPC_SHL2ADDX, - TILEGX_OPC_SHL3ADDX, - BITFIELD(18, 2) /* index 163 */, - TILEGX_OPC_MUL_HS_HS, TILEGX_OPC_MUL_HU_HU, TILEGX_OPC_MUL_LS_LS, - TILEGX_OPC_MUL_LU_LU, - BITFIELD(18, 2) /* index 168 */, - TILEGX_OPC_MULA_HS_HS, TILEGX_OPC_MULA_HU_HU, TILEGX_OPC_MULA_LS_LS, - TILEGX_OPC_MULA_LU_LU, - BITFIELD(18, 2) /* index 173 */, - TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, -}; - -static const unsigned short decode_Y1_fsm[167] = -{ - BITFIELD(58, 4) /* index 0 */, - TILEGX_OPC_NONE, CHILD(17), TILEGX_OPC_ADDXI, CHILD(32), TILEGX_OPC_CMPEQI, - TILEGX_OPC_CMPLTSI, CHILD(62), CHILD(67), CHILD(117), CHILD(122), - CHILD(127), CHILD(132), CHILD(152), CHILD(157), CHILD(162), TILEGX_OPC_NONE, - BITFIELD(37, 2) /* index 17 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(22), - BITFIELD(39, 2) /* index 22 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, CHILD(27), - BITFIELD(41, 2) /* index 27 */, - TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_ADDI, TILEGX_OPC_MOVEI, - BITFIELD(31, 2) /* index 32 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(37), - BITFIELD(33, 2) /* index 37 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(42), - BITFIELD(35, 2) /* index 42 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(47), - BITFIELD(37, 2) /* index 47 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(52), - BITFIELD(39, 2) /* index 52 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, CHILD(57), - BITFIELD(41, 2) /* index 57 */, - TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_ANDI, TILEGX_OPC_INFO, - BITFIELD(49, 2) /* index 62 */, - TILEGX_OPC_ADDX, TILEGX_OPC_ADD, TILEGX_OPC_SUBX, TILEGX_OPC_SUB, - BITFIELD(47, 4) /* index 67 */, - TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL1ADD, - TILEGX_OPC_SHL1ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, - TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL2ADD, TILEGX_OPC_SHL3ADD, - TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, TILEGX_OPC_SHL3ADD, CHILD(84), - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_NONE, - BITFIELD(43, 3) /* index 84 */, - CHILD(93), CHILD(96), CHILD(99), CHILD(102), CHILD(105), CHILD(108), - CHILD(111), CHILD(114), - BITFIELD(46, 1) /* index 93 */, - TILEGX_OPC_NONE, TILEGX_OPC_FNOP, - BITFIELD(46, 1) /* index 96 */, - TILEGX_OPC_NONE, TILEGX_OPC_ILL, - BITFIELD(46, 1) /* index 99 */, - TILEGX_OPC_NONE, TILEGX_OPC_JALRP, - BITFIELD(46, 1) /* index 102 */, - TILEGX_OPC_NONE, TILEGX_OPC_JALR, - BITFIELD(46, 1) /* index 105 */, - TILEGX_OPC_NONE, TILEGX_OPC_JRP, - BITFIELD(46, 1) /* index 108 */, - TILEGX_OPC_NONE, TILEGX_OPC_JR, - BITFIELD(46, 1) /* index 111 */, - TILEGX_OPC_NONE, TILEGX_OPC_LNK, - BITFIELD(46, 1) /* index 114 */, - TILEGX_OPC_NONE, TILEGX_OPC_NOP, - BITFIELD(49, 2) /* index 117 */, - TILEGX_OPC_CMPLES, TILEGX_OPC_CMPLEU, TILEGX_OPC_CMPLTS, TILEGX_OPC_CMPLTU, - BITFIELD(49, 2) /* index 122 */, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_CMPEQ, TILEGX_OPC_CMPNE, - BITFIELD(49, 2) /* index 127 */, - TILEGX_OPC_NONE, TILEGX_OPC_NONE, TILEGX_OPC_MNZ, TILEGX_OPC_MZ, - BITFIELD(49, 2) /* index 132 */, - TILEGX_OPC_AND, TILEGX_OPC_NOR, CHILD(137), TILEGX_OPC_XOR, - BITFIELD(43, 2) /* index 137 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(142), - BITFIELD(45, 2) /* index 142 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, CHILD(147), - BITFIELD(47, 2) /* index 147 */, - TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_OR, TILEGX_OPC_MOVE, - BITFIELD(49, 2) /* index 152 */, - TILEGX_OPC_ROTL, TILEGX_OPC_SHL, TILEGX_OPC_SHRS, TILEGX_OPC_SHRU, - BITFIELD(49, 2) /* index 157 */, - TILEGX_OPC_NONE, TILEGX_OPC_SHL1ADDX, TILEGX_OPC_SHL2ADDX, - TILEGX_OPC_SHL3ADDX, - BITFIELD(49, 2) /* index 162 */, - TILEGX_OPC_ROTLI, TILEGX_OPC_SHLI, TILEGX_OPC_SHRSI, TILEGX_OPC_SHRUI, -}; - -static const unsigned short decode_Y2_fsm[118] = -{ - BITFIELD(62, 2) /* index 0 */, - TILEGX_OPC_NONE, CHILD(5), CHILD(66), CHILD(109), - BITFIELD(55, 3) /* index 5 */, - CHILD(14), CHILD(14), CHILD(14), CHILD(17), CHILD(40), CHILD(40), CHILD(40), - CHILD(43), - BITFIELD(26, 1) /* index 14 */, - TILEGX_OPC_LD1S, TILEGX_OPC_LD1U, - BITFIELD(26, 1) /* index 17 */, - CHILD(20), CHILD(30), - BITFIELD(51, 2) /* index 20 */, - TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, CHILD(25), - BITFIELD(53, 2) /* index 25 */, - TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, TILEGX_OPC_LD1S, - TILEGX_OPC_PREFETCH_L1_FAULT, - BITFIELD(51, 2) /* index 30 */, - TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, CHILD(35), - BITFIELD(53, 2) /* index 35 */, - TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_LD1U, TILEGX_OPC_PREFETCH, - BITFIELD(26, 1) /* index 40 */, - TILEGX_OPC_LD2S, TILEGX_OPC_LD2U, - BITFIELD(26, 1) /* index 43 */, - CHILD(46), CHILD(56), - BITFIELD(51, 2) /* index 46 */, - TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, CHILD(51), - BITFIELD(53, 2) /* index 51 */, - TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, TILEGX_OPC_LD2S, - TILEGX_OPC_PREFETCH_L2_FAULT, - BITFIELD(51, 2) /* index 56 */, - TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, CHILD(61), - BITFIELD(53, 2) /* index 61 */, - TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_LD2U, TILEGX_OPC_PREFETCH_L2, - BITFIELD(56, 2) /* index 66 */, - CHILD(71), CHILD(74), CHILD(90), CHILD(93), - BITFIELD(26, 1) /* index 71 */, - TILEGX_OPC_NONE, TILEGX_OPC_LD4S, - BITFIELD(26, 1) /* index 74 */, - TILEGX_OPC_NONE, CHILD(77), - BITFIELD(51, 2) /* index 77 */, - TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(82), - BITFIELD(53, 2) /* index 82 */, - TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, TILEGX_OPC_LD4S, CHILD(87), - BITFIELD(55, 1) /* index 87 */, - TILEGX_OPC_LD4S, TILEGX_OPC_PREFETCH_L3_FAULT, - BITFIELD(26, 1) /* index 90 */, - TILEGX_OPC_LD4U, TILEGX_OPC_LD, - BITFIELD(26, 1) /* index 93 */, - CHILD(96), TILEGX_OPC_LD, - BITFIELD(51, 2) /* index 96 */, - TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(101), - BITFIELD(53, 2) /* index 101 */, - TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, TILEGX_OPC_LD4U, CHILD(106), - BITFIELD(55, 1) /* index 106 */, - TILEGX_OPC_LD4U, TILEGX_OPC_PREFETCH_L3, - BITFIELD(26, 1) /* index 109 */, - CHILD(112), CHILD(115), - BITFIELD(57, 1) /* index 112 */, - TILEGX_OPC_ST1, TILEGX_OPC_ST4, - BITFIELD(57, 1) /* index 115 */, - TILEGX_OPC_ST2, TILEGX_OPC_ST, -}; - -#undef BITFIELD -#undef CHILD -const unsigned short * const -tilegx_bundle_decoder_fsms[TILEGX_NUM_PIPELINE_ENCODINGS] = -{ - decode_X0_fsm, - decode_X1_fsm, - decode_Y0_fsm, - decode_Y1_fsm, - decode_Y2_fsm -}; -const struct tilegx_operand tilegx_operands[35] = -{ - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_X0), - 8, 1, 0, 0, 0, 0, - create_Imm8_X0, get_Imm8_X0 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_X1), - 8, 1, 0, 0, 0, 0, - create_Imm8_X1, get_Imm8_X1 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_Y0), - 8, 1, 0, 0, 0, 0, - create_Imm8_Y0, get_Imm8_Y0 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM8_Y1), - 8, 1, 0, 0, 0, 0, - create_Imm8_Y1, get_Imm8_Y1 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM16_X0_HW0_LAST), - 16, 1, 0, 0, 0, 0, - create_Imm16_X0, get_Imm16_X0 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_IMM16_X1_HW0_LAST), - 16, 1, 0, 0, 0, 0, - create_Imm16_X1, get_Imm16_X1 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 0, 1, 0, 0, - create_Dest_X0, get_Dest_X0 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcA_X0, get_SrcA_X0 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 0, 1, 0, 0, - create_Dest_X1, get_Dest_X1 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcA_X1, get_SrcA_X1 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 0, 1, 0, 0, - create_Dest_Y0, get_Dest_Y0 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcA_Y0, get_SrcA_Y0 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 0, 1, 0, 0, - create_Dest_Y1, get_Dest_Y1 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcA_Y1, get_SrcA_Y1 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcA_Y2, get_SrcA_Y2 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 1, 0, 0, - create_SrcA_X1, get_SrcA_X1 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcB_X0, get_SrcB_X0 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcB_X1, get_SrcB_X1 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcB_Y0, get_SrcB_Y0 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcB_Y1, get_SrcB_Y1 - }, - { - TILEGX_OP_TYPE_ADDRESS, BFD_RELOC(TILEGX_BROFF_X1), - 17, 1, 0, 0, 1, TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, - create_BrOff_X1, get_BrOff_X1 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_MMSTART_X0), - 6, 0, 0, 0, 0, 0, - create_BFStart_X0, get_BFStart_X0 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_MMEND_X0), - 6, 0, 0, 0, 0, 0, - create_BFEnd_X0, get_BFEnd_X0 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 1, 0, 0, - create_Dest_X0, get_Dest_X0 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 1, 0, 0, - create_Dest_Y0, get_Dest_Y0 - }, - { - TILEGX_OP_TYPE_ADDRESS, BFD_RELOC(TILEGX_JUMPOFF_X1), - 27, 1, 0, 0, 1, TILEGX_LOG2_BUNDLE_ALIGNMENT_IN_BYTES, - create_JumpOff_X1, get_JumpOff_X1 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 0, 1, 0, 0, - create_SrcBDest_Y2, get_SrcBDest_Y2 - }, - { - TILEGX_OP_TYPE_SPR, BFD_RELOC(TILEGX_MF_IMM14_X1), - 14, 0, 0, 0, 0, 0, - create_MF_Imm14_X1, get_MF_Imm14_X1 - }, - { - TILEGX_OP_TYPE_SPR, BFD_RELOC(TILEGX_MT_IMM14_X1), - 14, 0, 0, 0, 0, 0, - create_MT_Imm14_X1, get_MT_Imm14_X1 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_X0), - 6, 0, 0, 0, 0, 0, - create_ShAmt_X0, get_ShAmt_X0 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_X1), - 6, 0, 0, 0, 0, 0, - create_ShAmt_X1, get_ShAmt_X1 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_Y0), - 6, 0, 0, 0, 0, 0, - create_ShAmt_Y0, get_ShAmt_Y0 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_SHAMT_Y1), - 6, 0, 0, 0, 0, 0, - create_ShAmt_Y1, get_ShAmt_Y1 - }, - { - TILEGX_OP_TYPE_REGISTER, BFD_RELOC(NONE), - 6, 0, 1, 0, 0, 0, - create_SrcBDest_Y2, get_SrcBDest_Y2 - }, - { - TILEGX_OP_TYPE_IMMEDIATE, BFD_RELOC(TILEGX_DEST_IMM8_X1), - 8, 1, 0, 0, 0, 0, - create_Dest_Imm8_X1, get_Dest_Imm8_X1 - } -}; - - - - -/* Given a set of bundle bits and the lookup FSM for a specific pipe, - * returns which instruction the bundle contains in that pipe. - */ -static const struct tilegx_opcode * -find_opcode(tilegx_bundle_bits bits, const unsigned short *table) -{ - int index = 0; - - while (1) - { - unsigned short bitspec = table[index]; - unsigned int bitfield = - ((unsigned int)(bits >> (bitspec & 63))) & (bitspec >> 6); - - unsigned short next = table[index + 1 + bitfield]; - if (next <= TILEGX_OPC_NONE) - return &tilegx_opcodes[next]; - - index = next - TILEGX_OPC_NONE; - } -} - - -int -parse_insn_tilegx(tilegx_bundle_bits bits, - unsigned long long pc, - struct tilegx_decoded_instruction - decoded[TILEGX_MAX_INSTRUCTIONS_PER_BUNDLE]) -{ - int num_instructions = 0; - int pipe; - - int min_pipe, max_pipe; - if ((bits & TILEGX_BUNDLE_MODE_MASK) == 0) - { - min_pipe = TILEGX_PIPELINE_X0; - max_pipe = TILEGX_PIPELINE_X1; - } - else - { - min_pipe = TILEGX_PIPELINE_Y0; - max_pipe = TILEGX_PIPELINE_Y2; - } - - /* For each pipe, find an instruction that fits. */ - for (pipe = min_pipe; pipe <= max_pipe; pipe++) - { - const struct tilegx_opcode *opc; - struct tilegx_decoded_instruction *d; - int i; - - d = &decoded[num_instructions++]; - opc = find_opcode (bits, tilegx_bundle_decoder_fsms[pipe]); - d->opcode = opc; - - /* Decode each operand, sign extending, etc. as appropriate. */ - for (i = 0; i < opc->num_operands; i++) - { - const struct tilegx_operand *op = - &tilegx_operands[opc->operands[pipe][i]]; - int raw_opval = op->extract (bits); - long long opval; - - if (op->is_signed) - { - /* Sign-extend the operand. */ - int shift = (int)((sizeof(int) * 8) - op->num_bits); - raw_opval = (raw_opval << shift) >> shift; - } - - /* Adjust PC-relative scaled branch offsets. */ - if (op->type == TILEGX_OP_TYPE_ADDRESS) - opval = (raw_opval * TILEGX_BUNDLE_SIZE_IN_BYTES) + pc; - else - opval = raw_opval; - - /* Record the final value. */ - d->operands[i] = op; - d->operand_values[i] = opval; - } - } - - return num_instructions; -} diff --git a/arch/tile/kernel/time.c b/arch/tile/kernel/time.c deleted file mode 100644 index f95d65f3162b..000000000000 --- a/arch/tile/kernel/time.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Support the cycle counter clocksource and tile timer clock event device. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * Define the cycle counter clock source. - */ - -/* How many cycles per second we are running at. */ -static cycles_t cycles_per_sec __ro_after_init; - -cycles_t get_clock_rate(void) -{ - return cycles_per_sec; -} - -#if CHIP_HAS_SPLIT_CYCLE() -cycles_t get_cycles(void) -{ - unsigned int high = __insn_mfspr(SPR_CYCLE_HIGH); - unsigned int low = __insn_mfspr(SPR_CYCLE_LOW); - unsigned int high2 = __insn_mfspr(SPR_CYCLE_HIGH); - - while (unlikely(high != high2)) { - low = __insn_mfspr(SPR_CYCLE_LOW); - high = high2; - high2 = __insn_mfspr(SPR_CYCLE_HIGH); - } - - return (((cycles_t)high) << 32) | low; -} -EXPORT_SYMBOL(get_cycles); -#endif - -/* - * We use a relatively small shift value so that sched_clock() - * won't wrap around very often. - */ -#define SCHED_CLOCK_SHIFT 10 - -static unsigned long sched_clock_mult __ro_after_init; - -static cycles_t clocksource_get_cycles(struct clocksource *cs) -{ - return get_cycles(); -} - -static struct clocksource cycle_counter_cs = { - .name = "cycle counter", - .rating = 300, - .read = clocksource_get_cycles, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -/* - * Called very early from setup_arch() to set cycles_per_sec. - * We initialize it early so we can use it to set up loops_per_jiffy. - */ -void __init setup_clock(void) -{ - cycles_per_sec = hv_sysconf(HV_SYSCONF_CPU_SPEED); - sched_clock_mult = - clocksource_hz2mult(cycles_per_sec, SCHED_CLOCK_SHIFT); -} - -void __init calibrate_delay(void) -{ - loops_per_jiffy = get_clock_rate() / HZ; - pr_info("Clock rate yields %lu.%02lu BogoMIPS (lpj=%lu)\n", - loops_per_jiffy / (500000 / HZ), - (loops_per_jiffy / (5000 / HZ)) % 100, loops_per_jiffy); -} - -/* Called fairly late in init/main.c, but before we go smp. */ -void __init time_init(void) -{ - /* Initialize and register the clock source. */ - clocksource_register_hz(&cycle_counter_cs, cycles_per_sec); - - /* Start up the tile-timer interrupt source on the boot cpu. */ - setup_tile_timer(); -} - -/* - * Define the tile timer clock event device. The timer is driven by - * the TILE_TIMER_CONTROL register, which consists of a 31-bit down - * counter, plus bit 31, which signifies that the counter has wrapped - * from zero to (2**31) - 1. The INT_TILE_TIMER interrupt will be - * raised as long as bit 31 is set. - * - * The TILE_MINSEC value represents the largest range of real-time - * we can possibly cover with the timer, based on MAX_TICK combined - * with the slowest reasonable clock rate we might run at. - */ - -#define MAX_TICK 0x7fffffff /* we have 31 bits of countdown timer */ -#define TILE_MINSEC 5 /* timer covers no more than 5 seconds */ - -static int tile_timer_set_next_event(unsigned long ticks, - struct clock_event_device *evt) -{ - BUG_ON(ticks > MAX_TICK); - __insn_mtspr(SPR_TILE_TIMER_CONTROL, ticks); - arch_local_irq_unmask_now(INT_TILE_TIMER); - return 0; -} - -/* - * Whenever anyone tries to change modes, we just mask interrupts - * and wait for the next event to get set. - */ -static int tile_timer_shutdown(struct clock_event_device *evt) -{ - arch_local_irq_mask_now(INT_TILE_TIMER); - return 0; -} - -/* - * Set min_delta_ns to 1 microsecond, since it takes about - * that long to fire the interrupt. - */ -static DEFINE_PER_CPU(struct clock_event_device, tile_timer) = { - .name = "tile timer", - .features = CLOCK_EVT_FEAT_ONESHOT, - .min_delta_ns = 1000, - .min_delta_ticks = 1, - .max_delta_ticks = MAX_TICK, - .rating = 100, - .irq = -1, - .set_next_event = tile_timer_set_next_event, - .set_state_shutdown = tile_timer_shutdown, - .set_state_oneshot = tile_timer_shutdown, - .set_state_oneshot_stopped = tile_timer_shutdown, - .tick_resume = tile_timer_shutdown, -}; - -void setup_tile_timer(void) -{ - struct clock_event_device *evt = this_cpu_ptr(&tile_timer); - - /* Fill in fields that are speed-specific. */ - clockevents_calc_mult_shift(evt, cycles_per_sec, TILE_MINSEC); - evt->max_delta_ns = clockevent_delta2ns(MAX_TICK, evt); - - /* Mark as being for this cpu only. */ - evt->cpumask = cpumask_of(smp_processor_id()); - - /* Start out with timer not firing. */ - arch_local_irq_mask_now(INT_TILE_TIMER); - - /* Register tile timer. */ - clockevents_register_device(evt); -} - -/* Called from the interrupt vector. */ -void do_timer_interrupt(struct pt_regs *regs, int fault_num) -{ - struct pt_regs *old_regs = set_irq_regs(regs); - struct clock_event_device *evt = this_cpu_ptr(&tile_timer); - - /* - * Mask the timer interrupt here, since we are a oneshot timer - * and there are now by definition no events pending. - */ - arch_local_irq_mask(INT_TILE_TIMER); - - /* Track time spent here in an interrupt context */ - irq_enter(); - - /* Track interrupt count. */ - __this_cpu_inc(irq_stat.irq_timer_count); - - /* Call the generic timer handler */ - evt->event_handler(evt); - - /* - * Track time spent against the current process again and - * process any softirqs if they are waiting. - */ - irq_exit(); - - set_irq_regs(old_regs); -} - -/* - * Scheduler clock - returns current time in nanosec units. - * Note that with LOCKDEP, this is called during lockdep_init(), and - * we will claim that sched_clock() is zero for a little while, until - * we run setup_clock(), above. - */ -unsigned long long sched_clock(void) -{ - return mult_frac(get_cycles(), - sched_clock_mult, 1ULL << SCHED_CLOCK_SHIFT); -} - -int setup_profiling_timer(unsigned int multiplier) -{ - return -EINVAL; -} - -/* - * Use the tile timer to convert nsecs to core clock cycles, relying - * on it having the same frequency as SPR_CYCLE. - */ -cycles_t ns2cycles(unsigned long nsecs) -{ - /* - * We do not have to disable preemption here as each core has the same - * clock frequency. - */ - struct clock_event_device *dev = raw_cpu_ptr(&tile_timer); - - /* - * as in clocksource.h and x86's timer.h, we split the calculation - * into 2 parts to avoid unecessary overflow of the intermediate - * value. This will not lead to any loss of precision. - */ - u64 quot = (u64)nsecs >> dev->shift; - u64 rem = (u64)nsecs & ((1ULL << dev->shift) - 1); - return quot * dev->mult + ((rem * dev->mult) >> dev->shift); -} - -void update_vsyscall_tz(void) -{ - write_seqcount_begin(&vdso_data->tz_seq); - vdso_data->tz_minuteswest = sys_tz.tz_minuteswest; - vdso_data->tz_dsttime = sys_tz.tz_dsttime; - write_seqcount_end(&vdso_data->tz_seq); -} - -void update_vsyscall(struct timekeeper *tk) -{ - if (tk->tkr_mono.clock != &cycle_counter_cs) - return; - - write_seqcount_begin(&vdso_data->tb_seq); - - vdso_data->cycle_last = tk->tkr_mono.cycle_last; - vdso_data->mask = tk->tkr_mono.mask; - vdso_data->mult = tk->tkr_mono.mult; - vdso_data->shift = tk->tkr_mono.shift; - - vdso_data->wall_time_sec = tk->xtime_sec; - vdso_data->wall_time_snsec = tk->tkr_mono.xtime_nsec; - - vdso_data->monotonic_time_sec = tk->xtime_sec - + tk->wall_to_monotonic.tv_sec; - vdso_data->monotonic_time_snsec = tk->tkr_mono.xtime_nsec - + ((u64)tk->wall_to_monotonic.tv_nsec - << tk->tkr_mono.shift); - while (vdso_data->monotonic_time_snsec >= - (((u64)NSEC_PER_SEC) << tk->tkr_mono.shift)) { - vdso_data->monotonic_time_snsec -= - ((u64)NSEC_PER_SEC) << tk->tkr_mono.shift; - vdso_data->monotonic_time_sec++; - } - - vdso_data->wall_time_coarse_sec = tk->xtime_sec; - vdso_data->wall_time_coarse_nsec = (long)(tk->tkr_mono.xtime_nsec >> - tk->tkr_mono.shift); - - vdso_data->monotonic_time_coarse_sec = - vdso_data->wall_time_coarse_sec + tk->wall_to_monotonic.tv_sec; - vdso_data->monotonic_time_coarse_nsec = - vdso_data->wall_time_coarse_nsec + tk->wall_to_monotonic.tv_nsec; - - while (vdso_data->monotonic_time_coarse_nsec >= NSEC_PER_SEC) { - vdso_data->monotonic_time_coarse_nsec -= NSEC_PER_SEC; - vdso_data->monotonic_time_coarse_sec++; - } - - write_seqcount_end(&vdso_data->tb_seq); -} diff --git a/arch/tile/kernel/tlb.c b/arch/tile/kernel/tlb.c deleted file mode 100644 index f23b53515671..000000000000 --- a/arch/tile/kernel/tlb.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - */ - -#include -#include -#include -#include -#include -#include - -/* From tlbflush.h */ -DEFINE_PER_CPU(int, current_asid); -int min_asid, max_asid; - -/* - * Note that we flush the L1I (for VM_EXEC pages) as well as the TLB - * so that when we are unmapping an executable page, we also flush it. - * Combined with flushing the L1I at context switch time, this means - * we don't have to do any other icache flushes. - */ - -void flush_tlb_mm(struct mm_struct *mm) -{ - HV_Remote_ASID asids[NR_CPUS]; - int i = 0, cpu; - for_each_cpu(cpu, mm_cpumask(mm)) { - HV_Remote_ASID *asid = &asids[i++]; - asid->y = cpu / smp_topology.width; - asid->x = cpu % smp_topology.width; - asid->asid = per_cpu(current_asid, cpu); - } - flush_remote(0, HV_FLUSH_EVICT_L1I, mm_cpumask(mm), - 0, 0, 0, NULL, asids, i); -} - -void flush_tlb_current_task(void) -{ - flush_tlb_mm(current->mm); -} - -void flush_tlb_page_mm(struct vm_area_struct *vma, struct mm_struct *mm, - unsigned long va) -{ - unsigned long size = vma_kernel_pagesize(vma); - int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0; - flush_remote(0, cache, mm_cpumask(mm), - va, size, size, mm_cpumask(mm), NULL, 0); -} - -void flush_tlb_page(struct vm_area_struct *vma, unsigned long va) -{ - flush_tlb_page_mm(vma, vma->vm_mm, va); -} -EXPORT_SYMBOL(flush_tlb_page); - -void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - unsigned long size = vma_kernel_pagesize(vma); - struct mm_struct *mm = vma->vm_mm; - int cache = (vma->vm_flags & VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0; - flush_remote(0, cache, mm_cpumask(mm), start, end - start, size, - mm_cpumask(mm), NULL, 0); -} - -void flush_tlb_all(void) -{ - int i; - for (i = 0; ; ++i) { - HV_VirtAddrRange r = hv_inquire_virtual(i); - if (r.size == 0) - break; - flush_remote(0, HV_FLUSH_EVICT_L1I, cpu_online_mask, - r.start, r.size, PAGE_SIZE, cpu_online_mask, - NULL, 0); - flush_remote(0, 0, NULL, - r.start, r.size, HPAGE_SIZE, cpu_online_mask, - NULL, 0); - } -} - -/* - * Callers need to flush the L1I themselves if necessary, e.g. for - * kernel module unload. Otherwise we assume callers are not using - * executable pgprot_t's. Using EVICT_L1I means that dataplane cpus - * will get an unnecessary interrupt otherwise. - */ -void flush_tlb_kernel_range(unsigned long start, unsigned long end) -{ - flush_remote(0, 0, NULL, - start, end - start, PAGE_SIZE, cpu_online_mask, NULL, 0); -} diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c deleted file mode 100644 index 83a7186198d7..000000000000 --- a/arch/tile/kernel/traps.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -void __init trap_init(void) -{ - /* Nothing needed here since we link code at .intrpt */ -} - -int unaligned_fixup = 1; - -static int __init setup_unaligned_fixup(char *str) -{ - /* - * Say "=-1" to completely disable it. If you just do "=0", we - * will still parse the instruction, then fire a SIGBUS with - * the correct address from inside the single_step code. - */ - if (kstrtoint(str, 0, &unaligned_fixup) != 0) - return 0; - - pr_info("Fixups for unaligned data accesses are %s\n", - unaligned_fixup >= 0 ? - (unaligned_fixup ? "enabled" : "disabled") : - "completely disabled"); - return 1; -} -__setup("unaligned_fixup=", setup_unaligned_fixup); - -#if CHIP_HAS_TILE_DMA() - -static int dma_disabled; - -static int __init nodma(char *str) -{ - pr_info("User-space DMA is disabled\n"); - dma_disabled = 1; - return 1; -} -__setup("nodma", nodma); - -/* How to decode SPR_GPV_REASON */ -#define IRET_ERROR (1U << 31) -#define MT_ERROR (1U << 30) -#define MF_ERROR (1U << 29) -#define SPR_INDEX ((1U << 15) - 1) -#define SPR_MPL_SHIFT 9 /* starting bit position for MPL encoded in SPR */ - -/* - * See if this GPV is just to notify the kernel of SPR use and we can - * retry the user instruction after adjusting some MPLs suitably. - */ -static int retry_gpv(unsigned int gpv_reason) -{ - int mpl; - - if (gpv_reason & IRET_ERROR) - return 0; - - BUG_ON((gpv_reason & (MT_ERROR|MF_ERROR)) == 0); - mpl = (gpv_reason & SPR_INDEX) >> SPR_MPL_SHIFT; - if (mpl == INT_DMA_NOTIFY && !dma_disabled) { - /* User is turning on DMA. Allow it and retry. */ - printk(KERN_DEBUG "Process %d/%s is now enabled for DMA\n", - current->pid, current->comm); - BUG_ON(current->thread.tile_dma_state.enabled); - current->thread.tile_dma_state.enabled = 1; - grant_dma_mpls(); - return 1; - } - - return 0; -} - -#endif /* CHIP_HAS_TILE_DMA() */ - -extern tile_bundle_bits bpt_code; - -asm(".pushsection .rodata.bpt_code,\"a\";" - ".align 8;" - "bpt_code: bpt;" - ".size bpt_code,.-bpt_code;" - ".popsection"); - -static int special_ill(tile_bundle_bits bundle, int *sigp, int *codep) -{ - int sig, code, maxcode; - - if (bundle == bpt_code) { - *sigp = SIGTRAP; - *codep = TRAP_BRKPT; - return 1; - } - - /* If it's a "raise" bundle, then "ill" must be in pipe X1. */ -#ifdef __tilegx__ - if ((bundle & TILEGX_BUNDLE_MODE_MASK) != 0) - return 0; - if (get_Opcode_X1(bundle) != RRR_0_OPCODE_X1) - return 0; - if (get_RRROpcodeExtension_X1(bundle) != UNARY_RRR_0_OPCODE_X1) - return 0; - if (get_UnaryOpcodeExtension_X1(bundle) != ILL_UNARY_OPCODE_X1) - return 0; -#else - if (bundle & TILEPRO_BUNDLE_Y_ENCODING_MASK) - return 0; - if (get_Opcode_X1(bundle) != SHUN_0_OPCODE_X1) - return 0; - if (get_UnShOpcodeExtension_X1(bundle) != UN_0_SHUN_0_OPCODE_X1) - return 0; - if (get_UnOpcodeExtension_X1(bundle) != ILL_UN_0_SHUN_0_OPCODE_X1) - return 0; -#endif - - /* Check that the magic distinguishers are set to mean "raise". */ - if (get_Dest_X1(bundle) != 29 || get_SrcA_X1(bundle) != 37) - return 0; - - /* There must be an "addli zero, zero, VAL" in X0. */ - if (get_Opcode_X0(bundle) != ADDLI_OPCODE_X0) - return 0; - if (get_Dest_X0(bundle) != TREG_ZERO) - return 0; - if (get_SrcA_X0(bundle) != TREG_ZERO) - return 0; - - /* - * Validate the proposed signal number and si_code value. - * Note that we embed these in the static instruction itself - * so that we perturb the register state as little as possible - * at the time of the actual fault; it's unlikely you'd ever - * need to dynamically choose which kind of fault to raise - * from user space. - */ - sig = get_Imm16_X0(bundle) & 0x3f; - switch (sig) { - case SIGILL: - maxcode = NSIGILL; - break; - case SIGFPE: - maxcode = NSIGFPE; - break; - case SIGSEGV: - maxcode = NSIGSEGV; - break; - case SIGBUS: - maxcode = NSIGBUS; - break; - case SIGTRAP: - maxcode = NSIGTRAP; - break; - default: - return 0; - } - code = (get_Imm16_X0(bundle) >> 6) & 0xf; - if (code <= 0 || code > maxcode) - return 0; - - /* Make it the requested signal. */ - *sigp = sig; - *codep = code; - return 1; -} - -static const char *const int_name[] = { - [INT_MEM_ERROR] = "Memory error", - [INT_ILL] = "Illegal instruction", - [INT_GPV] = "General protection violation", - [INT_UDN_ACCESS] = "UDN access", - [INT_IDN_ACCESS] = "IDN access", -#if CHIP_HAS_SN() - [INT_SN_ACCESS] = "SN access", -#endif - [INT_SWINT_3] = "Software interrupt 3", - [INT_SWINT_2] = "Software interrupt 2", - [INT_SWINT_0] = "Software interrupt 0", - [INT_UNALIGN_DATA] = "Unaligned data", - [INT_DOUBLE_FAULT] = "Double fault", -#ifdef __tilegx__ - [INT_ILL_TRANS] = "Illegal virtual address", -#endif -}; - -static int do_bpt(struct pt_regs *regs) -{ - unsigned long bundle, bcode, bpt; - - bundle = *(unsigned long *)instruction_pointer(regs); - - /* - * bpt shoule be { bpt; nop }, which is 0x286a44ae51485000ULL. - * we encode the unused least significant bits for other purpose. - */ - bpt = bundle & ~((1ULL << 12) - 1); - if (bpt != TILE_BPT_BUNDLE) - return 0; - - bcode = bundle & ((1ULL << 12) - 1); - /* - * notify the kprobe handlers, if instruction is likely to - * pertain to them. - */ - switch (bcode) { - /* breakpoint_insn */ - case 0: - notify_die(DIE_BREAK, "debug", regs, bundle, - INT_ILL, SIGTRAP); - break; - /* compiled_bpt */ - case DIE_COMPILED_BPT: - notify_die(DIE_COMPILED_BPT, "debug", regs, bundle, - INT_ILL, SIGTRAP); - break; - /* breakpoint2_insn */ - case DIE_SSTEPBP: - notify_die(DIE_SSTEPBP, "single_step", regs, bundle, - INT_ILL, SIGTRAP); - break; - default: - return 0; - } - - return 1; -} - -void __kprobes do_trap(struct pt_regs *regs, int fault_num, - unsigned long reason) -{ - siginfo_t info; - int signo, code; - unsigned long address = 0; - tile_bundle_bits instr; - int is_kernel = !user_mode(regs); - - clear_siginfo(&info); - - /* Handle breakpoints, etc. */ - if (is_kernel && fault_num == INT_ILL && do_bpt(regs)) - return; - - /* Re-enable interrupts, if they were previously enabled. */ - if (!(regs->flags & PT_FLAGS_DISABLE_IRQ)) - local_irq_enable(); - - /* - * If it hits in kernel mode and we can't fix it up, just exit the - * current process and hope for the best. - */ - if (is_kernel) { - const char *name; - char buf[100]; - if (fixup_exception(regs)) /* ILL_TRANS or UNALIGN_DATA */ - return; - if (fault_num >= 0 && - fault_num < ARRAY_SIZE(int_name) && - int_name[fault_num] != NULL) - name = int_name[fault_num]; - else - name = "Unknown interrupt"; - if (fault_num == INT_GPV) - snprintf(buf, sizeof(buf), "; GPV_REASON %#lx", reason); -#ifdef __tilegx__ - else if (fault_num == INT_ILL_TRANS) - snprintf(buf, sizeof(buf), "; address %#lx", reason); -#endif - else - buf[0] = '\0'; - pr_alert("Kernel took bad trap %d (%s) at PC %#lx%s\n", - fault_num, name, regs->pc, buf); - show_regs(regs); - do_exit(SIGKILL); /* FIXME: implement i386 die() */ - } - - switch (fault_num) { - case INT_MEM_ERROR: - signo = SIGBUS; - code = BUS_OBJERR; - break; - case INT_ILL: - if (copy_from_user(&instr, (void __user *)regs->pc, - sizeof(instr))) { - pr_err("Unreadable instruction for INT_ILL: %#lx\n", - regs->pc); - do_exit(SIGKILL); - } - if (!special_ill(instr, &signo, &code)) { - signo = SIGILL; - code = ILL_ILLOPC; - } - address = regs->pc; - break; - case INT_GPV: -#if CHIP_HAS_TILE_DMA() - if (retry_gpv(reason)) - return; -#endif - /*FALLTHROUGH*/ - case INT_UDN_ACCESS: - case INT_IDN_ACCESS: -#if CHIP_HAS_SN() - case INT_SN_ACCESS: -#endif - signo = SIGILL; - code = ILL_PRVREG; - address = regs->pc; - break; - case INT_SWINT_3: - case INT_SWINT_2: - case INT_SWINT_0: - signo = SIGILL; - code = ILL_ILLTRP; - address = regs->pc; - break; - case INT_UNALIGN_DATA: -#ifndef __tilegx__ /* Emulated support for single step debugging */ - if (unaligned_fixup >= 0) { - struct single_step_state *state = - current_thread_info()->step_state; - if (!state || - (void __user *)(regs->pc) != state->buffer) { - single_step_once(regs); - return; - } - } -#endif - signo = SIGBUS; - code = BUS_ADRALN; - address = 0; - break; - case INT_DOUBLE_FAULT: - /* - * For double fault, "reason" is actually passed as - * SYSTEM_SAVE_K_2, the hypervisor's double-fault info, so - * we can provide the original fault number rather than - * the uninteresting "INT_DOUBLE_FAULT" so the user can - * learn what actually struck while PL0 ICS was set. - */ - fault_num = reason; - signo = SIGILL; - code = ILL_DBLFLT; - address = regs->pc; - break; -#ifdef __tilegx__ - case INT_ILL_TRANS: { - /* Avoid a hardware erratum with the return address stack. */ - fill_ra_stack(); - - signo = SIGSEGV; - address = reason; - code = SEGV_MAPERR; - break; - } -#endif - default: - panic("Unexpected do_trap interrupt number %d", fault_num); - } - - info.si_signo = signo; - info.si_code = code; - info.si_addr = (void __user *)address; - if (signo == SIGILL) - info.si_trapno = fault_num; - if (signo != SIGTRAP) - trace_unhandled_signal("trap", regs, address, signo); - force_sig_info(signo, &info, current); -} - -void do_nmi(struct pt_regs *regs, int fault_num, unsigned long reason) -{ - nmi_enter(); - switch (reason) { -#ifdef arch_trigger_cpumask_backtrace - case TILE_NMI_DUMP_STACK: - nmi_cpu_backtrace(regs); - break; -#endif - default: - panic("Unexpected do_nmi type %ld", reason); - } - nmi_exit(); -} - -/* Deprecated function currently only used here. */ -extern void _dump_stack(int dummy, ulong pc, ulong lr, ulong sp, ulong r52); - -void kernel_double_fault(int dummy, ulong pc, ulong lr, ulong sp, ulong r52) -{ - _dump_stack(dummy, pc, lr, sp, r52); - pr_emerg("Double fault: exiting\n"); - machine_halt(); -} diff --git a/arch/tile/kernel/unaligned.c b/arch/tile/kernel/unaligned.c deleted file mode 100644 index 77a0b6b6a2a1..000000000000 --- a/arch/tile/kernel/unaligned.c +++ /dev/null @@ -1,1603 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * A code-rewriter that handles unaligned exception. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * This file handles unaligned exception for tile-Gx. The tilepro's unaligned - * exception is supported out of single_step.c - */ - -int unaligned_printk; - -static int __init setup_unaligned_printk(char *str) -{ - long val; - if (kstrtol(str, 0, &val) != 0) - return 0; - unaligned_printk = val; - pr_info("Printk for each unaligned data accesses is %s\n", - unaligned_printk ? "enabled" : "disabled"); - return 1; -} -__setup("unaligned_printk=", setup_unaligned_printk); - -unsigned int unaligned_fixup_count; - -#ifdef __tilegx__ - -/* - * Unalign data jit fixup code fragement. Reserved space is 128 bytes. - * The 1st 64-bit word saves fault PC address, 2nd word is the fault - * instruction bundle followed by 14 JIT bundles. - */ - -struct unaligned_jit_fragment { - unsigned long pc; - tilegx_bundle_bits bundle; - tilegx_bundle_bits insn[14]; -}; - -/* - * Check if a nop or fnop at bundle's pipeline X0. - */ - -static bool is_bundle_x0_nop(tilegx_bundle_bits bundle) -{ - return (((get_UnaryOpcodeExtension_X0(bundle) == - NOP_UNARY_OPCODE_X0) && - (get_RRROpcodeExtension_X0(bundle) == - UNARY_RRR_0_OPCODE_X0) && - (get_Opcode_X0(bundle) == - RRR_0_OPCODE_X0)) || - ((get_UnaryOpcodeExtension_X0(bundle) == - FNOP_UNARY_OPCODE_X0) && - (get_RRROpcodeExtension_X0(bundle) == - UNARY_RRR_0_OPCODE_X0) && - (get_Opcode_X0(bundle) == - RRR_0_OPCODE_X0))); -} - -/* - * Check if nop or fnop at bundle's pipeline X1. - */ - -static bool is_bundle_x1_nop(tilegx_bundle_bits bundle) -{ - return (((get_UnaryOpcodeExtension_X1(bundle) == - NOP_UNARY_OPCODE_X1) && - (get_RRROpcodeExtension_X1(bundle) == - UNARY_RRR_0_OPCODE_X1) && - (get_Opcode_X1(bundle) == - RRR_0_OPCODE_X1)) || - ((get_UnaryOpcodeExtension_X1(bundle) == - FNOP_UNARY_OPCODE_X1) && - (get_RRROpcodeExtension_X1(bundle) == - UNARY_RRR_0_OPCODE_X1) && - (get_Opcode_X1(bundle) == - RRR_0_OPCODE_X1))); -} - -/* - * Check if nop or fnop at bundle's Y0 pipeline. - */ - -static bool is_bundle_y0_nop(tilegx_bundle_bits bundle) -{ - return (((get_UnaryOpcodeExtension_Y0(bundle) == - NOP_UNARY_OPCODE_Y0) && - (get_RRROpcodeExtension_Y0(bundle) == - UNARY_RRR_1_OPCODE_Y0) && - (get_Opcode_Y0(bundle) == - RRR_1_OPCODE_Y0)) || - ((get_UnaryOpcodeExtension_Y0(bundle) == - FNOP_UNARY_OPCODE_Y0) && - (get_RRROpcodeExtension_Y0(bundle) == - UNARY_RRR_1_OPCODE_Y0) && - (get_Opcode_Y0(bundle) == - RRR_1_OPCODE_Y0))); -} - -/* - * Check if nop or fnop at bundle's pipeline Y1. - */ - -static bool is_bundle_y1_nop(tilegx_bundle_bits bundle) -{ - return (((get_UnaryOpcodeExtension_Y1(bundle) == - NOP_UNARY_OPCODE_Y1) && - (get_RRROpcodeExtension_Y1(bundle) == - UNARY_RRR_1_OPCODE_Y1) && - (get_Opcode_Y1(bundle) == - RRR_1_OPCODE_Y1)) || - ((get_UnaryOpcodeExtension_Y1(bundle) == - FNOP_UNARY_OPCODE_Y1) && - (get_RRROpcodeExtension_Y1(bundle) == - UNARY_RRR_1_OPCODE_Y1) && - (get_Opcode_Y1(bundle) == - RRR_1_OPCODE_Y1))); -} - -/* - * Test if a bundle's y0 and y1 pipelines are both nop or fnop. - */ - -static bool is_y0_y1_nop(tilegx_bundle_bits bundle) -{ - return is_bundle_y0_nop(bundle) && is_bundle_y1_nop(bundle); -} - -/* - * Test if a bundle's x0 and x1 pipelines are both nop or fnop. - */ - -static bool is_x0_x1_nop(tilegx_bundle_bits bundle) -{ - return is_bundle_x0_nop(bundle) && is_bundle_x1_nop(bundle); -} - -/* - * Find the destination, source registers of fault unalign access instruction - * at X1 or Y2. Also, allocate up to 3 scratch registers clob1, clob2 and - * clob3, which are guaranteed different from any register used in the fault - * bundle. r_alias is used to return if the other instructions other than the - * unalign load/store shares same register with ra, rb and rd. - */ - -static void find_regs(tilegx_bundle_bits bundle, uint64_t *rd, uint64_t *ra, - uint64_t *rb, uint64_t *clob1, uint64_t *clob2, - uint64_t *clob3, bool *r_alias) -{ - int i; - uint64_t reg; - uint64_t reg_map = 0, alias_reg_map = 0, map; - bool alias = false; - - /* - * Parse fault bundle, find potential used registers and mark - * corresponding bits in reg_map and alias_map. These 2 bit maps - * are used to find the scratch registers and determine if there - * is register alias. - */ - if (bundle & TILEGX_BUNDLE_MODE_MASK) { /* Y Mode Bundle. */ - - reg = get_SrcA_Y2(bundle); - reg_map |= 1ULL << reg; - *ra = reg; - reg = get_SrcBDest_Y2(bundle); - reg_map |= 1ULL << reg; - - if (rd) { - /* Load. */ - *rd = reg; - alias_reg_map = (1ULL << *rd) | (1ULL << *ra); - } else { - /* Store. */ - *rb = reg; - alias_reg_map = (1ULL << *ra) | (1ULL << *rb); - } - - if (!is_bundle_y1_nop(bundle)) { - reg = get_SrcA_Y1(bundle); - reg_map |= (1ULL << reg); - map = (1ULL << reg); - - reg = get_SrcB_Y1(bundle); - reg_map |= (1ULL << reg); - map |= (1ULL << reg); - - reg = get_Dest_Y1(bundle); - reg_map |= (1ULL << reg); - map |= (1ULL << reg); - - if (map & alias_reg_map) - alias = true; - } - - if (!is_bundle_y0_nop(bundle)) { - reg = get_SrcA_Y0(bundle); - reg_map |= (1ULL << reg); - map = (1ULL << reg); - - reg = get_SrcB_Y0(bundle); - reg_map |= (1ULL << reg); - map |= (1ULL << reg); - - reg = get_Dest_Y0(bundle); - reg_map |= (1ULL << reg); - map |= (1ULL << reg); - - if (map & alias_reg_map) - alias = true; - } - } else { /* X Mode Bundle. */ - - reg = get_SrcA_X1(bundle); - reg_map |= (1ULL << reg); - *ra = reg; - if (rd) { - /* Load. */ - reg = get_Dest_X1(bundle); - reg_map |= (1ULL << reg); - *rd = reg; - alias_reg_map = (1ULL << *rd) | (1ULL << *ra); - } else { - /* Store. */ - reg = get_SrcB_X1(bundle); - reg_map |= (1ULL << reg); - *rb = reg; - alias_reg_map = (1ULL << *ra) | (1ULL << *rb); - } - - if (!is_bundle_x0_nop(bundle)) { - reg = get_SrcA_X0(bundle); - reg_map |= (1ULL << reg); - map = (1ULL << reg); - - reg = get_SrcB_X0(bundle); - reg_map |= (1ULL << reg); - map |= (1ULL << reg); - - reg = get_Dest_X0(bundle); - reg_map |= (1ULL << reg); - map |= (1ULL << reg); - - if (map & alias_reg_map) - alias = true; - } - } - - /* - * "alias" indicates if the unalign access registers have collision - * with others in the same bundle. We jsut simply test all register - * operands case (RRR), ignored the case with immidate. If a bundle - * has no register alias, we may do fixup in a simple or fast manner. - * So if an immidata field happens to hit with a register, we may end - * up fall back to the generic handling. - */ - - *r_alias = alias; - - /* Flip bits on reg_map. */ - reg_map ^= -1ULL; - - /* Scan reg_map lower 54(TREG_SP) bits to find 3 set bits. */ - for (i = 0; i < TREG_SP; i++) { - if (reg_map & (0x1ULL << i)) { - if (*clob1 == -1) { - *clob1 = i; - } else if (*clob2 == -1) { - *clob2 = i; - } else if (*clob3 == -1) { - *clob3 = i; - return; - } - } - } -} - -/* - * Sanity check for register ra, rb, rd, clob1/2/3. Return true if any of them - * is unexpected. - */ - -static bool check_regs(uint64_t rd, uint64_t ra, uint64_t rb, - uint64_t clob1, uint64_t clob2, uint64_t clob3) -{ - bool unexpected = false; - if ((ra >= 56) && (ra != TREG_ZERO)) - unexpected = true; - - if ((clob1 >= 56) || (clob2 >= 56) || (clob3 >= 56)) - unexpected = true; - - if (rd != -1) { - if ((rd >= 56) && (rd != TREG_ZERO)) - unexpected = true; - } else { - if ((rb >= 56) && (rb != TREG_ZERO)) - unexpected = true; - } - return unexpected; -} - - -#define GX_INSN_X0_MASK ((1ULL << 31) - 1) -#define GX_INSN_X1_MASK (((1ULL << 31) - 1) << 31) -#define GX_INSN_Y0_MASK ((0xFULL << 27) | (0xFFFFFULL)) -#define GX_INSN_Y1_MASK (GX_INSN_Y0_MASK << 31) -#define GX_INSN_Y2_MASK ((0x7FULL << 51) | (0x7FULL << 20)) - -#ifdef __LITTLE_ENDIAN -#define GX_INSN_BSWAP(_bundle_) (_bundle_) -#else -#define GX_INSN_BSWAP(_bundle_) swab64(_bundle_) -#endif /* __LITTLE_ENDIAN */ - -/* - * __JIT_CODE(.) creates template bundles in .rodata.unalign_data section. - * The corresponding static function jix_x#_###(.) generates partial or - * whole bundle based on the template and given arguments. - */ - -#define __JIT_CODE(_X_) \ - asm (".pushsection .rodata.unalign_data, \"a\"\n" \ - _X_"\n" \ - ".popsection\n") - -__JIT_CODE("__unalign_jit_x1_mtspr: {mtspr 0, r0}"); -static tilegx_bundle_bits jit_x1_mtspr(int spr, int reg) -{ - extern tilegx_bundle_bits __unalign_jit_x1_mtspr; - return (GX_INSN_BSWAP(__unalign_jit_x1_mtspr) & GX_INSN_X1_MASK) | - create_MT_Imm14_X1(spr) | create_SrcA_X1(reg); -} - -__JIT_CODE("__unalign_jit_x1_mfspr: {mfspr r0, 0}"); -static tilegx_bundle_bits jit_x1_mfspr(int reg, int spr) -{ - extern tilegx_bundle_bits __unalign_jit_x1_mfspr; - return (GX_INSN_BSWAP(__unalign_jit_x1_mfspr) & GX_INSN_X1_MASK) | - create_MF_Imm14_X1(spr) | create_Dest_X1(reg); -} - -__JIT_CODE("__unalign_jit_x0_addi: {addi r0, r0, 0; iret}"); -static tilegx_bundle_bits jit_x0_addi(int rd, int ra, int imm8) -{ - extern tilegx_bundle_bits __unalign_jit_x0_addi; - return (GX_INSN_BSWAP(__unalign_jit_x0_addi) & GX_INSN_X0_MASK) | - create_Dest_X0(rd) | create_SrcA_X0(ra) | - create_Imm8_X0(imm8); -} - -__JIT_CODE("__unalign_jit_x1_ldna: {ldna r0, r0}"); -static tilegx_bundle_bits jit_x1_ldna(int rd, int ra) -{ - extern tilegx_bundle_bits __unalign_jit_x1_ldna; - return (GX_INSN_BSWAP(__unalign_jit_x1_ldna) & GX_INSN_X1_MASK) | - create_Dest_X1(rd) | create_SrcA_X1(ra); -} - -__JIT_CODE("__unalign_jit_x0_dblalign: {dblalign r0, r0 ,r0}"); -static tilegx_bundle_bits jit_x0_dblalign(int rd, int ra, int rb) -{ - extern tilegx_bundle_bits __unalign_jit_x0_dblalign; - return (GX_INSN_BSWAP(__unalign_jit_x0_dblalign) & GX_INSN_X0_MASK) | - create_Dest_X0(rd) | create_SrcA_X0(ra) | - create_SrcB_X0(rb); -} - -__JIT_CODE("__unalign_jit_x1_iret: {iret}"); -static tilegx_bundle_bits jit_x1_iret(void) -{ - extern tilegx_bundle_bits __unalign_jit_x1_iret; - return GX_INSN_BSWAP(__unalign_jit_x1_iret) & GX_INSN_X1_MASK; -} - -__JIT_CODE("__unalign_jit_x01_fnop: {fnop;fnop}"); -static tilegx_bundle_bits jit_x0_fnop(void) -{ - extern tilegx_bundle_bits __unalign_jit_x01_fnop; - return GX_INSN_BSWAP(__unalign_jit_x01_fnop) & GX_INSN_X0_MASK; -} - -static tilegx_bundle_bits jit_x1_fnop(void) -{ - extern tilegx_bundle_bits __unalign_jit_x01_fnop; - return GX_INSN_BSWAP(__unalign_jit_x01_fnop) & GX_INSN_X1_MASK; -} - -__JIT_CODE("__unalign_jit_y2_dummy: {fnop; fnop; ld zero, sp}"); -static tilegx_bundle_bits jit_y2_dummy(void) -{ - extern tilegx_bundle_bits __unalign_jit_y2_dummy; - return GX_INSN_BSWAP(__unalign_jit_y2_dummy) & GX_INSN_Y2_MASK; -} - -static tilegx_bundle_bits jit_y1_fnop(void) -{ - extern tilegx_bundle_bits __unalign_jit_y2_dummy; - return GX_INSN_BSWAP(__unalign_jit_y2_dummy) & GX_INSN_Y1_MASK; -} - -__JIT_CODE("__unalign_jit_x1_st1_add: {st1_add r1, r0, 0}"); -static tilegx_bundle_bits jit_x1_st1_add(int ra, int rb, int imm8) -{ - extern tilegx_bundle_bits __unalign_jit_x1_st1_add; - return (GX_INSN_BSWAP(__unalign_jit_x1_st1_add) & - (~create_SrcA_X1(-1)) & - GX_INSN_X1_MASK) | create_SrcA_X1(ra) | - create_SrcB_X1(rb) | create_Dest_Imm8_X1(imm8); -} - -__JIT_CODE("__unalign_jit_x1_st: {crc32_8 r1, r0, r0; st r0, r0}"); -static tilegx_bundle_bits jit_x1_st(int ra, int rb) -{ - extern tilegx_bundle_bits __unalign_jit_x1_st; - return (GX_INSN_BSWAP(__unalign_jit_x1_st) & GX_INSN_X1_MASK) | - create_SrcA_X1(ra) | create_SrcB_X1(rb); -} - -__JIT_CODE("__unalign_jit_x1_st_add: {st_add r1, r0, 0}"); -static tilegx_bundle_bits jit_x1_st_add(int ra, int rb, int imm8) -{ - extern tilegx_bundle_bits __unalign_jit_x1_st_add; - return (GX_INSN_BSWAP(__unalign_jit_x1_st_add) & - (~create_SrcA_X1(-1)) & - GX_INSN_X1_MASK) | create_SrcA_X1(ra) | - create_SrcB_X1(rb) | create_Dest_Imm8_X1(imm8); -} - -__JIT_CODE("__unalign_jit_x1_ld: {crc32_8 r1, r0, r0; ld r0, r0}"); -static tilegx_bundle_bits jit_x1_ld(int rd, int ra) -{ - extern tilegx_bundle_bits __unalign_jit_x1_ld; - return (GX_INSN_BSWAP(__unalign_jit_x1_ld) & GX_INSN_X1_MASK) | - create_Dest_X1(rd) | create_SrcA_X1(ra); -} - -__JIT_CODE("__unalign_jit_x1_ld_add: {ld_add r1, r0, 0}"); -static tilegx_bundle_bits jit_x1_ld_add(int rd, int ra, int imm8) -{ - extern tilegx_bundle_bits __unalign_jit_x1_ld_add; - return (GX_INSN_BSWAP(__unalign_jit_x1_ld_add) & - (~create_Dest_X1(-1)) & - GX_INSN_X1_MASK) | create_Dest_X1(rd) | - create_SrcA_X1(ra) | create_Imm8_X1(imm8); -} - -__JIT_CODE("__unalign_jit_x0_bfexts: {bfexts r0, r0, 0, 0}"); -static tilegx_bundle_bits jit_x0_bfexts(int rd, int ra, int bfs, int bfe) -{ - extern tilegx_bundle_bits __unalign_jit_x0_bfexts; - return (GX_INSN_BSWAP(__unalign_jit_x0_bfexts) & - GX_INSN_X0_MASK) | - create_Dest_X0(rd) | create_SrcA_X0(ra) | - create_BFStart_X0(bfs) | create_BFEnd_X0(bfe); -} - -__JIT_CODE("__unalign_jit_x0_bfextu: {bfextu r0, r0, 0, 0}"); -static tilegx_bundle_bits jit_x0_bfextu(int rd, int ra, int bfs, int bfe) -{ - extern tilegx_bundle_bits __unalign_jit_x0_bfextu; - return (GX_INSN_BSWAP(__unalign_jit_x0_bfextu) & - GX_INSN_X0_MASK) | - create_Dest_X0(rd) | create_SrcA_X0(ra) | - create_BFStart_X0(bfs) | create_BFEnd_X0(bfe); -} - -__JIT_CODE("__unalign_jit_x1_addi: {bfextu r1, r1, 0, 0; addi r0, r0, 0}"); -static tilegx_bundle_bits jit_x1_addi(int rd, int ra, int imm8) -{ - extern tilegx_bundle_bits __unalign_jit_x1_addi; - return (GX_INSN_BSWAP(__unalign_jit_x1_addi) & GX_INSN_X1_MASK) | - create_Dest_X1(rd) | create_SrcA_X1(ra) | - create_Imm8_X1(imm8); -} - -__JIT_CODE("__unalign_jit_x0_shrui: {shrui r0, r0, 0; iret}"); -static tilegx_bundle_bits jit_x0_shrui(int rd, int ra, int imm6) -{ - extern tilegx_bundle_bits __unalign_jit_x0_shrui; - return (GX_INSN_BSWAP(__unalign_jit_x0_shrui) & - GX_INSN_X0_MASK) | - create_Dest_X0(rd) | create_SrcA_X0(ra) | - create_ShAmt_X0(imm6); -} - -__JIT_CODE("__unalign_jit_x0_rotli: {rotli r0, r0, 0; iret}"); -static tilegx_bundle_bits jit_x0_rotli(int rd, int ra, int imm6) -{ - extern tilegx_bundle_bits __unalign_jit_x0_rotli; - return (GX_INSN_BSWAP(__unalign_jit_x0_rotli) & - GX_INSN_X0_MASK) | - create_Dest_X0(rd) | create_SrcA_X0(ra) | - create_ShAmt_X0(imm6); -} - -__JIT_CODE("__unalign_jit_x1_bnezt: {bnezt r0, __unalign_jit_x1_bnezt}"); -static tilegx_bundle_bits jit_x1_bnezt(int ra, int broff) -{ - extern tilegx_bundle_bits __unalign_jit_x1_bnezt; - return (GX_INSN_BSWAP(__unalign_jit_x1_bnezt) & - GX_INSN_X1_MASK) | - create_SrcA_X1(ra) | create_BrOff_X1(broff); -} - -#undef __JIT_CODE - -/* - * This function generates unalign fixup JIT. - * - * We first find unalign load/store instruction's destination, source - * registers: ra, rb and rd. and 3 scratch registers by calling - * find_regs(...). 3 scratch clobbers should not alias with any register - * used in the fault bundle. Then analyze the fault bundle to determine - * if it's a load or store, operand width, branch or address increment etc. - * At last generated JIT is copied into JIT code area in user space. - */ - -static -void jit_bundle_gen(struct pt_regs *regs, tilegx_bundle_bits bundle, - int align_ctl) -{ - struct thread_info *info = current_thread_info(); - struct unaligned_jit_fragment frag; - struct unaligned_jit_fragment *jit_code_area; - tilegx_bundle_bits bundle_2 = 0; - /* If bundle_2_enable = false, bundle_2 is fnop/nop operation. */ - bool bundle_2_enable = true; - uint64_t ra = -1, rb = -1, rd = -1, clob1 = -1, clob2 = -1, clob3 = -1; - /* - * Indicate if the unalign access - * instruction's registers hit with - * others in the same bundle. - */ - bool alias = false; - bool load_n_store = true; - bool load_store_signed = false; - unsigned int load_store_size = 8; - bool y1_br = false; /* True, for a branch in same bundle at Y1.*/ - int y1_br_reg = 0; - /* True for link operation. i.e. jalr or lnk at Y1 */ - bool y1_lr = false; - int y1_lr_reg = 0; - bool x1_add = false;/* True, for load/store ADD instruction at X1*/ - int x1_add_imm8 = 0; - bool unexpected = false; - int n = 0, k; - - jit_code_area = - (struct unaligned_jit_fragment *)(info->unalign_jit_base); - - memset((void *)&frag, 0, sizeof(frag)); - - /* 0: X mode, Otherwise: Y mode. */ - if (bundle & TILEGX_BUNDLE_MODE_MASK) { - unsigned int mod, opcode; - - if (get_Opcode_Y1(bundle) == RRR_1_OPCODE_Y1 && - get_RRROpcodeExtension_Y1(bundle) == - UNARY_RRR_1_OPCODE_Y1) { - - opcode = get_UnaryOpcodeExtension_Y1(bundle); - - /* - * Test "jalr", "jalrp", "jr", "jrp" instruction at Y1 - * pipeline. - */ - switch (opcode) { - case JALR_UNARY_OPCODE_Y1: - case JALRP_UNARY_OPCODE_Y1: - y1_lr = true; - y1_lr_reg = 55; /* Link register. */ - /* FALLTHROUGH */ - case JR_UNARY_OPCODE_Y1: - case JRP_UNARY_OPCODE_Y1: - y1_br = true; - y1_br_reg = get_SrcA_Y1(bundle); - break; - case LNK_UNARY_OPCODE_Y1: - /* "lnk" at Y1 pipeline. */ - y1_lr = true; - y1_lr_reg = get_Dest_Y1(bundle); - break; - } - } - - opcode = get_Opcode_Y2(bundle); - mod = get_Mode(bundle); - - /* - * bundle_2 is bundle after making Y2 as a dummy operation - * - ld zero, sp - */ - bundle_2 = (bundle & (~GX_INSN_Y2_MASK)) | jit_y2_dummy(); - - /* Make Y1 as fnop if Y1 is a branch or lnk operation. */ - if (y1_br || y1_lr) { - bundle_2 &= ~(GX_INSN_Y1_MASK); - bundle_2 |= jit_y1_fnop(); - } - - if (is_y0_y1_nop(bundle_2)) - bundle_2_enable = false; - - if (mod == MODE_OPCODE_YC2) { - /* Store. */ - load_n_store = false; - load_store_size = 1 << opcode; - load_store_signed = false; - find_regs(bundle, 0, &ra, &rb, &clob1, &clob2, - &clob3, &alias); - if (load_store_size > 8) - unexpected = true; - } else { - /* Load. */ - load_n_store = true; - if (mod == MODE_OPCODE_YB2) { - switch (opcode) { - case LD_OPCODE_Y2: - load_store_signed = false; - load_store_size = 8; - break; - case LD4S_OPCODE_Y2: - load_store_signed = true; - load_store_size = 4; - break; - case LD4U_OPCODE_Y2: - load_store_signed = false; - load_store_size = 4; - break; - default: - unexpected = true; - } - } else if (mod == MODE_OPCODE_YA2) { - if (opcode == LD2S_OPCODE_Y2) { - load_store_signed = true; - load_store_size = 2; - } else if (opcode == LD2U_OPCODE_Y2) { - load_store_signed = false; - load_store_size = 2; - } else - unexpected = true; - } else - unexpected = true; - find_regs(bundle, &rd, &ra, &rb, &clob1, &clob2, - &clob3, &alias); - } - } else { - unsigned int opcode; - - /* bundle_2 is bundle after making X1 as "fnop". */ - bundle_2 = (bundle & (~GX_INSN_X1_MASK)) | jit_x1_fnop(); - - if (is_x0_x1_nop(bundle_2)) - bundle_2_enable = false; - - if (get_Opcode_X1(bundle) == RRR_0_OPCODE_X1) { - opcode = get_UnaryOpcodeExtension_X1(bundle); - - if (get_RRROpcodeExtension_X1(bundle) == - UNARY_RRR_0_OPCODE_X1) { - load_n_store = true; - find_regs(bundle, &rd, &ra, &rb, &clob1, - &clob2, &clob3, &alias); - - switch (opcode) { - case LD_UNARY_OPCODE_X1: - load_store_signed = false; - load_store_size = 8; - break; - case LD4S_UNARY_OPCODE_X1: - load_store_signed = true; - /* FALLTHROUGH */ - case LD4U_UNARY_OPCODE_X1: - load_store_size = 4; - break; - - case LD2S_UNARY_OPCODE_X1: - load_store_signed = true; - /* FALLTHROUGH */ - case LD2U_UNARY_OPCODE_X1: - load_store_size = 2; - break; - default: - unexpected = true; - } - } else { - load_n_store = false; - load_store_signed = false; - find_regs(bundle, 0, &ra, &rb, - &clob1, &clob2, &clob3, - &alias); - - opcode = get_RRROpcodeExtension_X1(bundle); - switch (opcode) { - case ST_RRR_0_OPCODE_X1: - load_store_size = 8; - break; - case ST4_RRR_0_OPCODE_X1: - load_store_size = 4; - break; - case ST2_RRR_0_OPCODE_X1: - load_store_size = 2; - break; - default: - unexpected = true; - } - } - } else if (get_Opcode_X1(bundle) == IMM8_OPCODE_X1) { - load_n_store = true; - opcode = get_Imm8OpcodeExtension_X1(bundle); - switch (opcode) { - case LD_ADD_IMM8_OPCODE_X1: - load_store_size = 8; - break; - - case LD4S_ADD_IMM8_OPCODE_X1: - load_store_signed = true; - /* FALLTHROUGH */ - case LD4U_ADD_IMM8_OPCODE_X1: - load_store_size = 4; - break; - - case LD2S_ADD_IMM8_OPCODE_X1: - load_store_signed = true; - /* FALLTHROUGH */ - case LD2U_ADD_IMM8_OPCODE_X1: - load_store_size = 2; - break; - - case ST_ADD_IMM8_OPCODE_X1: - load_n_store = false; - load_store_size = 8; - break; - case ST4_ADD_IMM8_OPCODE_X1: - load_n_store = false; - load_store_size = 4; - break; - case ST2_ADD_IMM8_OPCODE_X1: - load_n_store = false; - load_store_size = 2; - break; - default: - unexpected = true; - } - - if (!unexpected) { - x1_add = true; - if (load_n_store) - x1_add_imm8 = get_Imm8_X1(bundle); - else - x1_add_imm8 = get_Dest_Imm8_X1(bundle); - } - - find_regs(bundle, load_n_store ? (&rd) : NULL, - &ra, &rb, &clob1, &clob2, &clob3, &alias); - } else - unexpected = true; - } - - /* - * Some sanity check for register numbers extracted from fault bundle. - */ - if (check_regs(rd, ra, rb, clob1, clob2, clob3) == true) - unexpected = true; - - /* Give warning if register ra has an aligned address. */ - if (!unexpected) - WARN_ON(!((load_store_size - 1) & (regs->regs[ra]))); - - - /* - * Fault came from kernel space, here we only need take care of - * unaligned "get_user/put_user" macros defined in "uaccess.h". - * Basically, we will handle bundle like this: - * {ld/2u/4s rd, ra; movei rx, 0} or {st/2/4 ra, rb; movei rx, 0} - * (Refer to file "arch/tile/include/asm/uaccess.h" for details). - * For either load or store, byte-wise operation is performed by calling - * get_user() or put_user(). If the macro returns non-zero value, - * set the value to rx, otherwise set zero to rx. Finally make pc point - * to next bundle and return. - */ - - if (EX1_PL(regs->ex1) != USER_PL) { - - unsigned long rx = 0; - unsigned long x = 0, ret = 0; - - if (y1_br || y1_lr || x1_add || - (load_store_signed != - (load_n_store && load_store_size == 4))) { - /* No branch, link, wrong sign-ext or load/store add. */ - unexpected = true; - } else if (!unexpected) { - if (bundle & TILEGX_BUNDLE_MODE_MASK) { - /* - * Fault bundle is Y mode. - * Check if the Y1 and Y0 is the form of - * { movei rx, 0; nop/fnop }, if yes, - * find the rx. - */ - - if ((get_Opcode_Y1(bundle) == ADDI_OPCODE_Y1) - && (get_SrcA_Y1(bundle) == TREG_ZERO) && - (get_Imm8_Y1(bundle) == 0) && - is_bundle_y0_nop(bundle)) { - rx = get_Dest_Y1(bundle); - } else if ((get_Opcode_Y0(bundle) == - ADDI_OPCODE_Y0) && - (get_SrcA_Y0(bundle) == TREG_ZERO) && - (get_Imm8_Y0(bundle) == 0) && - is_bundle_y1_nop(bundle)) { - rx = get_Dest_Y0(bundle); - } else { - unexpected = true; - } - } else { - /* - * Fault bundle is X mode. - * Check if the X0 is 'movei rx, 0', - * if yes, find the rx. - */ - - if ((get_Opcode_X0(bundle) == IMM8_OPCODE_X0) - && (get_Imm8OpcodeExtension_X0(bundle) == - ADDI_IMM8_OPCODE_X0) && - (get_SrcA_X0(bundle) == TREG_ZERO) && - (get_Imm8_X0(bundle) == 0)) { - rx = get_Dest_X0(bundle); - } else { - unexpected = true; - } - } - - /* rx should be less than 56. */ - if (!unexpected && (rx >= 56)) - unexpected = true; - } - - if (!search_exception_tables(regs->pc)) { - /* No fixup in the exception tables for the pc. */ - unexpected = true; - } - - if (unexpected) { - /* Unexpected unalign kernel fault. */ - struct task_struct *tsk = validate_current(); - - bust_spinlocks(1); - - show_regs(regs); - - if (unlikely(tsk->pid < 2)) { - panic("Kernel unalign fault running %s!", - tsk->pid ? "init" : "the idle task"); - } -#ifdef SUPPORT_DIE - die("Oops", regs); -#endif - bust_spinlocks(1); - - do_group_exit(SIGKILL); - - } else { - unsigned long i, b = 0; - unsigned char *ptr = - (unsigned char *)regs->regs[ra]; - if (load_n_store) { - /* handle get_user(x, ptr) */ - for (i = 0; i < load_store_size; i++) { - ret = get_user(b, ptr++); - if (!ret) { - /* Success! update x. */ -#ifdef __LITTLE_ENDIAN - x |= (b << (8 * i)); -#else - x <<= 8; - x |= b; -#endif /* __LITTLE_ENDIAN */ - } else { - x = 0; - break; - } - } - - /* Sign-extend 4-byte loads. */ - if (load_store_size == 4) - x = (long)(int)x; - - /* Set register rd. */ - regs->regs[rd] = x; - - /* Set register rx. */ - regs->regs[rx] = ret; - - /* Bump pc. */ - regs->pc += 8; - - } else { - /* Handle put_user(x, ptr) */ - x = regs->regs[rb]; -#ifdef __LITTLE_ENDIAN - b = x; -#else - /* - * Swap x in order to store x from low - * to high memory same as the - * little-endian case. - */ - switch (load_store_size) { - case 8: - b = swab64(x); - break; - case 4: - b = swab32(x); - break; - case 2: - b = swab16(x); - break; - } -#endif /* __LITTLE_ENDIAN */ - for (i = 0; i < load_store_size; i++) { - ret = put_user(b, ptr++); - if (ret) - break; - /* Success! shift 1 byte. */ - b >>= 8; - } - /* Set register rx. */ - regs->regs[rx] = ret; - - /* Bump pc. */ - regs->pc += 8; - } - } - - unaligned_fixup_count++; - - if (unaligned_printk) { - pr_info("%s/%d - Unalign fixup for kernel access to userspace %lx\n", - current->comm, current->pid, regs->regs[ra]); - } - - /* Done! Return to the exception handler. */ - return; - } - - if ((align_ctl == 0) || unexpected) { - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGBUS; - info.si_code = BUS_ADRALN; - info.si_addr = (unsigned char __user *)0; - - if (unaligned_printk) - pr_info("Unalign bundle: unexp @%llx, %llx\n", - (unsigned long long)regs->pc, - (unsigned long long)bundle); - - if (ra < 56) { - unsigned long uaa = (unsigned long)regs->regs[ra]; - /* Set bus Address. */ - info.si_addr = (unsigned char __user *)uaa; - } - - unaligned_fixup_count++; - - trace_unhandled_signal("unaligned fixup trap", regs, - (unsigned long)info.si_addr, SIGBUS); - force_sig_info(info.si_signo, &info, current); - return; - } - -#ifdef __LITTLE_ENDIAN -#define UA_FIXUP_ADDR_DELTA 1 -#define UA_FIXUP_BFEXT_START(_B_) 0 -#define UA_FIXUP_BFEXT_END(_B_) (8 * (_B_) - 1) -#else /* __BIG_ENDIAN */ -#define UA_FIXUP_ADDR_DELTA -1 -#define UA_FIXUP_BFEXT_START(_B_) (64 - 8 * (_B_)) -#define UA_FIXUP_BFEXT_END(_B_) 63 -#endif /* __LITTLE_ENDIAN */ - - - - if ((ra != rb) && (rd != TREG_SP) && !alias && - !y1_br && !y1_lr && !x1_add) { - /* - * Simple case: ra != rb and no register alias found, - * and no branch or link. This will be the majority. - * We can do a little better for simplae case than the - * generic scheme below. - */ - if (!load_n_store) { - /* - * Simple store: ra != rb, no need for scratch register. - * Just store and rotate to right bytewise. - */ -#ifdef __BIG_ENDIAN - frag.insn[n++] = - jit_x0_addi(ra, ra, load_store_size - 1) | - jit_x1_fnop(); -#endif /* __BIG_ENDIAN */ - for (k = 0; k < load_store_size; k++) { - /* Store a byte. */ - frag.insn[n++] = - jit_x0_rotli(rb, rb, 56) | - jit_x1_st1_add(ra, rb, - UA_FIXUP_ADDR_DELTA); - } -#ifdef __BIG_ENDIAN - frag.insn[n] = jit_x1_addi(ra, ra, 1); -#else - frag.insn[n] = jit_x1_addi(ra, ra, - -1 * load_store_size); -#endif /* __LITTLE_ENDIAN */ - - if (load_store_size == 8) { - frag.insn[n] |= jit_x0_fnop(); - } else if (load_store_size == 4) { - frag.insn[n] |= jit_x0_rotli(rb, rb, 32); - } else { /* = 2 */ - frag.insn[n] |= jit_x0_rotli(rb, rb, 16); - } - n++; - if (bundle_2_enable) - frag.insn[n++] = bundle_2; - frag.insn[n++] = jit_x0_fnop() | jit_x1_iret(); - } else { - if (rd == ra) { - /* Use two clobber registers: clob1/2. */ - frag.insn[n++] = - jit_x0_addi(TREG_SP, TREG_SP, -16) | - jit_x1_fnop(); - frag.insn[n++] = - jit_x0_addi(clob1, ra, 7) | - jit_x1_st_add(TREG_SP, clob1, -8); - frag.insn[n++] = - jit_x0_addi(clob2, ra, 0) | - jit_x1_st(TREG_SP, clob2); - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_ldna(rd, ra); - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_ldna(clob1, clob1); - /* - * Note: we must make sure that rd must not - * be sp. Recover clob1/2 from stack. - */ - frag.insn[n++] = - jit_x0_dblalign(rd, clob1, clob2) | - jit_x1_ld_add(clob2, TREG_SP, 8); - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_ld_add(clob1, TREG_SP, 16); - } else { - /* Use one clobber register: clob1 only. */ - frag.insn[n++] = - jit_x0_addi(TREG_SP, TREG_SP, -16) | - jit_x1_fnop(); - frag.insn[n++] = - jit_x0_addi(clob1, ra, 7) | - jit_x1_st(TREG_SP, clob1); - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_ldna(rd, ra); - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_ldna(clob1, clob1); - /* - * Note: we must make sure that rd must not - * be sp. Recover clob1 from stack. - */ - frag.insn[n++] = - jit_x0_dblalign(rd, clob1, ra) | - jit_x1_ld_add(clob1, TREG_SP, 16); - } - - if (bundle_2_enable) - frag.insn[n++] = bundle_2; - /* - * For non 8-byte load, extract corresponding bytes and - * signed extension. - */ - if (load_store_size == 4) { - if (load_store_signed) - frag.insn[n++] = - jit_x0_bfexts( - rd, rd, - UA_FIXUP_BFEXT_START(4), - UA_FIXUP_BFEXT_END(4)) | - jit_x1_fnop(); - else - frag.insn[n++] = - jit_x0_bfextu( - rd, rd, - UA_FIXUP_BFEXT_START(4), - UA_FIXUP_BFEXT_END(4)) | - jit_x1_fnop(); - } else if (load_store_size == 2) { - if (load_store_signed) - frag.insn[n++] = - jit_x0_bfexts( - rd, rd, - UA_FIXUP_BFEXT_START(2), - UA_FIXUP_BFEXT_END(2)) | - jit_x1_fnop(); - else - frag.insn[n++] = - jit_x0_bfextu( - rd, rd, - UA_FIXUP_BFEXT_START(2), - UA_FIXUP_BFEXT_END(2)) | - jit_x1_fnop(); - } - - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_iret(); - } - } else if (!load_n_store) { - - /* - * Generic memory store cases: use 3 clobber registers. - * - * Alloc space for saveing clob2,1,3 on user's stack. - * register clob3 points to where clob2 saved, followed by - * clob1 and 3 from high to low memory. - */ - frag.insn[n++] = - jit_x0_addi(TREG_SP, TREG_SP, -32) | - jit_x1_fnop(); - frag.insn[n++] = - jit_x0_addi(clob3, TREG_SP, 16) | - jit_x1_st_add(TREG_SP, clob3, 8); -#ifdef __LITTLE_ENDIAN - frag.insn[n++] = - jit_x0_addi(clob1, ra, 0) | - jit_x1_st_add(TREG_SP, clob1, 8); -#else - frag.insn[n++] = - jit_x0_addi(clob1, ra, load_store_size - 1) | - jit_x1_st_add(TREG_SP, clob1, 8); -#endif - if (load_store_size == 8) { - /* - * We save one byte a time, not for fast, but compact - * code. After each store, data source register shift - * right one byte. unchanged after 8 stores. - */ - frag.insn[n++] = - jit_x0_addi(clob2, TREG_ZERO, 7) | - jit_x1_st_add(TREG_SP, clob2, 16); - frag.insn[n++] = - jit_x0_rotli(rb, rb, 56) | - jit_x1_st1_add(clob1, rb, UA_FIXUP_ADDR_DELTA); - frag.insn[n++] = - jit_x0_addi(clob2, clob2, -1) | - jit_x1_bnezt(clob2, -1); - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_addi(clob2, y1_br_reg, 0); - } else if (load_store_size == 4) { - frag.insn[n++] = - jit_x0_addi(clob2, TREG_ZERO, 3) | - jit_x1_st_add(TREG_SP, clob2, 16); - frag.insn[n++] = - jit_x0_rotli(rb, rb, 56) | - jit_x1_st1_add(clob1, rb, UA_FIXUP_ADDR_DELTA); - frag.insn[n++] = - jit_x0_addi(clob2, clob2, -1) | - jit_x1_bnezt(clob2, -1); - /* - * same as 8-byte case, but need shift another 4 - * byte to recover rb for 4-byte store. - */ - frag.insn[n++] = jit_x0_rotli(rb, rb, 32) | - jit_x1_addi(clob2, y1_br_reg, 0); - } else { /* =2 */ - frag.insn[n++] = - jit_x0_addi(clob2, rb, 0) | - jit_x1_st_add(TREG_SP, clob2, 16); - for (k = 0; k < 2; k++) { - frag.insn[n++] = - jit_x0_shrui(rb, rb, 8) | - jit_x1_st1_add(clob1, rb, - UA_FIXUP_ADDR_DELTA); - } - frag.insn[n++] = - jit_x0_addi(rb, clob2, 0) | - jit_x1_addi(clob2, y1_br_reg, 0); - } - - if (bundle_2_enable) - frag.insn[n++] = bundle_2; - - if (y1_lr) { - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_mfspr(y1_lr_reg, - SPR_EX_CONTEXT_0_0); - } - if (y1_br) { - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_mtspr(SPR_EX_CONTEXT_0_0, - clob2); - } - if (x1_add) { - frag.insn[n++] = - jit_x0_addi(ra, ra, x1_add_imm8) | - jit_x1_ld_add(clob2, clob3, -8); - } else { - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_ld_add(clob2, clob3, -8); - } - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_ld_add(clob1, clob3, -8); - frag.insn[n++] = jit_x0_fnop() | jit_x1_ld(clob3, clob3); - frag.insn[n++] = jit_x0_fnop() | jit_x1_iret(); - - } else { - /* - * Generic memory load cases. - * - * Alloc space for saveing clob1,2,3 on user's stack. - * register clob3 points to where clob1 saved, followed - * by clob2 and 3 from high to low memory. - */ - - frag.insn[n++] = - jit_x0_addi(TREG_SP, TREG_SP, -32) | - jit_x1_fnop(); - frag.insn[n++] = - jit_x0_addi(clob3, TREG_SP, 16) | - jit_x1_st_add(TREG_SP, clob3, 8); - frag.insn[n++] = - jit_x0_addi(clob2, ra, 0) | - jit_x1_st_add(TREG_SP, clob2, 8); - - if (y1_br) { - frag.insn[n++] = - jit_x0_addi(clob1, y1_br_reg, 0) | - jit_x1_st_add(TREG_SP, clob1, 16); - } else { - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_st_add(TREG_SP, clob1, 16); - } - - if (bundle_2_enable) - frag.insn[n++] = bundle_2; - - if (y1_lr) { - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_mfspr(y1_lr_reg, - SPR_EX_CONTEXT_0_0); - } - - if (y1_br) { - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_mtspr(SPR_EX_CONTEXT_0_0, - clob1); - } - - frag.insn[n++] = - jit_x0_addi(clob1, clob2, 7) | - jit_x1_ldna(rd, clob2); - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_ldna(clob1, clob1); - frag.insn[n++] = - jit_x0_dblalign(rd, clob1, clob2) | - jit_x1_ld_add(clob1, clob3, -8); - if (x1_add) { - frag.insn[n++] = - jit_x0_addi(ra, ra, x1_add_imm8) | - jit_x1_ld_add(clob2, clob3, -8); - } else { - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_ld_add(clob2, clob3, -8); - } - - frag.insn[n++] = - jit_x0_fnop() | - jit_x1_ld(clob3, clob3); - - if (load_store_size == 4) { - if (load_store_signed) - frag.insn[n++] = - jit_x0_bfexts( - rd, rd, - UA_FIXUP_BFEXT_START(4), - UA_FIXUP_BFEXT_END(4)) | - jit_x1_fnop(); - else - frag.insn[n++] = - jit_x0_bfextu( - rd, rd, - UA_FIXUP_BFEXT_START(4), - UA_FIXUP_BFEXT_END(4)) | - jit_x1_fnop(); - } else if (load_store_size == 2) { - if (load_store_signed) - frag.insn[n++] = - jit_x0_bfexts( - rd, rd, - UA_FIXUP_BFEXT_START(2), - UA_FIXUP_BFEXT_END(2)) | - jit_x1_fnop(); - else - frag.insn[n++] = - jit_x0_bfextu( - rd, rd, - UA_FIXUP_BFEXT_START(2), - UA_FIXUP_BFEXT_END(2)) | - jit_x1_fnop(); - } - - frag.insn[n++] = jit_x0_fnop() | jit_x1_iret(); - } - - /* Max JIT bundle count is 14. */ - WARN_ON(n > 14); - - if (!unexpected) { - int status = 0; - int idx = (regs->pc >> 3) & - ((1ULL << (PAGE_SHIFT - UNALIGN_JIT_SHIFT)) - 1); - - frag.pc = regs->pc; - frag.bundle = bundle; - - if (unaligned_printk) { - pr_info("%s/%d, Unalign fixup: pc=%lx bundle=%lx %d %d %d %d %d %d %d %d\n", - current->comm, current->pid, - (unsigned long)frag.pc, - (unsigned long)frag.bundle, - (int)alias, (int)rd, (int)ra, - (int)rb, (int)bundle_2_enable, - (int)y1_lr, (int)y1_br, (int)x1_add); - - for (k = 0; k < n; k += 2) - pr_info("[%d] %016llx %016llx\n", - k, (unsigned long long)frag.insn[k], - (unsigned long long)frag.insn[k+1]); - } - - /* Swap bundle byte order for big endian sys. */ -#ifdef __BIG_ENDIAN - frag.bundle = GX_INSN_BSWAP(frag.bundle); - for (k = 0; k < n; k++) - frag.insn[k] = GX_INSN_BSWAP(frag.insn[k]); -#endif /* __BIG_ENDIAN */ - - status = copy_to_user((void __user *)&jit_code_area[idx], - &frag, sizeof(frag)); - if (status) { - /* Fail to copy JIT into user land. send SIGSEGV. */ - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGSEGV; - info.si_code = SEGV_MAPERR; - info.si_addr = (void __user *)&jit_code_area[idx]; - - pr_warn("Unalign fixup: pid=%d %s jit_code_area=%llx\n", - current->pid, current->comm, - (unsigned long long)&jit_code_area[idx]); - - trace_unhandled_signal("segfault in unalign fixup", - regs, - (unsigned long)info.si_addr, - SIGSEGV); - force_sig_info(info.si_signo, &info, current); - return; - } - - - /* Do a cheaper increment, not accurate. */ - unaligned_fixup_count++; - __flush_icache_range((unsigned long)&jit_code_area[idx], - (unsigned long)&jit_code_area[idx] + - sizeof(frag)); - - /* Setup SPR_EX_CONTEXT_0_0/1 for returning to user program.*/ - __insn_mtspr(SPR_EX_CONTEXT_0_0, regs->pc + 8); - __insn_mtspr(SPR_EX_CONTEXT_0_1, PL_ICS_EX1(USER_PL, 0)); - - /* Modify pc at the start of new JIT. */ - regs->pc = (unsigned long)&jit_code_area[idx].insn[0]; - /* Set ICS in SPR_EX_CONTEXT_K_1. */ - regs->ex1 = PL_ICS_EX1(USER_PL, 1); - } -} - - -/* - * C function to generate unalign data JIT. Called from unalign data - * interrupt handler. - * - * First check if unalign fix is disabled or exception did not not come from - * user space or sp register points to unalign address, if true, generate a - * SIGBUS. Then map a page into user space as JIT area if it is not mapped - * yet. Genenerate JIT code by calling jit_bundle_gen(). After that return - * back to exception handler. - * - * The exception handler will "iret" to new generated JIT code after - * restoring caller saved registers. In theory, the JIT code will perform - * another "iret" to resume user's program. - */ - -void do_unaligned(struct pt_regs *regs, int vecnum) -{ - tilegx_bundle_bits __user *pc; - tilegx_bundle_bits bundle; - struct thread_info *info = current_thread_info(); - int align_ctl; - - /* Checks the per-process unaligned JIT flags */ - align_ctl = unaligned_fixup; - switch (task_thread_info(current)->align_ctl) { - case PR_UNALIGN_NOPRINT: - align_ctl = 1; - break; - case PR_UNALIGN_SIGBUS: - align_ctl = 0; - break; - } - - /* Enable iterrupt in order to access user land. */ - local_irq_enable(); - - /* - * The fault came from kernel space. Two choices: - * (a) unaligned_fixup < 1, we will first call get/put_user fixup - * to return -EFAULT. If no fixup, simply panic the kernel. - * (b) unaligned_fixup >=1, we will try to fix the unaligned access - * if it was triggered by get_user/put_user() macros. Panic the - * kernel if it is not fixable. - */ - - if (EX1_PL(regs->ex1) != USER_PL) { - - if (align_ctl < 1) { - unaligned_fixup_count++; - /* If exception came from kernel, try fix it up. */ - if (fixup_exception(regs)) { - if (unaligned_printk) - pr_info("Unalign fixup: %d %llx @%llx\n", - (int)unaligned_fixup, - (unsigned long long)regs->ex1, - (unsigned long long)regs->pc); - } else { - /* Not fixable. Go panic. */ - panic("Unalign exception in Kernel. pc=%lx", - regs->pc); - } - } else { - /* - * Try to fix the exception. If we can't, panic the - * kernel. - */ - bundle = GX_INSN_BSWAP( - *((tilegx_bundle_bits *)(regs->pc))); - jit_bundle_gen(regs, bundle, align_ctl); - } - return; - } - - /* - * Fault came from user with ICS or stack is not aligned. - * If so, we will trigger SIGBUS. - */ - if ((regs->sp & 0x7) || (regs->ex1) || (align_ctl < 0)) { - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGBUS; - info.si_code = BUS_ADRALN; - info.si_addr = (unsigned char __user *)0; - - if (unaligned_printk) - pr_info("Unalign fixup: %d %llx @%llx\n", - (int)unaligned_fixup, - (unsigned long long)regs->ex1, - (unsigned long long)regs->pc); - - unaligned_fixup_count++; - - trace_unhandled_signal("unaligned fixup trap", regs, 0, SIGBUS); - force_sig_info(info.si_signo, &info, current); - return; - } - - - /* Read the bundle caused the exception! */ - pc = (tilegx_bundle_bits __user *)(regs->pc); - if (get_user(bundle, pc) != 0) { - /* Probably never be here since pc is valid user address.*/ - siginfo_t info; - - clear_siginfo(&info); - info.si_signo = SIGSEGV; - info.si_code = SEGV_MAPERR; - info.si_addr = (void __user *)pc; - - pr_err("Couldn't read instruction at %p trying to step\n", pc); - trace_unhandled_signal("segfault in unalign fixup", regs, - (unsigned long)info.si_addr, SIGSEGV); - force_sig_info(info.si_signo, &info, current); - return; - } - - if (!info->unalign_jit_base) { - void __user *user_page; - - /* - * Allocate a page in userland. - * For 64-bit processes we try to place the mapping far - * from anything else that might be going on (specifically - * 64 GB below the top of the user address space). If it - * happens not to be possible to put it there, it's OK; - * the kernel will choose another location and we'll - * remember it for later. - */ - if (is_compat_task()) - user_page = NULL; - else - user_page = (void __user *)(TASK_SIZE - (1UL << 36)) + - (current->pid << PAGE_SHIFT); - - user_page = (void __user *) vm_mmap(NULL, - (unsigned long)user_page, - PAGE_SIZE, - PROT_EXEC | PROT_READ | - PROT_WRITE, -#ifdef CONFIG_HOMECACHE - MAP_CACHE_HOME_TASK | -#endif - MAP_PRIVATE | - MAP_ANONYMOUS, - 0); - - if (IS_ERR((void __force *)user_page)) { - pr_err("Out of kernel pages trying do_mmap\n"); - return; - } - - /* Save the address in the thread_info struct */ - info->unalign_jit_base = user_page; - if (unaligned_printk) - pr_info("Unalign bundle: %d:%d, allocate page @%llx\n", - raw_smp_processor_id(), current->pid, - (unsigned long long)user_page); - } - - /* Generate unalign JIT */ - jit_bundle_gen(regs, GX_INSN_BSWAP(bundle), align_ctl); -} - -#endif /* __tilegx__ */ diff --git a/arch/tile/kernel/usb.c b/arch/tile/kernel/usb.c deleted file mode 100644 index 9f1e05e12255..000000000000 --- a/arch/tile/kernel/usb.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Register the Tile-Gx USB interfaces as platform devices. - * - * The actual USB driver is just some glue (in - * drivers/usb/host/[eo]hci-tilegx.c) which makes the registers available - * to the standard kernel EHCI and OHCI drivers. - */ - -#include -#include -#include -#include -#include -#include - -static u64 ehci_dmamask = DMA_BIT_MASK(32); - -#define USB_HOST_DEF(unit, type, dmamask) \ - static struct \ - tilegx_usb_platform_data tilegx_usb_platform_data_ ## type ## \ - hci ## unit = { \ - .dev_index = unit, \ - }; \ - \ - static struct platform_device tilegx_usb_ ## type ## hci ## unit = { \ - .name = "tilegx-" #type "hci", \ - .id = unit, \ - .dev = { \ - .dma_mask = dmamask, \ - .coherent_dma_mask = DMA_BIT_MASK(32), \ - .platform_data = \ - &tilegx_usb_platform_data_ ## type ## hci ## \ - unit, \ - }, \ - }; - -USB_HOST_DEF(0, e, &ehci_dmamask) -USB_HOST_DEF(0, o, NULL) -USB_HOST_DEF(1, e, &ehci_dmamask) -USB_HOST_DEF(1, o, NULL) - -#undef USB_HOST_DEF - -static struct platform_device *tilegx_usb_devices[] __initdata = { - &tilegx_usb_ehci0, - &tilegx_usb_ehci1, - &tilegx_usb_ohci0, - &tilegx_usb_ohci1, -}; - -/** Add our set of possible USB devices. */ -static int __init tilegx_usb_init(void) -{ - platform_add_devices(tilegx_usb_devices, - ARRAY_SIZE(tilegx_usb_devices)); - - return 0; -} -arch_initcall(tilegx_usb_init); diff --git a/arch/tile/kernel/vdso.c b/arch/tile/kernel/vdso.c deleted file mode 100644 index 5bc51d7dfdcb..000000000000 --- a/arch/tile/kernel/vdso.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -/* The alignment of the vDSO. */ -#define VDSO_ALIGNMENT PAGE_SIZE - - -static unsigned int vdso_pages; -static struct page **vdso_pagelist; - -#ifdef CONFIG_COMPAT -static unsigned int vdso32_pages; -static struct page **vdso32_pagelist; -#endif -static int vdso_ready; - -/* - * The vdso data page. - */ -static union { - struct vdso_data data; - u8 page[PAGE_SIZE]; -} vdso_data_store __page_aligned_data; - -struct vdso_data *vdso_data = &vdso_data_store.data; - -static unsigned int __read_mostly vdso_enabled = 1; - -static struct page **vdso_setup(void *vdso_kbase, unsigned int pages) -{ - int i; - struct page **pagelist; - - pagelist = kzalloc(sizeof(struct page *) * (pages + 1), GFP_KERNEL); - BUG_ON(pagelist == NULL); - for (i = 0; i < pages - 1; i++) { - struct page *pg = virt_to_page(vdso_kbase + i*PAGE_SIZE); - ClearPageReserved(pg); - pagelist[i] = pg; - } - pagelist[pages - 1] = virt_to_page(vdso_data); - pagelist[pages] = NULL; - - return pagelist; -} - -static int __init vdso_init(void) -{ - int data_pages = sizeof(vdso_data_store) >> PAGE_SHIFT; - - /* - * We can disable vDSO support generally, but we need to retain - * one page to support the two-bundle (16-byte) rt_sigreturn path. - */ - if (!vdso_enabled) { - size_t offset = (unsigned long)&__vdso_rt_sigreturn; - static struct page *sigret_page; - sigret_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - BUG_ON(sigret_page == NULL); - vdso_pagelist = &sigret_page; - vdso_pages = 1; - BUG_ON(offset >= PAGE_SIZE); - memcpy(page_address(sigret_page) + offset, - vdso_start + offset, 16); -#ifdef CONFIG_COMPAT - vdso32_pages = vdso_pages; - vdso32_pagelist = vdso_pagelist; -#endif - vdso_ready = 1; - return 0; - } - - vdso_pages = (vdso_end - vdso_start) >> PAGE_SHIFT; - vdso_pages += data_pages; - vdso_pagelist = vdso_setup(vdso_start, vdso_pages); - -#ifdef CONFIG_COMPAT - vdso32_pages = (vdso32_end - vdso32_start) >> PAGE_SHIFT; - vdso32_pages += data_pages; - vdso32_pagelist = vdso_setup(vdso32_start, vdso32_pages); -#endif - - smp_wmb(); - vdso_ready = 1; - - return 0; -} -arch_initcall(vdso_init); - -const char *arch_vma_name(struct vm_area_struct *vma) -{ - if (vma->vm_mm && vma->vm_start == VDSO_BASE) - return "[vdso]"; -#ifndef __tilegx__ - if (vma->vm_start == MEM_USER_INTRPT) - return "[intrpt]"; -#endif - return NULL; -} - -int setup_vdso_pages(void) -{ - struct page **pagelist; - unsigned long pages; - struct mm_struct *mm = current->mm; - unsigned long vdso_base = 0; - int retval = 0; - - if (!vdso_ready) - return 0; - - mm->context.vdso_base = 0; - - pagelist = vdso_pagelist; - pages = vdso_pages; -#ifdef CONFIG_COMPAT - if (is_compat_task()) { - pagelist = vdso32_pagelist; - pages = vdso32_pages; - } -#endif - - /* - * vDSO has a problem and was disabled, just don't "enable" it for the - * process. - */ - if (pages == 0) - return 0; - - vdso_base = get_unmapped_area(NULL, vdso_base, - (pages << PAGE_SHIFT) + - ((VDSO_ALIGNMENT - 1) & PAGE_MASK), - 0, 0); - if (IS_ERR_VALUE(vdso_base)) { - retval = vdso_base; - return retval; - } - - /* Add required alignment. */ - vdso_base = ALIGN(vdso_base, VDSO_ALIGNMENT); - - /* - * Put vDSO base into mm struct. We need to do this before calling - * install_special_mapping or the perf counter mmap tracking code - * will fail to recognise it as a vDSO (since arch_vma_name fails). - */ - mm->context.vdso_base = vdso_base; - - /* - * our vma flags don't have VM_WRITE so by default, the process isn't - * allowed to write those pages. - * gdb can break that with ptrace interface, and thus trigger COW on - * those pages but it's then your responsibility to never do that on - * the "data" page of the vDSO or you'll stop getting kernel updates - * and your nice userland gettimeofday will be totally dead. - * It's fine to use that for setting breakpoints in the vDSO code - * pages though - */ - retval = install_special_mapping(mm, vdso_base, - pages << PAGE_SHIFT, - VM_READ|VM_EXEC | - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, - pagelist); - if (retval) - mm->context.vdso_base = 0; - - return retval; -} - -static __init int vdso_func(char *s) -{ - return kstrtouint(s, 0, &vdso_enabled); -} -__setup("vdso=", vdso_func); diff --git a/arch/tile/kernel/vdso/Makefile b/arch/tile/kernel/vdso/Makefile deleted file mode 100644 index b596a7396382..000000000000 --- a/arch/tile/kernel/vdso/Makefile +++ /dev/null @@ -1,117 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# Symbols present in the vdso -vdso-syms = rt_sigreturn gettimeofday - -# Files to link into the vdso -obj-vdso = $(patsubst %, v%.o, $(vdso-syms)) - -# Build rules -targets := $(obj-vdso) vdso.so vdso.so.dbg vdso.lds vdso-dummy.o -obj-vdso := $(addprefix $(obj)/, $(obj-vdso)) - -# vdso32 is only for tilegx -m32 compat task. -VDSO32-$(CONFIG_COMPAT) := y - -obj-y += vdso.o vdso-syms.o -obj-$(VDSO32-y) += vdso32.o -CPPFLAGS_vdso.lds += -P -C -U$(ARCH) - -# vDSO code runs in userspace and -pg doesn't help with profiling anyway. -CFLAGS_REMOVE_vdso.o = -pg -CFLAGS_REMOVE_vdso32.o = -pg -CFLAGS_REMOVE_vrt_sigreturn.o = -pg -CFLAGS_REMOVE_vrt_sigreturn32.o = -pg -CFLAGS_REMOVE_vgettimeofday.o = -pg -CFLAGS_REMOVE_vgettimeofday32.o = -pg - -ifdef CONFIG_FEEDBACK_COLLECT -# vDSO code runs in userspace, not collecting feedback data. -CFLAGS_REMOVE_vdso.o = -ffeedback-generate -CFLAGS_REMOVE_vdso32.o = -ffeedback-generate -CFLAGS_REMOVE_vrt_sigreturn.o = -ffeedback-generate -CFLAGS_REMOVE_vrt_sigreturn32.o = -ffeedback-generate -CFLAGS_REMOVE_vgettimeofday.o = -ffeedback-generate -CFLAGS_REMOVE_vgettimeofday32.o = -ffeedback-generate -endif - -# Disable gcov profiling for VDSO code -GCOV_PROFILE := n - -# Force dependency -$(obj)/vdso.o: $(obj)/vdso.so - -# link rule for the .so file, .lds has to be first -SYSCFLAGS_vdso.so.dbg = $(c_flags) -$(obj)/vdso.so.dbg: $(src)/vdso.lds $(obj-vdso) FORCE - $(call if_changed,vdsold) - -# We also create a special relocatable object that should mirror the symbol -# table and layout of the linked DSO. With ld -R we can then refer to -# these symbols in the kernel code rather than hand-coded addresses. - -SYSCFLAGS_vdso.so.dbg = -shared -s -Wl,-soname=linux-vdso.so.1 \ - $(call cc-ldoption, -Wl$(comma)--hash-style=both) -SYSCFLAGS_vdso_dummy.o = -r -$(obj)/vdso-dummy.o: $(src)/vdso.lds $(obj)/vrt_sigreturn.o FORCE - $(call if_changed,vdsold) - -LDFLAGS_vdso-syms.o := -r -R -$(obj)/vdso-syms.o: $(obj)/vdso-dummy.o FORCE - $(call if_changed,ld) - -# strip rule for the .so file -$(obj)/%.so: OBJCOPYFLAGS := -S -$(obj)/%.so: $(obj)/%.so.dbg FORCE - $(call if_changed,objcopy) - -# actual build commands -# The DSO images are built using a special linker script -# Add -lgcc so tilepro gets static muldi3 and lshrdi3 definitions. -# Make sure only to export the intended __vdso_xxx symbol offsets. -quiet_cmd_vdsold = VDSOLD $@ - cmd_vdsold = $(CC) $(KCFLAGS) -nostdlib $(SYSCFLAGS_$(@F)) \ - -Wl,-T,$(filter-out FORCE,$^) -o $@.tmp -lgcc && \ - $(CROSS_COMPILE)objcopy \ - $(patsubst %, -G __vdso_%, $(vdso-syms)) $@.tmp $@ - -# install commands for the unstripped file -quiet_cmd_vdso_install = INSTALL $@ - cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ - -vdso.so: $(obj)/vdso.so.dbg - @mkdir -p $(MODLIB)/vdso - $(call cmd,vdso_install) - -vdso32.so: $(obj)/vdso32.so.dbg - $(call cmd,vdso_install) - -vdso_install: vdso.so -vdso32_install: vdso32.so - - -KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS)) -KBUILD_AFLAGS_32 += -m32 -s -KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS)) -KBUILD_CFLAGS_32 += -m32 -fPIC -shared - -obj-vdso32 = $(patsubst %, v%32.o, $(vdso-syms)) - -targets += $(obj-vdso32) vdso32.so vdso32.so.dbg -obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32)) - -$(obj-vdso32:%=%): KBUILD_AFLAGS = $(KBUILD_AFLAGS_32) -$(obj-vdso32:%=%): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32) - -$(obj)/vgettimeofday32.o: $(obj)/vgettimeofday.c FORCE - $(call if_changed_rule,cc_o_c) - -$(obj)/vrt_sigreturn32.o: $(obj)/vrt_sigreturn.S FORCE - $(call if_changed,as_o_S) - -# Force dependency -$(obj)/vdso32.o: $(obj)/vdso32.so - -SYSCFLAGS_vdso32.so.dbg = -m32 -shared -s -Wl,-soname=linux-vdso32.so.1 \ - $(call cc-ldoption, -Wl$(comma)--hash-style=both) -$(obj)/vdso32.so.dbg: $(src)/vdso.lds $(obj-vdso32) FORCE - $(call if_changed,vdsold) diff --git a/arch/tile/kernel/vdso/vdso.S b/arch/tile/kernel/vdso/vdso.S deleted file mode 100644 index 3467adb41630..000000000000 --- a/arch/tile/kernel/vdso/vdso.S +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include - - __PAGE_ALIGNED_DATA - - .global vdso_start, vdso_end - .align PAGE_SIZE -vdso_start: - .incbin "arch/tile/kernel/vdso/vdso.so" - .align PAGE_SIZE -vdso_end: - - .previous diff --git a/arch/tile/kernel/vdso/vdso.lds.S b/arch/tile/kernel/vdso/vdso.lds.S deleted file mode 100644 index 731529f3f06f..000000000000 --- a/arch/tile/kernel/vdso/vdso.lds.S +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#define VDSO_VERSION_STRING LINUX_2.6 - - -OUTPUT_ARCH(tile) - -/* The ELF entry point can be used to set the AT_SYSINFO value. */ -ENTRY(__vdso_rt_sigreturn); - - -SECTIONS -{ - . = SIZEOF_HEADERS; - - .hash : { *(.hash) } :text - .gnu.hash : { *(.gnu.hash) } - .dynsym : { *(.dynsym) } - .dynstr : { *(.dynstr) } - .gnu.version : { *(.gnu.version) } - .gnu.version_d : { *(.gnu.version_d) } - .gnu.version_r : { *(.gnu.version_r) } - - .note : { *(.note.*) } :text :note - .dynamic : { *(.dynamic) } :text :dynamic - - .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr - .eh_frame : { KEEP (*(.eh_frame)) } :text - - .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } - - /* - * This linker script is used both with -r and with -shared. - * For the layouts to match, we need to skip more than enough - * space for the dynamic symbol table et al. If this amount - * is insufficient, ld -shared will barf. Just increase it here. - */ - . = 0x1000; - .text : { *(.text .text.*) } :text - - .data : { - *(.got.plt) *(.got) - *(.data .data.* .gnu.linkonce.d.*) - *(.dynbss) - *(.bss .bss.* .gnu.linkonce.b.*) - } -} - - -/* - * We must supply the ELF program headers explicitly to get just one - * PT_LOAD segment, and set the flags explicitly to make segments read-only. - */ -PHDRS -{ - text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */ - dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ - note PT_NOTE FLAGS(4); /* PF_R */ - eh_frame_hdr PT_GNU_EH_FRAME; -} - - -/* - * This controls what userland symbols we export from the vDSO. - */ -VERSION -{ - VDSO_VERSION_STRING { - global: - __vdso_rt_sigreturn; - __vdso_gettimeofday; - gettimeofday; - __vdso_clock_gettime; - clock_gettime; - local:*; - }; -} diff --git a/arch/tile/kernel/vdso/vdso32.S b/arch/tile/kernel/vdso/vdso32.S deleted file mode 100644 index 1d1ac3257e11..000000000000 --- a/arch/tile/kernel/vdso/vdso32.S +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include - - __PAGE_ALIGNED_DATA - - .global vdso32_start, vdso32_end - .align PAGE_SIZE -vdso32_start: - .incbin "arch/tile/kernel/vdso/vdso32.so" - .align PAGE_SIZE -vdso32_end: - - .previous diff --git a/arch/tile/kernel/vdso/vgettimeofday.c b/arch/tile/kernel/vdso/vgettimeofday.c deleted file mode 100644 index e63310c49742..000000000000 --- a/arch/tile/kernel/vdso/vgettimeofday.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#define VDSO_BUILD /* avoid some shift warnings for -m32 in */ -#include -#include -#include -#include - -#if CHIP_HAS_SPLIT_CYCLE() -static inline cycles_t get_cycles_inline(void) -{ - unsigned int high = __insn_mfspr(SPR_CYCLE_HIGH); - unsigned int low = __insn_mfspr(SPR_CYCLE_LOW); - unsigned int high2 = __insn_mfspr(SPR_CYCLE_HIGH); - - while (unlikely(high != high2)) { - low = __insn_mfspr(SPR_CYCLE_LOW); - high = high2; - high2 = __insn_mfspr(SPR_CYCLE_HIGH); - } - - return (((cycles_t)high) << 32) | low; -} -#define get_cycles get_cycles_inline -#endif - -struct syscall_return_value { - long value; - long error; -}; - -/* - * Find out the vDSO data page address in the process address space. - */ -inline unsigned long get_datapage(void) -{ - unsigned long ret; - - /* vdso data page located in the 2nd vDSO page. */ - asm volatile ("lnk %0" : "=r"(ret)); - ret &= ~(PAGE_SIZE - 1); - ret += PAGE_SIZE; - - return ret; -} - -static inline u64 vgetsns(struct vdso_data *vdso) -{ - return ((get_cycles() - vdso->cycle_last) & vdso->mask) * vdso->mult; -} - -static inline int do_realtime(struct vdso_data *vdso, struct timespec *ts) -{ - unsigned count; - u64 ns; - - do { - count = raw_read_seqcount_begin(&vdso->tb_seq); - ts->tv_sec = vdso->wall_time_sec; - ns = vdso->wall_time_snsec; - ns += vgetsns(vdso); - ns >>= vdso->shift; - } while (unlikely(read_seqcount_retry(&vdso->tb_seq, count))); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; -} - -static inline int do_monotonic(struct vdso_data *vdso, struct timespec *ts) -{ - unsigned count; - u64 ns; - - do { - count = raw_read_seqcount_begin(&vdso->tb_seq); - ts->tv_sec = vdso->monotonic_time_sec; - ns = vdso->monotonic_time_snsec; - ns += vgetsns(vdso); - ns >>= vdso->shift; - } while (unlikely(read_seqcount_retry(&vdso->tb_seq, count))); - - ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns); - ts->tv_nsec = ns; - - return 0; -} - -static inline int do_realtime_coarse(struct vdso_data *vdso, - struct timespec *ts) -{ - unsigned count; - - do { - count = raw_read_seqcount_begin(&vdso->tb_seq); - ts->tv_sec = vdso->wall_time_coarse_sec; - ts->tv_nsec = vdso->wall_time_coarse_nsec; - } while (unlikely(read_seqcount_retry(&vdso->tb_seq, count))); - - return 0; -} - -static inline int do_monotonic_coarse(struct vdso_data *vdso, - struct timespec *ts) -{ - unsigned count; - - do { - count = raw_read_seqcount_begin(&vdso->tb_seq); - ts->tv_sec = vdso->monotonic_time_coarse_sec; - ts->tv_nsec = vdso->monotonic_time_coarse_nsec; - } while (unlikely(read_seqcount_retry(&vdso->tb_seq, count))); - - return 0; -} - -struct syscall_return_value __vdso_gettimeofday(struct timeval *tv, - struct timezone *tz) -{ - struct syscall_return_value ret = { 0, 0 }; - unsigned count; - struct vdso_data *vdso = (struct vdso_data *)get_datapage(); - - /* The use of the timezone is obsolete, normally tz is NULL. */ - if (unlikely(tz != NULL)) { - do { - count = raw_read_seqcount_begin(&vdso->tz_seq); - tz->tz_minuteswest = vdso->tz_minuteswest; - tz->tz_dsttime = vdso->tz_dsttime; - } while (unlikely(read_seqcount_retry(&vdso->tz_seq, count))); - } - - if (unlikely(tv == NULL)) - return ret; - - do_realtime(vdso, (struct timespec *)tv); - tv->tv_usec /= 1000; - - return ret; -} - -int gettimeofday(struct timeval *tv, struct timezone *tz) - __attribute__((weak, alias("__vdso_gettimeofday"))); - -static struct syscall_return_value vdso_fallback_gettime(long clock, - struct timespec *ts) -{ - struct syscall_return_value ret; - __asm__ __volatile__ ( - "swint1" - : "=R00" (ret.value), "=R01" (ret.error) - : "R10" (__NR_clock_gettime), "R00" (clock), "R01" (ts) - : "r2", "r3", "r4", "r5", "r6", "r7", - "r8", "r9", "r11", "r12", "r13", "r14", "r15", - "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", - "r24", "r25", "r26", "r27", "r28", "r29", "memory"); - return ret; -} - -struct syscall_return_value __vdso_clock_gettime(clockid_t clock, - struct timespec *ts) -{ - struct vdso_data *vdso = (struct vdso_data *)get_datapage(); - struct syscall_return_value ret = { 0, 0 }; - - switch (clock) { - case CLOCK_REALTIME: - do_realtime(vdso, ts); - return ret; - case CLOCK_MONOTONIC: - do_monotonic(vdso, ts); - return ret; - case CLOCK_REALTIME_COARSE: - do_realtime_coarse(vdso, ts); - return ret; - case CLOCK_MONOTONIC_COARSE: - do_monotonic_coarse(vdso, ts); - return ret; - default: - return vdso_fallback_gettime(clock, ts); - } -} - -int clock_gettime(clockid_t clock, struct timespec *ts) - __attribute__((weak, alias("__vdso_clock_gettime"))); diff --git a/arch/tile/kernel/vdso/vrt_sigreturn.S b/arch/tile/kernel/vdso/vrt_sigreturn.S deleted file mode 100644 index 6326caf4a039..000000000000 --- a/arch/tile/kernel/vdso/vrt_sigreturn.S +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2012 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include - -/* - * Note that libc has a copy of this function that it uses to compare - * against the PC when a stack backtrace ends, so if this code is - * changed, the libc implementation(s) should also be updated. - */ -ENTRY(__vdso_rt_sigreturn) - moveli TREG_SYSCALL_NR_NAME, __NR_rt_sigreturn - swint1 - /* We don't use ENDPROC to avoid tagging this symbol as FUNC, - * which confuses the perf tool. - */ - END(__vdso_rt_sigreturn) diff --git a/arch/tile/kernel/vmlinux.lds.S b/arch/tile/kernel/vmlinux.lds.S deleted file mode 100644 index 3558d981e336..000000000000 --- a/arch/tile/kernel/vmlinux.lds.S +++ /dev/null @@ -1,105 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#include -#include -#include -#include -#include - -/* Text loads starting from the supervisor interrupt vector address. */ -#define TEXT_OFFSET MEM_SV_START - -OUTPUT_ARCH(tile) -ENTRY(_start) -jiffies = jiffies_64; - -PHDRS -{ - intrpt PT_LOAD ; - text PT_LOAD ; - data PT_LOAD ; -} -SECTIONS -{ - /* Text is loaded with a different VA than data; start with text. */ - #undef LOAD_OFFSET - #define LOAD_OFFSET TEXT_OFFSET - - /* Interrupt vectors */ - .intrpt (LOAD_OFFSET) : AT ( 0 ) /* put at the start of physical memory */ - { - _text = .; - *(.intrpt) - } :intrpt =0 - - /* Hypervisor call vectors */ - . = ALIGN(0x10000); - .hvglue : AT (ADDR(.hvglue) - LOAD_OFFSET) { - *(.hvglue) - } :NONE - - /* Now the real code */ - . = ALIGN(0x20000); - _stext = .; - .text : AT (ADDR(.text) - LOAD_OFFSET) { - HEAD_TEXT - SCHED_TEXT - CPUIDLE_TEXT - LOCK_TEXT - KPROBES_TEXT - IRQENTRY_TEXT - SOFTIRQENTRY_TEXT - __fix_text_end = .; /* tile-cpack won't rearrange before this */ - ALIGN_FUNCTION(); - *(.hottext*) - TEXT_TEXT - *(.text.*) - *(.coldtext*) - *(.fixup) - *(.gnu.warning) - } :text =0 - _etext = .; - - /* "Init" is divided into two areas with very different virtual addresses. */ - INIT_TEXT_SECTION(PAGE_SIZE) - - /* - * Some things, like the __jump_table, may contain symbol references - * to __exit text, so include such text in the final image if so. - * In that case we also override the _einittext from INIT_TEXT_SECTION. - */ -#ifdef CONFIG_JUMP_LABEL - .exit.text : { - EXIT_TEXT - _einittext = .; - } -#endif - - /* Now we skip back to PAGE_OFFSET for the data. */ - . = (. - TEXT_OFFSET + PAGE_OFFSET); - #undef LOAD_OFFSET - #define LOAD_OFFSET PAGE_OFFSET - - . = ALIGN(PAGE_SIZE); - __init_begin = .; - INIT_DATA_SECTION(16) :data =0 - PERCPU_SECTION(L2_CACHE_BYTES) - . = ALIGN(PAGE_SIZE); - __init_end = .; - - _sdata = .; /* Start of data section */ - RO_DATA_SECTION(PAGE_SIZE) - RW_DATA_SECTION(L2_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) - _edata = .; - - EXCEPTION_TABLE(L2_CACHE_BYTES) - NOTES - - - BSS_SECTION(8, PAGE_SIZE, 1) - _end = . ; - - STABS_DEBUG - DWARF_DEBUG - - DISCARDS -} diff --git a/arch/tile/kvm/Kconfig b/arch/tile/kvm/Kconfig deleted file mode 100644 index efce89a8473b..000000000000 --- a/arch/tile/kvm/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# KVM configuration -# - -source "virt/kvm/Kconfig" - -menuconfig VIRTUALIZATION - bool "Virtualization" - ---help--- - Say Y here to get to see options for using your Linux host to run - other operating systems inside virtual machines (guests). - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and - disabled. - -if VIRTUALIZATION - -config KVM - tristate "Kernel-based Virtual Machine (KVM) support" - depends on HAVE_KVM && MODULES - select PREEMPT_NOTIFIERS - select ANON_INODES - select SRCU - ---help--- - Support hosting paravirtualized guest machines. - - This module provides access to the hardware capabilities through - a character device node named /dev/kvm. - - To compile this as a module, choose M here: the module - will be called kvm. - - If unsure, say N. - -source drivers/vhost/Kconfig - -endif # VIRTUALIZATION diff --git a/arch/tile/lib/Makefile b/arch/tile/lib/Makefile deleted file mode 100644 index 815a1fdeb2e4..000000000000 --- a/arch/tile/lib/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -# -# Makefile for TILE-specific library files.. -# - -lib-y = cacheflush.o checksum.o cpumask.o delay.o uaccess.o \ - memmove.o memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \ - strchr_$(BITS).o strlen_$(BITS).o strnlen_$(BITS).o - -lib-$(CONFIG_TILEGX) += memcpy_user_64.o -lib-$(CONFIG_TILEPRO) += atomic_32.o atomic_asm_32.o -lib-$(CONFIG_SMP) += spinlock_$(BITS).o usercopy_$(BITS).o - -obj-$(CONFIG_MODULES) += exports.o - -# The finv_buffer_remote() and copy_{to,from}_user() routines can't -# have -pg added, since they both rely on being leaf functions. -CFLAGS_REMOVE_cacheflush.o = -pg -CFLAGS_REMOVE_memcpy_user_64.o = -pg diff --git a/arch/tile/lib/atomic_32.c b/arch/tile/lib/atomic_32.c deleted file mode 100644 index f8128800dbf5..000000000000 --- a/arch/tile/lib/atomic_32.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* This page is remapped on startup to be hash-for-home. */ -int atomic_locks[PAGE_SIZE / sizeof(int)] __page_aligned_bss; - -int *__atomic_hashed_lock(volatile void *v) -{ - /* NOTE: this code must match "sys_cmpxchg" in kernel/intvec_32.S */ - /* - * Use bits [3, 3 + ATOMIC_HASH_SHIFT) as the lock index. - * Using mm works here because atomic_locks is page aligned. - */ - unsigned long ptr = __insn_mm((unsigned long)v >> 1, - (unsigned long)atomic_locks, - 2, (ATOMIC_HASH_SHIFT + 2) - 1); - return (int *)ptr; -} - -#ifdef CONFIG_SMP -/* Return whether the passed pointer is a valid atomic lock pointer. */ -static int is_atomic_lock(int *p) -{ - return p >= &atomic_locks[0] && p < &atomic_locks[ATOMIC_HASH_SIZE]; -} - -void __atomic_fault_unlock(int *irqlock_word) -{ - BUG_ON(!is_atomic_lock(irqlock_word)); - BUG_ON(*irqlock_word != 1); - *irqlock_word = 0; -} - -#endif /* CONFIG_SMP */ - -static inline int *__atomic_setup(volatile void *v) -{ - /* Issue a load to the target to bring it into cache. */ - *(volatile int *)v; - return __atomic_hashed_lock(v); -} - -int _atomic_xchg(int *v, int n) -{ - return __atomic32_xchg(v, __atomic_setup(v), n).val; -} -EXPORT_SYMBOL(_atomic_xchg); - -int _atomic_xchg_add(int *v, int i) -{ - return __atomic32_xchg_add(v, __atomic_setup(v), i).val; -} -EXPORT_SYMBOL(_atomic_xchg_add); - -int _atomic_xchg_add_unless(int *v, int a, int u) -{ - /* - * Note: argument order is switched here since it is easier - * to use the first argument consistently as the "old value" - * in the assembly, as is done for _atomic_cmpxchg(). - */ - return __atomic32_xchg_add_unless(v, __atomic_setup(v), u, a).val; -} -EXPORT_SYMBOL(_atomic_xchg_add_unless); - -int _atomic_cmpxchg(int *v, int o, int n) -{ - return __atomic32_cmpxchg(v, __atomic_setup(v), o, n).val; -} -EXPORT_SYMBOL(_atomic_cmpxchg); - -unsigned long _atomic_fetch_or(volatile unsigned long *p, unsigned long mask) -{ - return __atomic32_fetch_or((int *)p, __atomic_setup(p), mask).val; -} -EXPORT_SYMBOL(_atomic_fetch_or); - -unsigned long _atomic_fetch_and(volatile unsigned long *p, unsigned long mask) -{ - return __atomic32_fetch_and((int *)p, __atomic_setup(p), mask).val; -} -EXPORT_SYMBOL(_atomic_fetch_and); - -unsigned long _atomic_fetch_andn(volatile unsigned long *p, unsigned long mask) -{ - return __atomic32_fetch_andn((int *)p, __atomic_setup(p), mask).val; -} -EXPORT_SYMBOL(_atomic_fetch_andn); - -unsigned long _atomic_fetch_xor(volatile unsigned long *p, unsigned long mask) -{ - return __atomic32_fetch_xor((int *)p, __atomic_setup(p), mask).val; -} -EXPORT_SYMBOL(_atomic_fetch_xor); - - -long long _atomic64_xchg(long long *v, long long n) -{ - return __atomic64_xchg(v, __atomic_setup(v), n); -} -EXPORT_SYMBOL(_atomic64_xchg); - -long long _atomic64_xchg_add(long long *v, long long i) -{ - return __atomic64_xchg_add(v, __atomic_setup(v), i); -} -EXPORT_SYMBOL(_atomic64_xchg_add); - -long long _atomic64_xchg_add_unless(long long *v, long long a, long long u) -{ - /* - * Note: argument order is switched here since it is easier - * to use the first argument consistently as the "old value" - * in the assembly, as is done for _atomic_cmpxchg(). - */ - return __atomic64_xchg_add_unless(v, __atomic_setup(v), u, a); -} -EXPORT_SYMBOL(_atomic64_xchg_add_unless); - -long long _atomic64_cmpxchg(long long *v, long long o, long long n) -{ - return __atomic64_cmpxchg(v, __atomic_setup(v), o, n); -} -EXPORT_SYMBOL(_atomic64_cmpxchg); - -long long _atomic64_fetch_and(long long *v, long long n) -{ - return __atomic64_fetch_and(v, __atomic_setup(v), n); -} -EXPORT_SYMBOL(_atomic64_fetch_and); - -long long _atomic64_fetch_or(long long *v, long long n) -{ - return __atomic64_fetch_or(v, __atomic_setup(v), n); -} -EXPORT_SYMBOL(_atomic64_fetch_or); - -long long _atomic64_fetch_xor(long long *v, long long n) -{ - return __atomic64_fetch_xor(v, __atomic_setup(v), n); -} -EXPORT_SYMBOL(_atomic64_fetch_xor); - -/* - * If any of the atomic or futex routines hit a bad address (not in - * the page tables at kernel PL) this routine is called. The futex - * routines are never used on kernel space, and the normal atomics and - * bitops are never used on user space. So a fault on kernel space - * must be fatal, but a fault on userspace is a futex fault and we - * need to return -EFAULT. Note that the context this routine is - * invoked in is the context of the "_atomic_xxx()" routines called - * by the functions in this file. - */ -struct __get_user __atomic_bad_address(int __user *addr) -{ - if (unlikely(!access_ok(VERIFY_WRITE, addr, sizeof(int)))) - panic("Bad address used for kernel atomic op: %p\n", addr); - return (struct __get_user) { .err = -EFAULT }; -} - - -void __init __init_atomic_per_cpu(void) -{ - /* Validate power-of-two and "bigger than cpus" assumption */ - BUILD_BUG_ON(ATOMIC_HASH_SIZE & (ATOMIC_HASH_SIZE-1)); - BUG_ON(ATOMIC_HASH_SIZE < nr_cpu_ids); - - /* - * On TILEPro we prefer to use a single hash-for-home - * page, since this means atomic operations are less - * likely to encounter a TLB fault and thus should - * in general perform faster. You may wish to disable - * this in situations where few hash-for-home tiles - * are configured. - */ - BUG_ON((unsigned long)atomic_locks % PAGE_SIZE != 0); - - /* The locks must all fit on one page. */ - BUILD_BUG_ON(ATOMIC_HASH_SIZE * sizeof(int) > PAGE_SIZE); - - /* - * We use the page offset of the atomic value's address as - * an index into atomic_locks, excluding the low 3 bits. - * That should not produce more indices than ATOMIC_HASH_SIZE. - */ - BUILD_BUG_ON((PAGE_SIZE >> 3) > ATOMIC_HASH_SIZE); -} diff --git a/arch/tile/lib/atomic_asm_32.S b/arch/tile/lib/atomic_asm_32.S deleted file mode 100644 index 94709ab41ed8..000000000000 --- a/arch/tile/lib/atomic_asm_32.S +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Support routines for atomic operations. Each function takes: - * - * r0: address to manipulate - * r1: pointer to atomic lock guarding this operation (for ATOMIC_LOCK_REG) - * r2: new value to write, or for cmpxchg/add_unless, value to compare against - * r3: (cmpxchg/xchg_add_unless) new value to write or add; - * (atomic64 ops) high word of value to write - * r4/r5: (cmpxchg64/add_unless64) new value to write or add - * - * The 32-bit routines return a "struct __get_user" so that the futex code - * has an opportunity to return -EFAULT to the user if needed. - * The 64-bit routines just return a "long long" with the value, - * since they are only used from kernel space and don't expect to fault. - * Support for 16-bit ops is included in the framework but we don't provide any. - * - * Note that the caller is advised to issue a suitable L1 or L2 - * prefetch on the address being manipulated to avoid extra stalls. - * In addition, the hot path is on two icache lines, and we start with - * a jump to the second line to make sure they are both in cache so - * that we never stall waiting on icache fill while holding the lock. - * (This doesn't work out with most 64-bit ops, since they consume - * too many bundles, so may take an extra i-cache stall.) - * - * These routines set the INTERRUPT_CRITICAL_SECTION bit, just - * like sys_cmpxchg(), so that NMIs like PERF_COUNT will not interrupt - * the code, just page faults. - * - * If the load or store faults in a way that can be directly fixed in - * the do_page_fault_ics() handler (e.g. a vmalloc reference) we fix it - * directly, return to the instruction that faulted, and retry it. - * - * If the load or store faults in a way that potentially requires us - * to release the atomic lock, then retry (e.g. a migrating PTE), we - * reset the PC in do_page_fault_ics() to the "tns" instruction so - * that on return we will reacquire the lock and restart the op. We - * are somewhat overloading the exception_table_entry notion by doing - * this, since those entries are not normally used for migrating PTEs. - * - * If the main page fault handler discovers a bad address, it will see - * the PC pointing to the "tns" instruction (due to the earlier - * exception_table_entry processing in do_page_fault_ics), and - * re-reset the PC to the fault handler, atomic_bad_address(), which - * effectively takes over from the atomic op and can either return a - * bad "struct __get_user" (for user addresses) or can just panic (for - * bad kernel addresses). - * - * Note that if the value we would store is the same as what we - * loaded, we bypass the store. Other platforms with true atomics can - * make the guarantee that a non-atomic __clear_bit(), for example, - * can safely race with an atomic test_and_set_bit(); this example is - * from bit_spinlock.h in slub_lock() / slub_unlock(). We can't do - * that on Tile since the "atomic" op is really just a - * read/modify/write, and can race with the non-atomic - * read/modify/write. However, if we can short-circuit the write when - * it is not needed, in the atomic case, we avoid the race. - */ - -#include -#include -#include -#include - - .section .text.atomic,"ax" -ENTRY(__start_atomic_asm_code) - - .macro atomic_op, name, bitwidth, body - .align 64 -STD_ENTRY_SECTION(__atomic\name, .text.atomic) - { - movei r24, 1 - j 4f /* branch to second cache line */ - } -1: { - .ifc \bitwidth,16 - lh r22, r0 - .else - lw r22, r0 - addi r28, r0, 4 - .endif - } - .ifc \bitwidth,64 - lw r23, r28 - .endif - \body /* set r24, and r25 if 64-bit */ - { - seq r26, r22, r24 - seq r27, r23, r25 - } - .ifc \bitwidth,64 - bbnst r27, 2f - .endif - bbs r26, 3f /* skip write-back if it's the same value */ -2: { - .ifc \bitwidth,16 - sh r0, r24 - .else - sw r0, r24 - .endif - } - .ifc \bitwidth,64 - sw r28, r25 - .endif - mf -3: { - move r0, r22 - .ifc \bitwidth,64 - move r1, r23 - .else - move r1, zero - .endif - sw ATOMIC_LOCK_REG_NAME, zero - } - mtspr INTERRUPT_CRITICAL_SECTION, zero - jrp lr -4: { - move ATOMIC_LOCK_REG_NAME, r1 - mtspr INTERRUPT_CRITICAL_SECTION, r24 - } -#ifndef CONFIG_SMP - j 1b /* no atomic locks */ -#else - { - tns r21, ATOMIC_LOCK_REG_NAME - moveli r23, 2048 /* maximum backoff time in cycles */ - } - { - bzt r21, 1b /* branch if lock acquired */ - moveli r25, 32 /* starting backoff time in cycles */ - } -5: mtspr INTERRUPT_CRITICAL_SECTION, zero - mfspr r26, CYCLE_LOW /* get start point for this backoff */ -6: mfspr r22, CYCLE_LOW /* test to see if we've backed off enough */ - sub r22, r22, r26 - slt r22, r22, r25 - bbst r22, 6b - { - mtspr INTERRUPT_CRITICAL_SECTION, r24 - shli r25, r25, 1 /* double the backoff; retry the tns */ - } - { - tns r21, ATOMIC_LOCK_REG_NAME - slt r26, r23, r25 /* is the proposed backoff too big? */ - } - { - bzt r21, 1b /* branch if lock acquired */ - mvnz r25, r26, r23 - } - j 5b -#endif - STD_ENDPROC(__atomic\name) - .ifc \bitwidth,32 - .pushsection __ex_table,"a" - .align 4 - .word 1b, __atomic\name - .word 2b, __atomic\name - .word __atomic\name, __atomic_bad_address - .popsection - .endif - .endm - - -/* - * Use __atomic32 prefix to avoid collisions with GCC builtin __atomic functions. - */ - -atomic_op 32_cmpxchg, 32, "seq r26, r22, r2; { bbns r26, 3f; move r24, r3 }" -atomic_op 32_xchg, 32, "move r24, r2" -atomic_op 32_xchg_add, 32, "add r24, r22, r2" -atomic_op 32_xchg_add_unless, 32, \ - "sne r26, r22, r2; { bbns r26, 3f; add r24, r22, r3 }" -atomic_op 32_fetch_or, 32, "or r24, r22, r2" -atomic_op 32_fetch_and, 32, "and r24, r22, r2" -atomic_op 32_fetch_andn, 32, "nor r2, r2, zero; and r24, r22, r2" -atomic_op 32_fetch_xor, 32, "xor r24, r22, r2" - -atomic_op 64_cmpxchg, 64, "{ seq r26, r22, r2; seq r27, r23, r3 }; \ - { bbns r26, 3f; move r24, r4 }; { bbns r27, 3f; move r25, r5 }" -atomic_op 64_xchg, 64, "{ move r24, r2; move r25, r3 }" -atomic_op 64_xchg_add, 64, "{ add r24, r22, r2; add r25, r23, r3 }; \ - slt_u r26, r24, r22; add r25, r25, r26" -atomic_op 64_xchg_add_unless, 64, \ - "{ sne r26, r22, r2; sne r27, r23, r3 }; \ - { bbns r26, 3f; add r24, r22, r4 }; \ - { bbns r27, 3f; add r25, r23, r5 }; \ - slt_u r26, r24, r22; add r25, r25, r26" -atomic_op 64_fetch_or, 64, "{ or r24, r22, r2; or r25, r23, r3 }" -atomic_op 64_fetch_and, 64, "{ and r24, r22, r2; and r25, r23, r3 }" -atomic_op 64_fetch_xor, 64, "{ xor r24, r22, r2; xor r25, r23, r3 }" - - jrp lr /* happy backtracer */ - -ENTRY(__end_atomic_asm_code) diff --git a/arch/tile/lib/cacheflush.c b/arch/tile/lib/cacheflush.c deleted file mode 100644 index c1ebc1065fc1..000000000000 --- a/arch/tile/lib/cacheflush.c +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include - - -void __flush_icache_range(unsigned long start, unsigned long end) -{ - invalidate_icache((const void *)start, end - start, PAGE_SIZE); -} - - -/* Force a load instruction to issue. */ -static inline void force_load(char *p) -{ - *(volatile char *)p; -} - -/* - * Flush and invalidate a VA range that is homed remotely on a single - * core (if "!hfh") or homed via hash-for-home (if "hfh"), waiting - * until the memory controller holds the flushed values. - */ -void __attribute__((optimize("omit-frame-pointer"))) -finv_buffer_remote(void *buffer, size_t size, int hfh) -{ - char *p, *base; - size_t step_size, load_count; - - /* - * On TILEPro the striping granularity is a fixed 8KB; on - * TILE-Gx it is configurable, and we rely on the fact that - * the hypervisor always configures maximum striping, so that - * bits 9 and 10 of the PA are part of the stripe function, so - * every 512 bytes we hit a striping boundary. - * - */ -#ifdef __tilegx__ - const unsigned long STRIPE_WIDTH = 512; -#else - const unsigned long STRIPE_WIDTH = 8192; -#endif - -#ifdef __tilegx__ - /* - * On TILE-Gx, we must disable the dstream prefetcher before doing - * a cache flush; otherwise, we could end up with data in the cache - * that we don't want there. Note that normally we'd do an mf - * after the SPR write to disabling the prefetcher, but we do one - * below, before any further loads, so there's no need to do it - * here. - */ - uint_reg_t old_dstream_pf = __insn_mfspr(SPR_DSTREAM_PF); - __insn_mtspr(SPR_DSTREAM_PF, 0); -#endif - - /* - * Flush and invalidate the buffer out of the local L1/L2 - * and request the home cache to flush and invalidate as well. - */ - __finv_buffer(buffer, size); - - /* - * Wait for the home cache to acknowledge that it has processed - * all the flush-and-invalidate requests. This does not mean - * that the flushed data has reached the memory controller yet, - * but it does mean the home cache is processing the flushes. - */ - __insn_mf(); - - /* - * Issue a load to the last cache line, which can't complete - * until all the previously-issued flushes to the same memory - * controller have also completed. If we weren't striping - * memory, that one load would be sufficient, but since we may - * be, we also need to back up to the last load issued to - * another memory controller, which would be the point where - * we crossed a "striping" boundary (the granularity of striping - * across memory controllers). Keep backing up and doing this - * until we are before the beginning of the buffer, or have - * hit all the controllers. - * - * If we are flushing a hash-for-home buffer, it's even worse. - * Each line may be homed on a different tile, and each tile - * may have up to four lines that are on different - * controllers. So as we walk backwards, we have to touch - * enough cache lines to satisfy these constraints. In - * practice this ends up being close enough to "load from - * every cache line on a full memory stripe on each - * controller" that we simply do that, to simplify the logic. - * - * On TILE-Gx the hash-for-home function is much more complex, - * with the upshot being we can't readily guarantee we have - * hit both entries in the 128-entry AMT that were hit by any - * load in the entire range, so we just re-load them all. - * With larger buffers, we may want to consider using a hypervisor - * trap to issue loads directly to each hash-for-home tile for - * each controller (doing it from Linux would trash the TLB). - */ - if (hfh) { - step_size = L2_CACHE_BYTES; -#ifdef __tilegx__ - load_count = (size + L2_CACHE_BYTES - 1) / L2_CACHE_BYTES; -#else - load_count = (STRIPE_WIDTH / L2_CACHE_BYTES) * - (1 << CHIP_LOG_NUM_MSHIMS()); -#endif - } else { - step_size = STRIPE_WIDTH; - load_count = (1 << CHIP_LOG_NUM_MSHIMS()); - } - - /* Load the last byte of the buffer. */ - p = (char *)buffer + size - 1; - force_load(p); - - /* Bump down to the end of the previous stripe or cache line. */ - p -= step_size; - p = (char *)((unsigned long)p | (step_size - 1)); - - /* Figure out how far back we need to go. */ - base = p - (step_size * (load_count - 2)); - if ((unsigned long)base < (unsigned long)buffer) - base = buffer; - - /* Fire all the loads we need. */ - for (; p >= base; p -= step_size) - force_load(p); - - /* - * Repeat, but with finv's instead of loads, to get rid of the - * data we just loaded into our own cache and the old home L3. - * The finv's are guaranteed not to actually flush the data in - * the buffer back to their home, since we just read it, so the - * lines are clean in cache; we will only invalidate those lines. - */ - p = (char *)buffer + size - 1; - __insn_finv(p); - p -= step_size; - p = (char *)((unsigned long)p | (step_size - 1)); - for (; p >= base; p -= step_size) - __insn_finv(p); - - /* Wait for these finv's (and thus the first finvs) to be done. */ - __insn_mf(); - -#ifdef __tilegx__ - /* Reenable the prefetcher. */ - __insn_mtspr(SPR_DSTREAM_PF, old_dstream_pf); -#endif -} -EXPORT_SYMBOL_GPL(finv_buffer_remote); diff --git a/arch/tile/lib/checksum.c b/arch/tile/lib/checksum.c deleted file mode 100644 index c3ca3e64d9d9..000000000000 --- a/arch/tile/lib/checksum.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * Support code for the main lib/checksum.c. - */ - -#include -#include - -__wsum do_csum(const unsigned char *buff, int len) -{ - int odd, count; - unsigned long result = 0; - - if (len <= 0) - goto out; - odd = 1 & (unsigned long) buff; - if (odd) { - result = (*buff << 8); - len--; - buff++; - } - count = len >> 1; /* nr of 16-bit words.. */ - if (count) { - if (2 & (unsigned long) buff) { - result += *(const unsigned short *)buff; - count--; - len -= 2; - buff += 2; - } - count >>= 1; /* nr of 32-bit words.. */ - if (count) { -#ifdef __tilegx__ - if (4 & (unsigned long) buff) { - unsigned int w = *(const unsigned int *)buff; - result = __insn_v2sadau(result, w, 0); - count--; - len -= 4; - buff += 4; - } - count >>= 1; /* nr of 64-bit words.. */ -#endif - - /* - * This algorithm could wrap around for very - * large buffers, but those should be impossible. - */ - BUG_ON(count >= 65530); - - while (count) { - unsigned long w = *(const unsigned long *)buff; - count--; - buff += sizeof(w); -#ifdef __tilegx__ - result = __insn_v2sadau(result, w, 0); -#else - result = __insn_sadah_u(result, w, 0); -#endif - } -#ifdef __tilegx__ - if (len & 4) { - unsigned int w = *(const unsigned int *)buff; - result = __insn_v2sadau(result, w, 0); - buff += 4; - } -#endif - } - if (len & 2) { - result += *(const unsigned short *) buff; - buff += 2; - } - } - if (len & 1) - result += *buff; - result = csum_long(result); - if (odd) - result = swab16(result); -out: - return result; -} diff --git a/arch/tile/lib/cpumask.c b/arch/tile/lib/cpumask.c deleted file mode 100644 index 75947edccb26..000000000000 --- a/arch/tile/lib/cpumask.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include - -/* - * Allow cropping out bits beyond the end of the array. - * Move to "lib" directory if more clients want to use this routine. - */ -int bitmap_parselist_crop(const char *bp, unsigned long *maskp, int nmaskbits) -{ - unsigned a, b; - - bitmap_zero(maskp, nmaskbits); - do { - if (!isdigit(*bp)) - return -EINVAL; - a = simple_strtoul(bp, (char **)&bp, 10); - b = a; - if (*bp == '-') { - bp++; - if (!isdigit(*bp)) - return -EINVAL; - b = simple_strtoul(bp, (char **)&bp, 10); - } - if (!(a <= b)) - return -EINVAL; - if (b >= nmaskbits) - b = nmaskbits-1; - while (a <= b) { - set_bit(a, maskp); - a++; - } - if (*bp == ',') - bp++; - } while (*bp != '\0' && *bp != '\n'); - return 0; -} -EXPORT_SYMBOL(bitmap_parselist_crop); diff --git a/arch/tile/lib/delay.c b/arch/tile/lib/delay.c deleted file mode 100644 index cdacdd11d360..000000000000 --- a/arch/tile/lib/delay.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include - -void __udelay(unsigned long usecs) -{ - if (usecs > ULONG_MAX / 1000) { - WARN_ON_ONCE(usecs > ULONG_MAX / 1000); - usecs = ULONG_MAX / 1000; - } - __ndelay(usecs * 1000); -} -EXPORT_SYMBOL(__udelay); - -void __ndelay(unsigned long nsecs) -{ - cycles_t target = get_cycles(); - target += ns2cycles(nsecs); - while (get_cycles() < target) - cpu_relax(); -} -EXPORT_SYMBOL(__ndelay); - -void __delay(unsigned long cycles) -{ - cycles_t target = get_cycles() + cycles; - while (get_cycles() < target) - cpu_relax(); -} -EXPORT_SYMBOL(__delay); diff --git a/arch/tile/lib/exports.c b/arch/tile/lib/exports.c deleted file mode 100644 index ecce8e177e3f..000000000000 --- a/arch/tile/lib/exports.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Exports from assembler code and from libtile-cc. - */ - -#include - -/* arch/tile/lib/usercopy.S */ -#include -EXPORT_SYMBOL(clear_user_asm); -EXPORT_SYMBOL(flush_user_asm); -EXPORT_SYMBOL(finv_user_asm); - -/* arch/tile/kernel/entry.S */ -#include -#include -EXPORT_SYMBOL(current_text_addr); - -/* arch/tile/kernel/head.S */ -EXPORT_SYMBOL(empty_zero_page); - -#ifdef CONFIG_FUNCTION_TRACER -/* arch/tile/kernel/mcount_64.S */ -#include -EXPORT_SYMBOL(__mcount); -#endif /* CONFIG_FUNCTION_TRACER */ - -/* arch/tile/lib/, various memcpy files */ -EXPORT_SYMBOL(memcpy); -EXPORT_SYMBOL(raw_copy_to_user); -EXPORT_SYMBOL(raw_copy_from_user); -#ifdef __tilegx__ -EXPORT_SYMBOL(raw_copy_in_user); -#endif - -/* hypervisor glue */ -#include -EXPORT_SYMBOL(hv_dev_open); -EXPORT_SYMBOL(hv_dev_pread); -EXPORT_SYMBOL(hv_dev_pwrite); -EXPORT_SYMBOL(hv_dev_preada); -EXPORT_SYMBOL(hv_dev_pwritea); -EXPORT_SYMBOL(hv_dev_poll); -EXPORT_SYMBOL(hv_dev_poll_cancel); -EXPORT_SYMBOL(hv_dev_close); -EXPORT_SYMBOL(hv_sysconf); -EXPORT_SYMBOL(hv_confstr); -EXPORT_SYMBOL(hv_get_rtc); -EXPORT_SYMBOL(hv_set_rtc); - -/* libgcc.a */ -uint32_t __udivsi3(uint32_t dividend, uint32_t divisor); -EXPORT_SYMBOL(__udivsi3); -int32_t __divsi3(int32_t dividend, int32_t divisor); -EXPORT_SYMBOL(__divsi3); -uint64_t __udivdi3(uint64_t dividend, uint64_t divisor); -EXPORT_SYMBOL(__udivdi3); -int64_t __divdi3(int64_t dividend, int64_t divisor); -EXPORT_SYMBOL(__divdi3); -uint32_t __umodsi3(uint32_t dividend, uint32_t divisor); -EXPORT_SYMBOL(__umodsi3); -int32_t __modsi3(int32_t dividend, int32_t divisor); -EXPORT_SYMBOL(__modsi3); -uint64_t __umoddi3(uint64_t dividend, uint64_t divisor); -EXPORT_SYMBOL(__umoddi3); -int64_t __moddi3(int64_t dividend, int64_t divisor); -EXPORT_SYMBOL(__moddi3); -#ifdef __tilegx__ -typedef int TItype __attribute__((mode(TI))); -TItype __multi3(TItype a, TItype b); -EXPORT_SYMBOL(__multi3); /* required for gcc 7 and later */ -#else -int64_t __muldi3(int64_t, int64_t); -EXPORT_SYMBOL(__muldi3); -uint64_t __lshrdi3(uint64_t, unsigned int); -EXPORT_SYMBOL(__lshrdi3); -uint64_t __ashrdi3(uint64_t, unsigned int); -EXPORT_SYMBOL(__ashrdi3); -uint64_t __ashldi3(uint64_t, unsigned int); -EXPORT_SYMBOL(__ashldi3); -int __ffsdi2(uint64_t); -EXPORT_SYMBOL(__ffsdi2); -#endif diff --git a/arch/tile/lib/memchr_32.c b/arch/tile/lib/memchr_32.c deleted file mode 100644 index cc3d9badf030..000000000000 --- a/arch/tile/lib/memchr_32.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include - -void *memchr(const void *s, int c, size_t n) -{ - const uint32_t *last_word_ptr; - const uint32_t *p; - const char *last_byte_ptr; - uintptr_t s_int; - uint32_t goal, before_mask, v, bits; - char *ret; - - if (__builtin_expect(n == 0, 0)) { - /* Don't dereference any memory if the array is empty. */ - return NULL; - } - - /* Get an aligned pointer. */ - s_int = (uintptr_t) s; - p = (const uint32_t *)(s_int & -4); - - /* Create four copies of the byte for which we are looking. */ - goal = 0x01010101 * (uint8_t) c; - - /* Read the first word, but munge it so that bytes before the array - * will not match goal. - * - * Note that this shift count expression works because we know - * shift counts are taken mod 32. - */ - before_mask = (1 << (s_int << 3)) - 1; - v = (*p | before_mask) ^ (goal & before_mask); - - /* Compute the address of the last byte. */ - last_byte_ptr = (const char *)s + n - 1; - - /* Compute the address of the word containing the last byte. */ - last_word_ptr = (const uint32_t *)((uintptr_t) last_byte_ptr & -4); - - while ((bits = __insn_seqb(v, goal)) == 0) { - if (__builtin_expect(p == last_word_ptr, 0)) { - /* We already read the last word in the array, - * so give up. - */ - return NULL; - } - v = *++p; - } - - /* We found a match, but it might be in a byte past the end - * of the array. - */ - ret = ((char *)p) + (__insn_ctz(bits) >> 3); - return (ret <= last_byte_ptr) ? ret : NULL; -} -EXPORT_SYMBOL(memchr); diff --git a/arch/tile/lib/memchr_64.c b/arch/tile/lib/memchr_64.c deleted file mode 100644 index f8196b3a950e..000000000000 --- a/arch/tile/lib/memchr_64.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include "string-endian.h" - -void *memchr(const void *s, int c, size_t n) -{ - const uint64_t *last_word_ptr; - const uint64_t *p; - const char *last_byte_ptr; - uintptr_t s_int; - uint64_t goal, before_mask, v, bits; - char *ret; - - if (__builtin_expect(n == 0, 0)) { - /* Don't dereference any memory if the array is empty. */ - return NULL; - } - - /* Get an aligned pointer. */ - s_int = (uintptr_t) s; - p = (const uint64_t *)(s_int & -8); - - /* Create eight copies of the byte for which we are looking. */ - goal = copy_byte(c); - - /* Read the first word, but munge it so that bytes before the array - * will not match goal. - */ - before_mask = MASK(s_int); - v = (*p | before_mask) ^ (goal & before_mask); - - /* Compute the address of the last byte. */ - last_byte_ptr = (const char *)s + n - 1; - - /* Compute the address of the word containing the last byte. */ - last_word_ptr = (const uint64_t *)((uintptr_t) last_byte_ptr & -8); - - while ((bits = __insn_v1cmpeq(v, goal)) == 0) { - if (__builtin_expect(p == last_word_ptr, 0)) { - /* We already read the last word in the array, - * so give up. - */ - return NULL; - } - v = *++p; - } - - /* We found a match, but it might be in a byte past the end - * of the array. - */ - ret = ((char *)p) + (CFZ(bits) >> 3); - return (ret <= last_byte_ptr) ? ret : NULL; -} -EXPORT_SYMBOL(memchr); diff --git a/arch/tile/lib/memcpy_32.S b/arch/tile/lib/memcpy_32.S deleted file mode 100644 index 270f1267cd18..000000000000 --- a/arch/tile/lib/memcpy_32.S +++ /dev/null @@ -1,544 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include - - -/* - * This file shares the implementation of the userspace memcpy and - * the kernel's memcpy, copy_to_user and copy_from_user. - */ - -#include - -#define IS_MEMCPY 0 -#define IS_COPY_FROM_USER 1 -#define IS_COPY_TO_USER -1 - - .section .text.memcpy_common, "ax" - .align 64 - -/* Use this to preface each bundle that can cause an exception so - * the kernel can clean up properly. The special cleanup code should - * not use these, since it knows what it is doing. - */ -#define EX \ - .pushsection __ex_table, "a"; \ - .align 4; \ - .word 9f, memcpy_common_fixup; \ - .popsection; \ - 9 - - -/* raw_copy_from_user takes the kernel target address in r0, - * the user source in r1, and the bytes to copy in r2. - * It returns the number of uncopiable bytes (hopefully zero) in r0. - */ -ENTRY(raw_copy_from_user) -.type raw_copy_from_user, @function - FEEDBACK_ENTER_EXPLICIT(raw_copy_from_user, \ - .text.memcpy_common, \ - .Lend_memcpy_common - raw_copy_from_user) - { movei r29, IS_COPY_FROM_USER; j memcpy_common } - .size raw_copy_from_user, . - raw_copy_from_user - -/* raw_copy_to_user takes the user target address in r0, - * the kernel source in r1, and the bytes to copy in r2. - * It returns the number of uncopiable bytes (hopefully zero) in r0. - */ -ENTRY(raw_copy_to_user) -.type raw_copy_to_user, @function - FEEDBACK_REENTER(raw_copy_from_user) - { movei r29, IS_COPY_TO_USER; j memcpy_common } - .size raw_copy_to_user, . - raw_copy_to_user - -ENTRY(memcpy) -.type memcpy, @function - FEEDBACK_REENTER(raw_copy_from_user) - { movei r29, IS_MEMCPY } - .size memcpy, . - memcpy - /* Fall through */ - - .type memcpy_common, @function -memcpy_common: - /* On entry, r29 holds one of the IS_* macro values from above. */ - - - /* r0 is the dest, r1 is the source, r2 is the size. */ - - /* Save aside original dest so we can return it at the end. */ - { sw sp, lr; move r23, r0; or r4, r0, r1 } - - /* Check for an empty size. */ - { bz r2, .Ldone; andi r4, r4, 3 } - - /* Save aside original values in case of a fault. */ - { move r24, r1; move r25, r2 } - move r27, lr - - /* Check for an unaligned source or dest. */ - { bnz r4, .Lcopy_unaligned_maybe_many; addli r4, r2, -256 } - -.Lcheck_aligned_copy_size: - /* If we are copying < 256 bytes, branch to simple case. */ - { blzt r4, .Lcopy_8_check; slti_u r8, r2, 8 } - - /* Copying >= 256 bytes, so jump to complex prefetching loop. */ - { andi r6, r1, 63; j .Lcopy_many } - -/* - * - * Aligned 4 byte at a time copy loop - * - */ - -.Lcopy_8_loop: - /* Copy two words at a time to hide load latency. */ -EX: { lw r3, r1; addi r1, r1, 4; slti_u r8, r2, 16 } -EX: { lw r4, r1; addi r1, r1, 4 } -EX: { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 } -EX: { sw r0, r4; addi r0, r0, 4; addi r2, r2, -4 } -.Lcopy_8_check: - { bzt r8, .Lcopy_8_loop; slti_u r4, r2, 4 } - - /* Copy odd leftover word, if any. */ - { bnzt r4, .Lcheck_odd_stragglers } -EX: { lw r3, r1; addi r1, r1, 4 } -EX: { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 } - -.Lcheck_odd_stragglers: - { bnz r2, .Lcopy_unaligned_few } - -.Ldone: - /* For memcpy return original dest address, else zero. */ - { mz r0, r29, r23; jrp lr } - - -/* - * - * Prefetching multiple cache line copy handler (for large transfers). - * - */ - - /* Copy words until r1 is cache-line-aligned. */ -.Lalign_loop: -EX: { lw r3, r1; addi r1, r1, 4 } - { andi r6, r1, 63 } -EX: { sw r0, r3; addi r0, r0, 4; addi r2, r2, -4 } -.Lcopy_many: - { bnzt r6, .Lalign_loop; addi r9, r0, 63 } - - { addi r3, r1, 60; andi r9, r9, -64 } - - /* No need to prefetch dst, we'll just do the wh64 - * right before we copy a line. - */ -EX: { lw r5, r3; addi r3, r3, 64; movei r4, 1 } - /* Intentionally stall for a few cycles to leave L2 cache alone. */ - { bnzt zero, .; move r27, lr } -EX: { lw r6, r3; addi r3, r3, 64 } - /* Intentionally stall for a few cycles to leave L2 cache alone. */ - { bnzt zero, . } -EX: { lw r7, r3; addi r3, r3, 64 } - /* Intentionally stall for a few cycles to leave L2 cache alone. */ - { bz zero, .Lbig_loop2 } - - /* On entry to this loop: - * - r0 points to the start of dst line 0 - * - r1 points to start of src line 0 - * - r2 >= (256 - 60), only the first time the loop trips. - * - r3 contains r1 + 128 + 60 [pointer to end of source line 2] - * This is our prefetch address. When we get near the end - * rather than prefetching off the end this is changed to point - * to some "safe" recently loaded address. - * - r5 contains *(r1 + 60) [i.e. last word of source line 0] - * - r6 contains *(r1 + 64 + 60) [i.e. last word of source line 1] - * - r9 contains ((r0 + 63) & -64) - * [start of next dst cache line.] - */ - -.Lbig_loop: - { jal .Lcopy_line2; add r15, r1, r2 } - -.Lbig_loop2: - /* Copy line 0, first stalling until r5 is ready. */ -EX: { move r12, r5; lw r16, r1 } - { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 } - /* Prefetch several lines ahead. */ -EX: { lw r5, r3; addi r3, r3, 64 } - { jal .Lcopy_line } - - /* Copy line 1, first stalling until r6 is ready. */ -EX: { move r12, r6; lw r16, r1 } - { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 } - /* Prefetch several lines ahead. */ -EX: { lw r6, r3; addi r3, r3, 64 } - { jal .Lcopy_line } - - /* Copy line 2, first stalling until r7 is ready. */ -EX: { move r12, r7; lw r16, r1 } - { bz r4, .Lcopy_8_check; slti_u r8, r2, 8 } - /* Prefetch several lines ahead. */ -EX: { lw r7, r3; addi r3, r3, 64 } - /* Use up a caches-busy cycle by jumping back to the top of the - * loop. Might as well get it out of the way now. - */ - { j .Lbig_loop } - - - /* On entry: - * - r0 points to the destination line. - * - r1 points to the source line. - * - r3 is the next prefetch address. - * - r9 holds the last address used for wh64. - * - r12 = WORD_15 - * - r16 = WORD_0. - * - r17 == r1 + 16. - * - r27 holds saved lr to restore. - * - * On exit: - * - r0 is incremented by 64. - * - r1 is incremented by 64, unless that would point to a word - * beyond the end of the source array, in which case it is redirected - * to point to an arbitrary word already in the cache. - * - r2 is decremented by 64. - * - r3 is unchanged, unless it points to a word beyond the - * end of the source array, in which case it is redirected - * to point to an arbitrary word already in the cache. - * Redirecting is OK since if we are that close to the end - * of the array we will not come back to this subroutine - * and use the contents of the prefetched address. - * - r4 is nonzero iff r2 >= 64. - * - r9 is incremented by 64, unless it points beyond the - * end of the last full destination cache line, in which - * case it is redirected to a "safe address" that can be - * clobbered (sp - 64) - * - lr contains the value in r27. - */ - -/* r26 unused */ - -.Lcopy_line: - /* TODO: when r3 goes past the end, we would like to redirect it - * to prefetch the last partial cache line (if any) just once, for the - * benefit of the final cleanup loop. But we don't want to - * prefetch that line more than once, or subsequent prefetches - * will go into the RTF. But then .Lbig_loop should unconditionally - * branch to top of loop to execute final prefetch, and its - * nop should become a conditional branch. - */ - - /* We need two non-memory cycles here to cover the resources - * used by the loads initiated by the caller. - */ - { add r15, r1, r2 } -.Lcopy_line2: - { slt_u r13, r3, r15; addi r17, r1, 16 } - - /* NOTE: this will stall for one cycle as L1 is busy. */ - - /* Fill second L1D line. */ -EX: { lw r17, r17; addi r1, r1, 48; mvz r3, r13, r1 } /* r17 = WORD_4 */ - - /* Prepare destination line for writing. */ -EX: { wh64 r9; addi r9, r9, 64 } - /* Load seven words that are L1D hits to cover wh64 L2 usage. */ - - /* Load the three remaining words from the last L1D line, which - * we know has already filled the L1D. - */ -EX: { lw r4, r1; addi r1, r1, 4; addi r20, r1, 16 } /* r4 = WORD_12 */ -EX: { lw r8, r1; addi r1, r1, 4; slt_u r13, r20, r15 }/* r8 = WORD_13 */ -EX: { lw r11, r1; addi r1, r1, -52; mvz r20, r13, r1 } /* r11 = WORD_14 */ - - /* Load the three remaining words from the first L1D line, first - * stalling until it has filled by "looking at" r16. - */ -EX: { lw r13, r1; addi r1, r1, 4; move zero, r16 } /* r13 = WORD_1 */ -EX: { lw r14, r1; addi r1, r1, 4 } /* r14 = WORD_2 */ -EX: { lw r15, r1; addi r1, r1, 8; addi r10, r0, 60 } /* r15 = WORD_3 */ - - /* Load second word from the second L1D line, first - * stalling until it has filled by "looking at" r17. - */ -EX: { lw r19, r1; addi r1, r1, 4; move zero, r17 } /* r19 = WORD_5 */ - - /* Store last word to the destination line, potentially dirtying it - * for the first time, which keeps the L2 busy for two cycles. - */ -EX: { sw r10, r12 } /* store(WORD_15) */ - - /* Use two L1D hits to cover the sw L2 access above. */ -EX: { lw r10, r1; addi r1, r1, 4 } /* r10 = WORD_6 */ -EX: { lw r12, r1; addi r1, r1, 4 } /* r12 = WORD_7 */ - - /* Fill third L1D line. */ -EX: { lw r18, r1; addi r1, r1, 4 } /* r18 = WORD_8 */ - - /* Store first L1D line. */ -EX: { sw r0, r16; addi r0, r0, 4; add r16, r0, r2 } /* store(WORD_0) */ -EX: { sw r0, r13; addi r0, r0, 4; andi r16, r16, -64 } /* store(WORD_1) */ -EX: { sw r0, r14; addi r0, r0, 4; slt_u r16, r9, r16 } /* store(WORD_2) */ -EX: { sw r0, r15; addi r0, r0, 4; addi r13, sp, -64 } /* store(WORD_3) */ - /* Store second L1D line. */ -EX: { sw r0, r17; addi r0, r0, 4; mvz r9, r16, r13 }/* store(WORD_4) */ -EX: { sw r0, r19; addi r0, r0, 4 } /* store(WORD_5) */ -EX: { sw r0, r10; addi r0, r0, 4 } /* store(WORD_6) */ -EX: { sw r0, r12; addi r0, r0, 4 } /* store(WORD_7) */ - -EX: { lw r13, r1; addi r1, r1, 4; move zero, r18 } /* r13 = WORD_9 */ -EX: { lw r14, r1; addi r1, r1, 4 } /* r14 = WORD_10 */ -EX: { lw r15, r1; move r1, r20 } /* r15 = WORD_11 */ - - /* Store third L1D line. */ -EX: { sw r0, r18; addi r0, r0, 4 } /* store(WORD_8) */ -EX: { sw r0, r13; addi r0, r0, 4 } /* store(WORD_9) */ -EX: { sw r0, r14; addi r0, r0, 4 } /* store(WORD_10) */ -EX: { sw r0, r15; addi r0, r0, 4 } /* store(WORD_11) */ - - /* Store rest of fourth L1D line. */ -EX: { sw r0, r4; addi r0, r0, 4 } /* store(WORD_12) */ - { -EX: sw r0, r8 /* store(WORD_13) */ - addi r0, r0, 4 - /* Will r2 be > 64 after we subtract 64 below? */ - shri r4, r2, 7 - } - { -EX: sw r0, r11 /* store(WORD_14) */ - addi r0, r0, 8 - /* Record 64 bytes successfully copied. */ - addi r2, r2, -64 - } - - { jrp lr; move lr, r27 } - - /* Convey to the backtrace library that the stack frame is size - * zero, and the real return address is on the stack rather than - * in 'lr'. - */ - { info 8 } - - .align 64 -.Lcopy_unaligned_maybe_many: - /* Skip the setup overhead if we aren't copying many bytes. */ - { slti_u r8, r2, 20; sub r4, zero, r0 } - { bnzt r8, .Lcopy_unaligned_few; andi r4, r4, 3 } - { bz r4, .Ldest_is_word_aligned; add r18, r1, r2 } - -/* - * - * unaligned 4 byte at a time copy handler. - * - */ - - /* Copy single bytes until r0 == 0 mod 4, so we can store words. */ -.Lalign_dest_loop: -EX: { lb_u r3, r1; addi r1, r1, 1; addi r4, r4, -1 } -EX: { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 } - { bnzt r4, .Lalign_dest_loop; andi r3, r1, 3 } - - /* If source and dest are now *both* aligned, do an aligned copy. */ - { bz r3, .Lcheck_aligned_copy_size; addli r4, r2, -256 } - -.Ldest_is_word_aligned: - -EX: { andi r8, r0, 63; lwadd_na r6, r1, 4} - { slti_u r9, r2, 64; bz r8, .Ldest_is_L2_line_aligned } - - /* This copies unaligned words until either there are fewer - * than 4 bytes left to copy, or until the destination pointer - * is cache-aligned, whichever comes first. - * - * On entry: - * - r0 is the next store address. - * - r1 points 4 bytes past the load address corresponding to r0. - * - r2 >= 4 - * - r6 is the next aligned word loaded. - */ -.Lcopy_unaligned_src_words: -EX: { lwadd_na r7, r1, 4; slti_u r8, r2, 4 + 4 } - /* stall */ - { dword_align r6, r7, r1; slti_u r9, r2, 64 + 4 } -EX: { swadd r0, r6, 4; addi r2, r2, -4 } - { bnz r8, .Lcleanup_unaligned_words; andi r8, r0, 63 } - { bnzt r8, .Lcopy_unaligned_src_words; move r6, r7 } - - /* On entry: - * - r0 is the next store address. - * - r1 points 4 bytes past the load address corresponding to r0. - * - r2 >= 4 (# of bytes left to store). - * - r6 is the next aligned src word value. - * - r9 = (r2 < 64U). - * - r18 points one byte past the end of source memory. - */ -.Ldest_is_L2_line_aligned: - - { - /* Not a full cache line remains. */ - bnz r9, .Lcleanup_unaligned_words - move r7, r6 - } - - /* r2 >= 64 */ - - /* Kick off two prefetches, but don't go past the end. */ - { addi r3, r1, 63 - 4; addi r8, r1, 64 + 63 - 4 } - { prefetch r3; move r3, r8; slt_u r8, r8, r18 } - { mvz r3, r8, r1; addi r8, r3, 64 } - { prefetch r3; move r3, r8; slt_u r8, r8, r18 } - { mvz r3, r8, r1; movei r17, 0 } - -.Lcopy_unaligned_line: - /* Prefetch another line. */ - { prefetch r3; addi r15, r1, 60; addi r3, r3, 64 } - /* Fire off a load of the last word we are about to copy. */ -EX: { lw_na r15, r15; slt_u r8, r3, r18 } - -EX: { mvz r3, r8, r1; wh64 r0 } - - /* This loop runs twice. - * - * On entry: - * - r17 is even before the first iteration, and odd before - * the second. It is incremented inside the loop. Encountering - * an even value at the end of the loop makes it stop. - */ -.Lcopy_half_an_unaligned_line: -EX: { - /* Stall until the last byte is ready. In the steady state this - * guarantees all words to load below will be in the L2 cache, which - * avoids shunting the loads to the RTF. - */ - move zero, r15 - lwadd_na r7, r1, 16 - } -EX: { lwadd_na r11, r1, 12 } -EX: { lwadd_na r14, r1, -24 } -EX: { lwadd_na r8, r1, 4 } -EX: { lwadd_na r9, r1, 4 } -EX: { - lwadd_na r10, r1, 8 - /* r16 = (r2 < 64), after we subtract 32 from r2 below. */ - slti_u r16, r2, 64 + 32 - } -EX: { lwadd_na r12, r1, 4; addi r17, r17, 1 } -EX: { lwadd_na r13, r1, 8; dword_align r6, r7, r1 } -EX: { swadd r0, r6, 4; dword_align r7, r8, r1 } -EX: { swadd r0, r7, 4; dword_align r8, r9, r1 } -EX: { swadd r0, r8, 4; dword_align r9, r10, r1 } -EX: { swadd r0, r9, 4; dword_align r10, r11, r1 } -EX: { swadd r0, r10, 4; dword_align r11, r12, r1 } -EX: { swadd r0, r11, 4; dword_align r12, r13, r1 } -EX: { swadd r0, r12, 4; dword_align r13, r14, r1 } -EX: { swadd r0, r13, 4; addi r2, r2, -32 } - { move r6, r14; bbst r17, .Lcopy_half_an_unaligned_line } - - { bzt r16, .Lcopy_unaligned_line; move r7, r6 } - - /* On entry: - * - r0 is the next store address. - * - r1 points 4 bytes past the load address corresponding to r0. - * - r2 >= 0 (# of bytes left to store). - * - r7 is the next aligned src word value. - */ -.Lcleanup_unaligned_words: - /* Handle any trailing bytes. */ - { bz r2, .Lcopy_unaligned_done; slti_u r8, r2, 4 } - { bzt r8, .Lcopy_unaligned_src_words; move r6, r7 } - - /* Move r1 back to the point where it corresponds to r0. */ - { addi r1, r1, -4 } - - /* Fall through */ - -/* - * - * 1 byte at a time copy handler. - * - */ - -.Lcopy_unaligned_few: -EX: { lb_u r3, r1; addi r1, r1, 1 } -EX: { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 } - { bnzt r2, .Lcopy_unaligned_few } - -.Lcopy_unaligned_done: - - /* For memcpy return original dest address, else zero. */ - { mz r0, r29, r23; jrp lr } - -.Lend_memcpy_common: - .size memcpy_common, .Lend_memcpy_common - memcpy_common - - .section .fixup,"ax" -memcpy_common_fixup: - .type memcpy_common_fixup, @function - - /* Skip any bytes we already successfully copied. - * r2 (num remaining) is correct, but r0 (dst) and r1 (src) - * may not be quite right because of unrolling and prefetching. - * So we need to recompute their values as the address just - * after the last byte we are sure was successfully loaded and - * then stored. - */ - - /* Determine how many bytes we successfully copied. */ - { sub r3, r25, r2 } - - /* Add this to the original r0 and r1 to get their new values. */ - { add r0, r23, r3; add r1, r24, r3 } - - { bzt r29, memcpy_fixup_loop } - { blzt r29, copy_to_user_fixup_loop } - -copy_from_user_fixup_loop: - /* Try copying the rest one byte at a time, expecting a load fault. */ -.Lcfu: { lb_u r3, r1; addi r1, r1, 1 } - { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 } - { bnzt r2, copy_from_user_fixup_loop } - -.Lcopy_from_user_fixup_zero_remainder: - move lr, r27 - { move r0, r2; jrp lr } - -copy_to_user_fixup_loop: - /* Try copying the rest one byte at a time, expecting a store fault. */ - { lb_u r3, r1; addi r1, r1, 1 } -.Lctu: { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 } - { bnzt r2, copy_to_user_fixup_loop } -.Lcopy_to_user_fixup_done: - move lr, r27 - { move r0, r2; jrp lr } - -memcpy_fixup_loop: - /* Try copying the rest one byte at a time. We expect a disastrous - * fault to happen since we are in fixup code, but let it happen. - */ - { lb_u r3, r1; addi r1, r1, 1 } - { sb r0, r3; addi r0, r0, 1; addi r2, r2, -1 } - { bnzt r2, memcpy_fixup_loop } - /* This should be unreachable, we should have faulted again. - * But be paranoid and handle it in case some interrupt changed - * the TLB or something. - */ - move lr, r27 - { move r0, r23; jrp lr } - - .size memcpy_common_fixup, . - memcpy_common_fixup - - .section __ex_table,"a" - .align 4 - .word .Lcfu, .Lcopy_from_user_fixup_zero_remainder - .word .Lctu, .Lcopy_to_user_fixup_done diff --git a/arch/tile/lib/memcpy_64.c b/arch/tile/lib/memcpy_64.c deleted file mode 100644 index 4815354b8cd2..000000000000 --- a/arch/tile/lib/memcpy_64.c +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -/* EXPORT_SYMBOL() is in arch/tile/lib/exports.c since this should be asm. */ - -/* Must be 8 bytes in size. */ -#define op_t uint64_t - -/* Threshold value for when to enter the unrolled loops. */ -#define OP_T_THRES 16 - -#if CHIP_L2_LINE_SIZE() != 64 -#error "Assumes 64 byte line size" -#endif - -/* How many cache lines ahead should we prefetch? */ -#define PREFETCH_LINES_AHEAD 4 - -/* - * Provide "base versions" of load and store for the normal code path. - * The kernel provides other versions for userspace copies. - */ -#define ST(p, v) (*(p) = (v)) -#define LD(p) (*(p)) - -#ifndef USERCOPY_FUNC -#define ST1 ST -#define ST2 ST -#define ST4 ST -#define ST8 ST -#define LD1 LD -#define LD2 LD -#define LD4 LD -#define LD8 LD -#define RETVAL dstv -void *memcpy(void *__restrict dstv, const void *__restrict srcv, size_t n) -#else -/* - * Special kernel version will provide implementation of the LDn/STn - * macros to return a count of uncopied bytes due to mm fault. - */ -#define RETVAL 0 -int __attribute__((optimize("omit-frame-pointer"))) -USERCOPY_FUNC(void *__restrict dstv, const void *__restrict srcv, size_t n) -#endif -{ - char *__restrict dst1 = (char *)dstv; - const char *__restrict src1 = (const char *)srcv; - const char *__restrict src1_end; - const char *__restrict prefetch; - op_t *__restrict dst8; /* 8-byte pointer to destination memory. */ - op_t final; /* Final bytes to write to trailing word, if any */ - long i; - - if (n < 16) { - for (; n; n--) - ST1(dst1++, LD1(src1++)); - return RETVAL; - } - - /* - * Locate the end of source memory we will copy. Don't - * prefetch past this. - */ - src1_end = src1 + n - 1; - - /* Prefetch ahead a few cache lines, but not past the end. */ - prefetch = src1; - for (i = 0; i < PREFETCH_LINES_AHEAD; i++) { - __insn_prefetch(prefetch); - prefetch += CHIP_L2_LINE_SIZE(); - prefetch = (prefetch < src1_end) ? prefetch : src1; - } - - /* Copy bytes until dst is word-aligned. */ - for (; (uintptr_t)dst1 & (sizeof(op_t) - 1); n--) - ST1(dst1++, LD1(src1++)); - - /* 8-byte pointer to destination memory. */ - dst8 = (op_t *)dst1; - - if (__builtin_expect((uintptr_t)src1 & (sizeof(op_t) - 1), 0)) { - /* Unaligned copy. */ - - op_t tmp0 = 0, tmp1 = 0, tmp2, tmp3; - const op_t *src8 = (const op_t *) ((uintptr_t)src1 & - -sizeof(op_t)); - const void *srci = (void *)src1; - int m; - - m = (CHIP_L2_LINE_SIZE() << 2) - - (((uintptr_t)dst8) & ((CHIP_L2_LINE_SIZE() << 2) - 1)); - m = (n < m) ? n : m; - m /= sizeof(op_t); - - /* Copy until 'dst' is cache-line-aligned. */ - n -= (sizeof(op_t) * m); - - switch (m % 4) { - case 0: - if (__builtin_expect(!m, 0)) - goto _M0; - tmp1 = LD8(src8++); - tmp2 = LD8(src8++); - goto _8B3; - case 2: - m += 2; - tmp3 = LD8(src8++); - tmp0 = LD8(src8++); - goto _8B1; - case 3: - m += 1; - tmp2 = LD8(src8++); - tmp3 = LD8(src8++); - goto _8B2; - case 1: - m--; - tmp0 = LD8(src8++); - tmp1 = LD8(src8++); - if (__builtin_expect(!m, 0)) - goto _8B0; - } - - do { - tmp2 = LD8(src8++); - tmp0 = __insn_dblalign(tmp0, tmp1, srci); - ST8(dst8++, tmp0); -_8B3: - tmp3 = LD8(src8++); - tmp1 = __insn_dblalign(tmp1, tmp2, srci); - ST8(dst8++, tmp1); -_8B2: - tmp0 = LD8(src8++); - tmp2 = __insn_dblalign(tmp2, tmp3, srci); - ST8(dst8++, tmp2); -_8B1: - tmp1 = LD8(src8++); - tmp3 = __insn_dblalign(tmp3, tmp0, srci); - ST8(dst8++, tmp3); - m -= 4; - } while (m); - -_8B0: - tmp0 = __insn_dblalign(tmp0, tmp1, srci); - ST8(dst8++, tmp0); - src8--; - -_M0: - if (__builtin_expect(n >= CHIP_L2_LINE_SIZE(), 0)) { - op_t tmp4, tmp5, tmp6, tmp7, tmp8; - - prefetch = ((const char *)src8) + - CHIP_L2_LINE_SIZE() * PREFETCH_LINES_AHEAD; - - for (tmp0 = LD8(src8++); n >= CHIP_L2_LINE_SIZE(); - n -= CHIP_L2_LINE_SIZE()) { - /* Prefetch and advance to next line to - prefetch, but don't go past the end. */ - __insn_prefetch(prefetch); - - /* Make sure prefetch got scheduled - earlier. */ - __asm__ ("" : : : "memory"); - - prefetch += CHIP_L2_LINE_SIZE(); - prefetch = (prefetch < src1_end) ? prefetch : - (const char *) src8; - - tmp1 = LD8(src8++); - tmp2 = LD8(src8++); - tmp3 = LD8(src8++); - tmp4 = LD8(src8++); - tmp5 = LD8(src8++); - tmp6 = LD8(src8++); - tmp7 = LD8(src8++); - tmp8 = LD8(src8++); - - tmp0 = __insn_dblalign(tmp0, tmp1, srci); - tmp1 = __insn_dblalign(tmp1, tmp2, srci); - tmp2 = __insn_dblalign(tmp2, tmp3, srci); - tmp3 = __insn_dblalign(tmp3, tmp4, srci); - tmp4 = __insn_dblalign(tmp4, tmp5, srci); - tmp5 = __insn_dblalign(tmp5, tmp6, srci); - tmp6 = __insn_dblalign(tmp6, tmp7, srci); - tmp7 = __insn_dblalign(tmp7, tmp8, srci); - - __insn_wh64(dst8); - - ST8(dst8++, tmp0); - ST8(dst8++, tmp1); - ST8(dst8++, tmp2); - ST8(dst8++, tmp3); - ST8(dst8++, tmp4); - ST8(dst8++, tmp5); - ST8(dst8++, tmp6); - ST8(dst8++, tmp7); - - tmp0 = tmp8; - } - src8--; - } - - /* Copy the rest 8-byte chunks. */ - if (n >= sizeof(op_t)) { - tmp0 = LD8(src8++); - for (; n >= sizeof(op_t); n -= sizeof(op_t)) { - tmp1 = LD8(src8++); - tmp0 = __insn_dblalign(tmp0, tmp1, srci); - ST8(dst8++, tmp0); - tmp0 = tmp1; - } - src8--; - } - - if (n == 0) - return RETVAL; - - tmp0 = LD8(src8++); - tmp1 = ((const char *)src8 <= src1_end) - ? LD8((op_t *)src8) : 0; - final = __insn_dblalign(tmp0, tmp1, srci); - - } else { - /* Aligned copy. */ - - const op_t *__restrict src8 = (const op_t *)src1; - - /* src8 and dst8 are both word-aligned. */ - if (n >= CHIP_L2_LINE_SIZE()) { - /* Copy until 'dst' is cache-line-aligned. */ - for (; (uintptr_t)dst8 & (CHIP_L2_LINE_SIZE() - 1); - n -= sizeof(op_t)) - ST8(dst8++, LD8(src8++)); - - for (; n >= CHIP_L2_LINE_SIZE(); ) { - op_t tmp0, tmp1, tmp2, tmp3; - op_t tmp4, tmp5, tmp6, tmp7; - - /* - * Prefetch and advance to next line - * to prefetch, but don't go past the - * end. - */ - __insn_prefetch(prefetch); - - /* Make sure prefetch got scheduled - earlier. */ - __asm__ ("" : : : "memory"); - - prefetch += CHIP_L2_LINE_SIZE(); - prefetch = (prefetch < src1_end) ? prefetch : - (const char *)src8; - - /* - * Do all the loads before wh64. This - * is necessary if [src8, src8+7] and - * [dst8, dst8+7] share the same cache - * line and dst8 <= src8, as can be - * the case when called from memmove, - * or with code tested on x86 whose - * memcpy always works with forward - * copies. - */ - tmp0 = LD8(src8++); - tmp1 = LD8(src8++); - tmp2 = LD8(src8++); - tmp3 = LD8(src8++); - tmp4 = LD8(src8++); - tmp5 = LD8(src8++); - tmp6 = LD8(src8++); - tmp7 = LD8(src8++); - - /* wh64 and wait for tmp7 load completion. */ - __asm__ ("move %0, %0; wh64 %1\n" - : : "r"(tmp7), "r"(dst8)); - - ST8(dst8++, tmp0); - ST8(dst8++, tmp1); - ST8(dst8++, tmp2); - ST8(dst8++, tmp3); - ST8(dst8++, tmp4); - ST8(dst8++, tmp5); - ST8(dst8++, tmp6); - ST8(dst8++, tmp7); - - n -= CHIP_L2_LINE_SIZE(); - } -#if CHIP_L2_LINE_SIZE() != 64 -# error "Fix code that assumes particular L2 cache line size." -#endif - } - - for (; n >= sizeof(op_t); n -= sizeof(op_t)) - ST8(dst8++, LD8(src8++)); - - if (__builtin_expect(n == 0, 1)) - return RETVAL; - - final = LD8(src8); - } - - /* n != 0 if we get here. Write out any trailing bytes. */ - dst1 = (char *)dst8; -#ifndef __BIG_ENDIAN__ - if (n & 4) { - ST4((uint32_t *)dst1, final); - dst1 += 4; - final >>= 32; - n &= 3; - } - if (n & 2) { - ST2((uint16_t *)dst1, final); - dst1 += 2; - final >>= 16; - n &= 1; - } - if (n) - ST1((uint8_t *)dst1, final); -#else - if (n & 4) { - ST4((uint32_t *)dst1, final >> 32); - dst1 += 4; - } - else - { - final >>= 32; - } - if (n & 2) { - ST2((uint16_t *)dst1, final >> 16); - dst1 += 2; - } - else - { - final >>= 16; - } - if (n & 1) - ST1((uint8_t *)dst1, final >> 8); -#endif - - return RETVAL; -} - -#ifdef USERCOPY_FUNC -#undef ST1 -#undef ST2 -#undef ST4 -#undef ST8 -#undef LD1 -#undef LD2 -#undef LD4 -#undef LD8 -#undef USERCOPY_FUNC -#endif diff --git a/arch/tile/lib/memcpy_user_64.c b/arch/tile/lib/memcpy_user_64.c deleted file mode 100644 index a3fea9fd973e..000000000000 --- a/arch/tile/lib/memcpy_user_64.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Do memcpy(), but trap and return "n" when a load or store faults. - * - * Note: this idiom only works when memcpy() compiles to a leaf function. - * Here leaf function not only means it does not have calls, but also - * requires no stack operations (sp, stack frame pointer) and no - * use of callee-saved registers, else "jrp lr" will be incorrect since - * unwinding stack frame is bypassed. Since memcpy() is not complex so - * these conditions are satisfied here, but we need to be careful when - * modifying this file. This is not a clean solution but is the best - * one so far. - * - * Also note that we are capturing "n" from the containing scope here. - */ - -#define _ST(p, inst, v) \ - ({ \ - asm("1: " #inst " %0, %1;" \ - ".pushsection .coldtext,\"ax\";" \ - "2: { move r0, %2; jrp lr };" \ - ".section __ex_table,\"a\";" \ - ".align 8;" \ - ".quad 1b, 2b;" \ - ".popsection" \ - : "=m" (*(p)) : "r" (v), "r" (n)); \ - }) - -#define _LD(p, inst) \ - ({ \ - unsigned long __v; \ - asm("1: " #inst " %0, %1;" \ - ".pushsection .coldtext,\"ax\";" \ - "2: { move r0, %2; jrp lr };" \ - ".section __ex_table,\"a\";" \ - ".align 8;" \ - ".quad 1b, 2b;" \ - ".popsection" \ - : "=r" (__v) : "m" (*(p)), "r" (n)); \ - __v; \ - }) - -#define USERCOPY_FUNC raw_copy_to_user -#define ST1(p, v) _ST((p), st1, (v)) -#define ST2(p, v) _ST((p), st2, (v)) -#define ST4(p, v) _ST((p), st4, (v)) -#define ST8(p, v) _ST((p), st, (v)) -#define LD1 LD -#define LD2 LD -#define LD4 LD -#define LD8 LD -#include "memcpy_64.c" - -#define USERCOPY_FUNC raw_copy_from_user -#define ST1 ST -#define ST2 ST -#define ST4 ST -#define ST8 ST -#define LD1(p) _LD((p), ld1u) -#define LD2(p) _LD((p), ld2u) -#define LD4(p) _LD((p), ld4u) -#define LD8(p) _LD((p), ld) -#include "memcpy_64.c" - -#define USERCOPY_FUNC raw_copy_in_user -#define ST1(p, v) _ST((p), st1, (v)) -#define ST2(p, v) _ST((p), st2, (v)) -#define ST4(p, v) _ST((p), st4, (v)) -#define ST8(p, v) _ST((p), st, (v)) -#define LD1(p) _LD((p), ld1u) -#define LD2(p) _LD((p), ld2u) -#define LD4(p) _LD((p), ld4u) -#define LD8(p) _LD((p), ld) -#include "memcpy_64.c" diff --git a/arch/tile/lib/memmove.c b/arch/tile/lib/memmove.c deleted file mode 100644 index fd615ae6ade7..000000000000 --- a/arch/tile/lib/memmove.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include - -void *memmove(void *dest, const void *src, size_t n) -{ - if ((const char *)src >= (char *)dest + n - || (char *)dest >= (const char *)src + n) { - /* We found no overlap, so let memcpy do all the heavy - * lifting (prefetching, etc.) - */ - return memcpy(dest, src, n); - } - - if (n != 0) { - const uint8_t *in; - uint8_t x; - uint8_t *out; - int stride; - - if (src < dest) { - /* copy backwards */ - in = (const uint8_t *)src + n - 1; - out = (uint8_t *)dest + n - 1; - stride = -1; - } else { - /* copy forwards */ - in = (const uint8_t *)src; - out = (uint8_t *)dest; - stride = 1; - } - - /* Manually software-pipeline this loop. */ - x = *in; - in += stride; - - while (--n != 0) { - *out = x; - out += stride; - x = *in; - in += stride; - } - - *out = x; - } - - return dest; -} -EXPORT_SYMBOL(memmove); diff --git a/arch/tile/lib/memset_32.c b/arch/tile/lib/memset_32.c deleted file mode 100644 index 2042bfe6595f..000000000000 --- a/arch/tile/lib/memset_32.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include - -void *memset(void *s, int c, size_t n) -{ - uint32_t *out32; - int n32; - uint32_t v16, v32; - uint8_t *out8 = s; - int to_align32; - - /* Experimentation shows that a trivial tight loop is a win up until - * around a size of 20, where writing a word at a time starts to win. - */ -#define BYTE_CUTOFF 20 - -#if BYTE_CUTOFF < 3 - /* This must be at least at least this big, or some code later - * on doesn't work. - */ -#error "BYTE_CUTOFF is too small" -#endif - - if (n < BYTE_CUTOFF) { - /* Strangely, this turns out to be the tightest way to - * write this loop. - */ - if (n != 0) { - do { - /* Strangely, combining these into one line - * performs worse. - */ - *out8 = c; - out8++; - } while (--n != 0); - } - - return s; - } - - /* Align 'out8'. We know n >= 3 so this won't write past the end. */ - while (((uintptr_t) out8 & 3) != 0) { - *out8++ = c; - --n; - } - - /* Align 'n'. */ - while (n & 3) - out8[--n] = c; - - out32 = (uint32_t *) out8; - n32 = n >> 2; - - /* Tile input byte out to 32 bits. */ - v16 = __insn_intlb(c, c); - v32 = __insn_intlh(v16, v16); - - /* This must be at least 8 or the following loop doesn't work. */ -#define CACHE_LINE_SIZE_IN_WORDS (CHIP_L2_LINE_SIZE() / 4) - - /* Determine how many words we need to emit before the 'out32' - * pointer becomes aligned modulo the cache line size. - */ - to_align32 = - (-((uintptr_t)out32 >> 2)) & (CACHE_LINE_SIZE_IN_WORDS - 1); - - /* Only bother aligning and using wh64 if there is at least - * one full cache line to process. This check also prevents - * overrunning the end of the buffer with alignment words. - */ - if (to_align32 <= n32 - CACHE_LINE_SIZE_IN_WORDS) { - int lines_left; - - /* Align out32 mod the cache line size so we can use wh64. */ - n32 -= to_align32; - for (; to_align32 != 0; to_align32--) { - *out32 = v32; - out32++; - } - - /* Use unsigned divide to turn this into a right shift. */ - lines_left = (unsigned)n32 / CACHE_LINE_SIZE_IN_WORDS; - - do { - /* Only wh64 a few lines at a time, so we don't - * exceed the maximum number of victim lines. - */ - int x = ((lines_left < CHIP_MAX_OUTSTANDING_VICTIMS()) - ? lines_left - : CHIP_MAX_OUTSTANDING_VICTIMS()); - uint32_t *wh = out32; - int i = x; - int j; - - lines_left -= x; - - do { - __insn_wh64(wh); - wh += CACHE_LINE_SIZE_IN_WORDS; - } while (--i); - - for (j = x * (CACHE_LINE_SIZE_IN_WORDS / 4); - j != 0; j--) { - *out32++ = v32; - *out32++ = v32; - *out32++ = v32; - *out32++ = v32; - } - } while (lines_left != 0); - - /* We processed all full lines above, so only this many - * words remain to be processed. - */ - n32 &= CACHE_LINE_SIZE_IN_WORDS - 1; - } - - /* Now handle any leftover values. */ - if (n32 != 0) { - do { - *out32 = v32; - out32++; - } while (--n32 != 0); - } - - return s; -} -EXPORT_SYMBOL(memset); diff --git a/arch/tile/lib/memset_64.c b/arch/tile/lib/memset_64.c deleted file mode 100644 index 03ef69cd73de..000000000000 --- a/arch/tile/lib/memset_64.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include "string-endian.h" - -void *memset(void *s, int c, size_t n) -{ - uint64_t *out64; - int n64, to_align64; - uint64_t v64; - uint8_t *out8 = s; - - /* Experimentation shows that a trivial tight loop is a win up until - * around a size of 20, where writing a word at a time starts to win. - */ -#define BYTE_CUTOFF 20 - -#if BYTE_CUTOFF < 7 - /* This must be at least at least this big, or some code later - * on doesn't work. - */ -#error "BYTE_CUTOFF is too small" -#endif - - if (n < BYTE_CUTOFF) { - /* Strangely, this turns out to be the tightest way to - * write this loop. - */ - if (n != 0) { - do { - /* Strangely, combining these into one line - * performs worse. - */ - *out8 = c; - out8++; - } while (--n != 0); - } - - return s; - } - - /* Align 'out8'. We know n >= 7 so this won't write past the end. */ - while (((uintptr_t) out8 & 7) != 0) { - *out8++ = c; - --n; - } - - /* Align 'n'. */ - while (n & 7) - out8[--n] = c; - - out64 = (uint64_t *) out8; - n64 = n >> 3; - - /* Tile input byte out to 64 bits. */ - v64 = copy_byte(c); - - /* This must be at least 8 or the following loop doesn't work. */ -#define CACHE_LINE_SIZE_IN_DOUBLEWORDS (CHIP_L2_LINE_SIZE() / 8) - - /* Determine how many words we need to emit before the 'out32' - * pointer becomes aligned modulo the cache line size. - */ - to_align64 = (-((uintptr_t)out64 >> 3)) & - (CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1); - - /* Only bother aligning and using wh64 if there is at least - * one full cache line to process. This check also prevents - * overrunning the end of the buffer with alignment words. - */ - if (to_align64 <= n64 - CACHE_LINE_SIZE_IN_DOUBLEWORDS) { - int lines_left; - - /* Align out64 mod the cache line size so we can use wh64. */ - n64 -= to_align64; - for (; to_align64 != 0; to_align64--) { - *out64 = v64; - out64++; - } - - /* Use unsigned divide to turn this into a right shift. */ - lines_left = (unsigned)n64 / CACHE_LINE_SIZE_IN_DOUBLEWORDS; - - do { - /* Only wh64 a few lines at a time, so we don't - * exceed the maximum number of victim lines. - */ - int x = ((lines_left < CHIP_MAX_OUTSTANDING_VICTIMS()) - ? lines_left - : CHIP_MAX_OUTSTANDING_VICTIMS()); - uint64_t *wh = out64; - int i = x; - int j; - - lines_left -= x; - - do { - __insn_wh64(wh); - wh += CACHE_LINE_SIZE_IN_DOUBLEWORDS; - } while (--i); - - for (j = x * (CACHE_LINE_SIZE_IN_DOUBLEWORDS / 4); - j != 0; j--) { - *out64++ = v64; - *out64++ = v64; - *out64++ = v64; - *out64++ = v64; - } - } while (lines_left != 0); - - /* We processed all full lines above, so only this many - * words remain to be processed. - */ - n64 &= CACHE_LINE_SIZE_IN_DOUBLEWORDS - 1; - } - - /* Now handle any leftover values. */ - if (n64 != 0) { - do { - *out64 = v64; - out64++; - } while (--n64 != 0); - } - - return s; -} -EXPORT_SYMBOL(memset); diff --git a/arch/tile/lib/spinlock_32.c b/arch/tile/lib/spinlock_32.c deleted file mode 100644 index db9333f2447c..000000000000 --- a/arch/tile/lib/spinlock_32.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include - -#include "spinlock_common.h" - -void arch_spin_lock(arch_spinlock_t *lock) -{ - int my_ticket; - int iterations = 0; - int delta; - - while ((my_ticket = __insn_tns((void *)&lock->next_ticket)) & 1) - delay_backoff(iterations++); - - /* Increment the next ticket number, implicitly releasing tns lock. */ - lock->next_ticket = my_ticket + TICKET_QUANTUM; - - /* Wait until it's our turn. */ - while ((delta = my_ticket - lock->current_ticket) != 0) - relax((128 / CYCLES_PER_RELAX_LOOP) * delta); -} -EXPORT_SYMBOL(arch_spin_lock); - -int arch_spin_trylock(arch_spinlock_t *lock) -{ - /* - * Grab a ticket; no need to retry if it's busy, we'll just - * treat that the same as "locked", since someone else - * will lock it momentarily anyway. - */ - int my_ticket = __insn_tns((void *)&lock->next_ticket); - - if (my_ticket == lock->current_ticket) { - /* Not currently locked, so lock it by keeping this ticket. */ - lock->next_ticket = my_ticket + TICKET_QUANTUM; - /* Success! */ - return 1; - } - - if (!(my_ticket & 1)) { - /* Release next_ticket. */ - lock->next_ticket = my_ticket; - } - - return 0; -} -EXPORT_SYMBOL(arch_spin_trylock); - -/* - * The low byte is always reserved to be the marker for a "tns" operation - * since the low bit is set to "1" by a tns. The next seven bits are - * zeroes. The next byte holds the "next" writer value, i.e. the ticket - * available for the next task that wants to write. The third byte holds - * the current writer value, i.e. the writer who holds the current ticket. - * If current == next == 0, there are no interested writers. - */ -#define WR_NEXT_SHIFT _WR_NEXT_SHIFT -#define WR_CURR_SHIFT _WR_CURR_SHIFT -#define WR_WIDTH _WR_WIDTH -#define WR_MASK ((1 << WR_WIDTH) - 1) - -/* - * The last eight bits hold the active reader count. This has to be - * zero before a writer can start to write. - */ -#define RD_COUNT_SHIFT _RD_COUNT_SHIFT -#define RD_COUNT_WIDTH _RD_COUNT_WIDTH -#define RD_COUNT_MASK ((1 << RD_COUNT_WIDTH) - 1) - - -/* - * We can get the read lock if everything but the reader bits (which - * are in the high part of the word) is zero, i.e. no active or - * waiting writers, no tns. - * - * We guard the tns/store-back with an interrupt critical section to - * preserve the semantic that the same read lock can be acquired in an - * interrupt context. - */ -int arch_read_trylock(arch_rwlock_t *rwlock) -{ - u32 val; - __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1); - val = __insn_tns((int *)&rwlock->lock); - if (likely((val << _RD_COUNT_WIDTH) == 0)) { - val += 1 << RD_COUNT_SHIFT; - rwlock->lock = val; - __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0); - BUG_ON(val == 0); /* we don't expect wraparound */ - return 1; - } - if ((val & 1) == 0) - rwlock->lock = val; - __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0); - return 0; -} -EXPORT_SYMBOL(arch_read_trylock); - -/* - * Spin doing arch_read_trylock() until we acquire the lock. - * ISSUE: This approach can permanently starve readers. A reader who sees - * a writer could instead take a ticket lock (just like a writer would), - * and atomically enter read mode (with 1 reader) when it gets the ticket. - * This way both readers and writers would always make forward progress - * in a finite time. - */ -void arch_read_lock(arch_rwlock_t *rwlock) -{ - u32 iterations = 0; - while (unlikely(!arch_read_trylock(rwlock))) - delay_backoff(iterations++); -} -EXPORT_SYMBOL(arch_read_lock); - -void arch_read_unlock(arch_rwlock_t *rwlock) -{ - u32 val, iterations = 0; - - mb(); /* guarantee anything modified under the lock is visible */ - for (;;) { - __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 1); - val = __insn_tns((int *)&rwlock->lock); - if (likely((val & 1) == 0)) { - rwlock->lock = val - (1 << _RD_COUNT_SHIFT); - __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0); - break; - } - __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0); - delay_backoff(iterations++); - } -} -EXPORT_SYMBOL(arch_read_unlock); - -/* - * We don't need an interrupt critical section here (unlike for - * arch_read_lock) since we should never use a bare write lock where - * it could be interrupted by code that could try to re-acquire it. - */ -void arch_write_lock(arch_rwlock_t *rwlock) -{ - /* - * The trailing underscore on this variable (and curr_ below) - * reminds us that the high bits are garbage; we mask them out - * when we compare them. - */ - u32 my_ticket_; - u32 iterations = 0; - u32 val = __insn_tns((int *)&rwlock->lock); - - if (likely(val == 0)) { - rwlock->lock = 1 << _WR_NEXT_SHIFT; - return; - } - - /* - * Wait until there are no readers, then bump up the next - * field and capture the ticket value. - */ - for (;;) { - if (!(val & 1)) { - if ((val >> RD_COUNT_SHIFT) == 0) - break; - rwlock->lock = val; - } - delay_backoff(iterations++); - val = __insn_tns((int *)&rwlock->lock); - } - - /* Take out the next ticket and extract my ticket value. */ - rwlock->lock = __insn_addb(val, 1 << WR_NEXT_SHIFT); - my_ticket_ = val >> WR_NEXT_SHIFT; - - /* Wait until the "current" field matches our ticket. */ - for (;;) { - u32 curr_ = val >> WR_CURR_SHIFT; - u32 delta = ((my_ticket_ - curr_) & WR_MASK); - if (likely(delta == 0)) - break; - - /* Delay based on how many lock-holders are still out there. */ - relax((256 / CYCLES_PER_RELAX_LOOP) * delta); - - /* - * Get a non-tns value to check; we don't need to tns - * it ourselves. Since we're not tns'ing, we retry - * more rapidly to get a valid value. - */ - while ((val = rwlock->lock) & 1) - relax(4); - } -} -EXPORT_SYMBOL(arch_write_lock); - -int arch_write_trylock(arch_rwlock_t *rwlock) -{ - u32 val = __insn_tns((int *)&rwlock->lock); - - /* - * If a tns is in progress, or there's a waiting or active locker, - * or active readers, we can't take the lock, so give up. - */ - if (unlikely(val != 0)) { - if (!(val & 1)) - rwlock->lock = val; - return 0; - } - - /* Set the "next" field to mark it locked. */ - rwlock->lock = 1 << _WR_NEXT_SHIFT; - return 1; -} -EXPORT_SYMBOL(arch_write_trylock); - -void arch_write_unlock(arch_rwlock_t *rwlock) -{ - u32 val, eq, mask; - - mb(); /* guarantee anything modified under the lock is visible */ - val = __insn_tns((int *)&rwlock->lock); - if (likely(val == (1 << _WR_NEXT_SHIFT))) { - rwlock->lock = 0; - return; - } - while (unlikely(val & 1)) { - /* Limited backoff since we are the highest-priority task. */ - relax(4); - val = __insn_tns((int *)&rwlock->lock); - } - mask = 1 << WR_CURR_SHIFT; - val = __insn_addb(val, mask); - eq = __insn_seqb(val, val << (WR_CURR_SHIFT - WR_NEXT_SHIFT)); - val = __insn_mz(eq & mask, val); - rwlock->lock = val; -} -EXPORT_SYMBOL(arch_write_unlock); diff --git a/arch/tile/lib/spinlock_64.c b/arch/tile/lib/spinlock_64.c deleted file mode 100644 index de414c22892f..000000000000 --- a/arch/tile/lib/spinlock_64.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include - -#include "spinlock_common.h" - -/* - * Read the spinlock value without allocating in our cache and without - * causing an invalidation to another cpu with a copy of the cacheline. - * This is important when we are spinning waiting for the lock. - */ -static inline u32 arch_spin_read_noalloc(void *lock) -{ - return atomic_cmpxchg((atomic_t *)lock, -1, -1); -} - -/* - * Wait until the high bits (current) match my ticket. - * If we notice the overflow bit set on entry, we clear it. - */ -void arch_spin_lock_slow(arch_spinlock_t *lock, u32 my_ticket) -{ - if (unlikely(my_ticket & __ARCH_SPIN_NEXT_OVERFLOW)) { - __insn_fetchand4(&lock->lock, ~__ARCH_SPIN_NEXT_OVERFLOW); - my_ticket &= ~__ARCH_SPIN_NEXT_OVERFLOW; - } - - for (;;) { - u32 val = arch_spin_read_noalloc(lock); - u32 delta = my_ticket - arch_spin_current(val); - if (delta == 0) - return; - relax((128 / CYCLES_PER_RELAX_LOOP) * delta); - } -} -EXPORT_SYMBOL(arch_spin_lock_slow); - -/* - * Check the lock to see if it is plausible, and try to get it with cmpxchg(). - */ -int arch_spin_trylock(arch_spinlock_t *lock) -{ - u32 val = arch_spin_read_noalloc(lock); - if (unlikely(arch_spin_current(val) != arch_spin_next(val))) - return 0; - return cmpxchg(&lock->lock, val, (val + 1) & ~__ARCH_SPIN_NEXT_OVERFLOW) - == val; -} -EXPORT_SYMBOL(arch_spin_trylock); - - -/* - * If the read lock fails due to a writer, we retry periodically - * until the value is positive and we write our incremented reader count. - */ -void __read_lock_failed(arch_rwlock_t *rw) -{ - u32 val; - int iterations = 0; - do { - delay_backoff(iterations++); - val = __insn_fetchaddgez4(&rw->lock, 1); - } while (unlikely(arch_write_val_locked(val))); -} -EXPORT_SYMBOL(__read_lock_failed); - -/* - * If we failed because there were readers, clear the "writer" bit - * so we don't block additional readers. Otherwise, there was another - * writer anyway, so our "fetchor" made no difference. Then wait, - * issuing periodic fetchor instructions, till we get the lock. - */ -void __write_lock_failed(arch_rwlock_t *rw, u32 val) -{ - int iterations = 0; - do { - if (!arch_write_val_locked(val)) - val = __insn_fetchand4(&rw->lock, ~__WRITE_LOCK_BIT); - delay_backoff(iterations++); - val = __insn_fetchor4(&rw->lock, __WRITE_LOCK_BIT); - } while (val != 0); -} -EXPORT_SYMBOL(__write_lock_failed); diff --git a/arch/tile/lib/spinlock_common.h b/arch/tile/lib/spinlock_common.h deleted file mode 100644 index 6ac37509faca..000000000000 --- a/arch/tile/lib/spinlock_common.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * This file is included into spinlock_32.c or _64.c. - */ - -/* - * The mfspr in __spinlock_relax() is 5 or 6 cycles plus 2 for loop - * overhead. - */ -#ifdef __tilegx__ -#define CYCLES_PER_RELAX_LOOP 7 -#else -#define CYCLES_PER_RELAX_LOOP 8 -#endif - -/* - * Idle the core for CYCLES_PER_RELAX_LOOP * iterations cycles. - */ -static inline void -relax(int iterations) -{ - for (/*above*/; iterations > 0; iterations--) - __insn_mfspr(SPR_PASS); - barrier(); -} - -/* Perform bounded exponential backoff.*/ -static void delay_backoff(int iterations) -{ - u32 exponent, loops; - - /* - * 2^exponent is how many times we go around the loop, - * which takes 8 cycles. We want to start with a 16- to 31-cycle - * loop, so we need to go around minimum 2 = 2^1 times, so we - * bias the original value up by 1. - */ - exponent = iterations + 1; - - /* - * Don't allow exponent to exceed 7, so we have 128 loops, - * or 1,024 (to 2,047) cycles, as our maximum. - */ - if (exponent > 8) - exponent = 8; - - loops = 1 << exponent; - - /* Add a randomness factor so two cpus never get in lock step. */ - loops += __insn_crc32_32(stack_pointer, get_cycles_low()) & - (loops - 1); - - relax(loops); -} diff --git a/arch/tile/lib/strchr_32.c b/arch/tile/lib/strchr_32.c deleted file mode 100644 index 841fe6963019..000000000000 --- a/arch/tile/lib/strchr_32.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include - -char *strchr(const char *s, int c) -{ - int z, g; - - /* Get an aligned pointer. */ - const uintptr_t s_int = (uintptr_t) s; - const uint32_t *p = (const uint32_t *)(s_int & -4); - - /* Create four copies of the byte for which we are looking. */ - const uint32_t goal = 0x01010101 * (uint8_t) c; - - /* Read the first aligned word, but force bytes before the string to - * match neither zero nor goal (we make sure the high bit of each - * byte is 1, and the low 7 bits are all the opposite of the goal - * byte). - * - * Note that this shift count expression works because we know shift - * counts are taken mod 32. - */ - const uint32_t before_mask = (1 << (s_int << 3)) - 1; - uint32_t v = (*p | before_mask) ^ (goal & __insn_shrib(before_mask, 1)); - - uint32_t zero_matches, goal_matches; - while (1) { - /* Look for a terminating '\0'. */ - zero_matches = __insn_seqb(v, 0); - - /* Look for the goal byte. */ - goal_matches = __insn_seqb(v, goal); - - if (__builtin_expect(zero_matches | goal_matches, 0)) - break; - - v = *++p; - } - - z = __insn_ctz(zero_matches); - g = __insn_ctz(goal_matches); - - /* If we found c before '\0' we got a match. Note that if c == '\0' - * then g == z, and we correctly return the address of the '\0' - * rather than NULL. - */ - return (g <= z) ? ((char *)p) + (g >> 3) : NULL; -} -EXPORT_SYMBOL(strchr); diff --git a/arch/tile/lib/strchr_64.c b/arch/tile/lib/strchr_64.c deleted file mode 100644 index fe6e31c06f8d..000000000000 --- a/arch/tile/lib/strchr_64.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include "string-endian.h" - -char *strchr(const char *s, int c) -{ - int z, g; - - /* Get an aligned pointer. */ - const uintptr_t s_int = (uintptr_t) s; - const uint64_t *p = (const uint64_t *)(s_int & -8); - - /* Create eight copies of the byte for which we are looking. */ - const uint64_t goal = copy_byte(c); - - /* Read the first aligned word, but force bytes before the string to - * match neither zero nor goal (we make sure the high bit of each - * byte is 1, and the low 7 bits are all the opposite of the goal - * byte). - */ - const uint64_t before_mask = MASK(s_int); - uint64_t v = (*p | before_mask) ^ (goal & __insn_v1shrui(before_mask, 1)); - - uint64_t zero_matches, goal_matches; - while (1) { - /* Look for a terminating '\0'. */ - zero_matches = __insn_v1cmpeqi(v, 0); - - /* Look for the goal byte. */ - goal_matches = __insn_v1cmpeq(v, goal); - - if (__builtin_expect((zero_matches | goal_matches) != 0, 0)) - break; - - v = *++p; - } - - z = CFZ(zero_matches); - g = CFZ(goal_matches); - - /* If we found c before '\0' we got a match. Note that if c == '\0' - * then g == z, and we correctly return the address of the '\0' - * rather than NULL. - */ - return (g <= z) ? ((char *)p) + (g >> 3) : NULL; -} -EXPORT_SYMBOL(strchr); diff --git a/arch/tile/lib/string-endian.h b/arch/tile/lib/string-endian.h deleted file mode 100644 index 2e49cbfe9371..000000000000 --- a/arch/tile/lib/string-endian.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Provide a mask based on the pointer alignment that - * sets up non-zero bytes before the beginning of the string. - * The MASK expression works because shift counts are taken mod 64. - * Also, specify how to count "first" and "last" bits - * when the bits have been read as a word. - */ - -#include - -#ifdef __LITTLE_ENDIAN -#define MASK(x) (__insn_shl(1ULL, (x << 3)) - 1) -#define NULMASK(x) ((2ULL << x) - 1) -#define CFZ(x) __insn_ctz(x) -#define REVCZ(x) __insn_clz(x) -#else -#define MASK(x) (__insn_shl(-2LL, ((-x << 3) - 1))) -#define NULMASK(x) (-2LL << (63 - x)) -#define CFZ(x) __insn_clz(x) -#define REVCZ(x) __insn_ctz(x) -#endif - -/* - * Create eight copies of the byte in a uint64_t. Byte Shuffle uses - * the bytes of srcB as the index into the dest vector to select a - * byte. With all indices of zero, the first byte is copied into all - * the other bytes. - */ -static inline uint64_t copy_byte(uint8_t byte) -{ - return __insn_shufflebytes(byte, 0, 0); -} diff --git a/arch/tile/lib/strlen_32.c b/arch/tile/lib/strlen_32.c deleted file mode 100644 index f26f88e11e4a..000000000000 --- a/arch/tile/lib/strlen_32.c +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include - -size_t strlen(const char *s) -{ - /* Get an aligned pointer. */ - const uintptr_t s_int = (uintptr_t) s; - const uint32_t *p = (const uint32_t *)(s_int & -4); - - /* Read the first word, but force bytes before the string to be nonzero. - * This expression works because we know shift counts are taken mod 32. - */ - uint32_t v = *p | ((1 << (s_int << 3)) - 1); - - uint32_t bits; - while ((bits = __insn_seqb(v, 0)) == 0) - v = *++p; - - return ((const char *)p) + (__insn_ctz(bits) >> 3) - s; -} -EXPORT_SYMBOL(strlen); diff --git a/arch/tile/lib/strlen_64.c b/arch/tile/lib/strlen_64.c deleted file mode 100644 index 9583fc3361fa..000000000000 --- a/arch/tile/lib/strlen_64.c +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include "string-endian.h" - -size_t strlen(const char *s) -{ - /* Get an aligned pointer. */ - const uintptr_t s_int = (uintptr_t) s; - const uint64_t *p = (const uint64_t *)(s_int & -8); - - /* Read and MASK the first word. */ - uint64_t v = *p | MASK(s_int); - - uint64_t bits; - while ((bits = __insn_v1cmpeqi(v, 0)) == 0) - v = *++p; - - return ((const char *)p) + (CFZ(bits) >> 3) - s; -} -EXPORT_SYMBOL(strlen); diff --git a/arch/tile/lib/strnlen_32.c b/arch/tile/lib/strnlen_32.c deleted file mode 100644 index 1434141d9e01..000000000000 --- a/arch/tile/lib/strnlen_32.c +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include - -size_t strnlen(const char *s, size_t count) -{ - /* Get an aligned pointer. */ - const uintptr_t s_int = (uintptr_t) s; - const uint32_t *p = (const uint32_t *)(s_int & -4); - size_t bytes_read = sizeof(*p) - (s_int & (sizeof(*p) - 1)); - size_t len; - uint32_t v, bits; - - /* Avoid page fault risk by not reading any bytes when count is 0. */ - if (count == 0) - return 0; - - /* Read first word, but force bytes before the string to be nonzero. */ - v = *p | ((1 << ((s_int << 3) & 31)) - 1); - - while ((bits = __insn_seqb(v, 0)) == 0) { - if (bytes_read >= count) { - /* Read COUNT bytes and didn't find the terminator. */ - return count; - } - v = *++p; - bytes_read += sizeof(v); - } - - len = ((const char *) p) + (__insn_ctz(bits) >> 3) - s; - return (len < count ? len : count); -} -EXPORT_SYMBOL(strnlen); diff --git a/arch/tile/lib/strnlen_64.c b/arch/tile/lib/strnlen_64.c deleted file mode 100644 index 2e8de6a5136f..000000000000 --- a/arch/tile/lib/strnlen_64.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2013 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include "string-endian.h" - -size_t strnlen(const char *s, size_t count) -{ - /* Get an aligned pointer. */ - const uintptr_t s_int = (uintptr_t) s; - const uint64_t *p = (const uint64_t *)(s_int & -8); - size_t bytes_read = sizeof(*p) - (s_int & (sizeof(*p) - 1)); - size_t len; - uint64_t v, bits; - - /* Avoid page fault risk by not reading any bytes when count is 0. */ - if (count == 0) - return 0; - - /* Read and MASK the first word. */ - v = *p | MASK(s_int); - - while ((bits = __insn_v1cmpeqi(v, 0)) == 0) { - if (bytes_read >= count) { - /* Read COUNT bytes and didn't find the terminator. */ - return count; - } - v = *++p; - bytes_read += sizeof(v); - } - - len = ((const char *) p) + (CFZ(bits) >> 3) - s; - return (len < count ? len : count); -} -EXPORT_SYMBOL(strnlen); diff --git a/arch/tile/lib/uaccess.c b/arch/tile/lib/uaccess.c deleted file mode 100644 index 030abe3ee4f1..000000000000 --- a/arch/tile/lib/uaccess.c +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include - -int __range_ok(unsigned long addr, unsigned long size) -{ - unsigned long limit = current_thread_info()->addr_limit.seg; - return !((addr < limit && size <= limit - addr) || - is_arch_mappable_range(addr, size)); -} -EXPORT_SYMBOL(__range_ok); diff --git a/arch/tile/lib/usercopy_32.S b/arch/tile/lib/usercopy_32.S deleted file mode 100644 index db93ad5fae25..000000000000 --- a/arch/tile/lib/usercopy_32.S +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include - -/* Access user memory, but use MMU to avoid propagating kernel exceptions. */ - -/* - * clear_user_asm takes the user target address in r0 and the - * number of bytes to zero in r1. - * It returns the number of uncopiable bytes (hopefully zero) in r0. - * Note that we don't use a separate .fixup section here since we fall - * through into the "fixup" code as the last straight-line bundle anyway. - */ -STD_ENTRY(clear_user_asm) - { bz r1, 2f; or r2, r0, r1 } - andi r2, r2, 3 - bzt r2, .Lclear_aligned_user_asm -1: { sb r0, zero; addi r0, r0, 1; addi r1, r1, -1 } - bnzt r1, 1b -2: { move r0, r1; jrp lr } - .pushsection __ex_table,"a" - .align 4 - .word 1b, 2b - .popsection - -.Lclear_aligned_user_asm: -1: { sw r0, zero; addi r0, r0, 4; addi r1, r1, -4 } - bnzt r1, 1b -2: { move r0, r1; jrp lr } - STD_ENDPROC(clear_user_asm) - .pushsection __ex_table,"a" - .align 4 - .word 1b, 2b - .popsection - -/* - * flush_user_asm takes the user target address in r0 and the - * number of bytes to flush in r1. - * It returns the number of unflushable bytes (hopefully zero) in r0. - */ -STD_ENTRY(flush_user_asm) - bz r1, 2f - { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } - { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } - { and r0, r0, r2; and r1, r1, r2 } - { sub r1, r1, r0 } -1: { flush r0; addi r1, r1, -CHIP_FLUSH_STRIDE() } - { addi r0, r0, CHIP_FLUSH_STRIDE(); bnzt r1, 1b } -2: { move r0, r1; jrp lr } - STD_ENDPROC(flush_user_asm) - .pushsection __ex_table,"a" - .align 4 - .word 1b, 2b - .popsection - -/* - * finv_user_asm takes the user target address in r0 and the - * number of bytes to flush-invalidate in r1. - * It returns the number of not finv'able bytes (hopefully zero) in r0. - */ -STD_ENTRY(finv_user_asm) - bz r1, 2f - { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } - { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } - { and r0, r0, r2; and r1, r1, r2 } - { sub r1, r1, r0 } -1: { finv r0; addi r1, r1, -CHIP_FINV_STRIDE() } - { addi r0, r0, CHIP_FINV_STRIDE(); bnzt r1, 1b } -2: { move r0, r1; jrp lr } - STD_ENDPROC(finv_user_asm) - .pushsection __ex_table,"a" - .align 4 - .word 1b, 2b - .popsection diff --git a/arch/tile/lib/usercopy_64.S b/arch/tile/lib/usercopy_64.S deleted file mode 100644 index 9322dc551e91..000000000000 --- a/arch/tile/lib/usercopy_64.S +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include - -/* Access user memory, but use MMU to avoid propagating kernel exceptions. */ - -/* - * clear_user_asm takes the user target address in r0 and the - * number of bytes to zero in r1. - * It returns the number of uncopiable bytes (hopefully zero) in r0. - * Note that we don't use a separate .fixup section here since we fall - * through into the "fixup" code as the last straight-line bundle anyway. - */ -STD_ENTRY(clear_user_asm) - { beqz r1, 2f; or r2, r0, r1 } - andi r2, r2, 7 - beqzt r2, .Lclear_aligned_user_asm -1: { st1 r0, zero; addi r0, r0, 1; addi r1, r1, -1 } - bnezt r1, 1b -2: { move r0, r1; jrp lr } - .pushsection __ex_table,"a" - .align 8 - .quad 1b, 2b - .popsection - -.Lclear_aligned_user_asm: -1: { st r0, zero; addi r0, r0, 8; addi r1, r1, -8 } - bnezt r1, 1b -2: { move r0, r1; jrp lr } - STD_ENDPROC(clear_user_asm) - .pushsection __ex_table,"a" - .align 8 - .quad 1b, 2b - .popsection - -/* - * flush_user_asm takes the user target address in r0 and the - * number of bytes to flush in r1. - * It returns the number of unflushable bytes (hopefully zero) in r0. - */ -STD_ENTRY(flush_user_asm) - beqz r1, 2f - { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } - { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } - { and r0, r0, r2; and r1, r1, r2 } - { sub r1, r1, r0 } -1: { flush r0; addi r1, r1, -CHIP_FLUSH_STRIDE() } - { addi r0, r0, CHIP_FLUSH_STRIDE(); bnezt r1, 1b } -2: { move r0, r1; jrp lr } - STD_ENDPROC(flush_user_asm) - .pushsection __ex_table,"a" - .align 8 - .quad 1b, 2b - .popsection - -/* - * finv_user_asm takes the user target address in r0 and the - * number of bytes to flush-invalidate in r1. - * It returns the number of not finv'able bytes (hopefully zero) in r0. - */ -STD_ENTRY(finv_user_asm) - beqz r1, 2f - { movei r2, L2_CACHE_BYTES; add r1, r0, r1 } - { sub r2, zero, r2; addi r1, r1, L2_CACHE_BYTES-1 } - { and r0, r0, r2; and r1, r1, r2 } - { sub r1, r1, r0 } -1: { finv r0; addi r1, r1, -CHIP_FINV_STRIDE() } - { addi r0, r0, CHIP_FINV_STRIDE(); bnezt r1, 1b } -2: { move r0, r1; jrp lr } - STD_ENDPROC(finv_user_asm) - .pushsection __ex_table,"a" - .align 8 - .quad 1b, 2b - .popsection diff --git a/arch/tile/mm/Makefile b/arch/tile/mm/Makefile deleted file mode 100644 index e252aeddc17d..000000000000 --- a/arch/tile/mm/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for the linux tile-specific parts of the memory manager. -# - -obj-y := init.o pgtable.o fault.o extable.o elf.o \ - mmap.o homecache.o migrate_$(BITS).o - -obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o -obj-$(CONFIG_HIGHMEM) += highmem.o diff --git a/arch/tile/mm/elf.c b/arch/tile/mm/elf.c deleted file mode 100644 index 889901824400..000000000000 --- a/arch/tile/mm/elf.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Notify a running simulator, if any, that an exec just occurred. */ -static void sim_notify_exec(const char *binary_name) -{ - unsigned char c; - do { - c = *binary_name++; - __insn_mtspr(SPR_SIM_CONTROL, - (SIM_CONTROL_OS_EXEC - | (c << _SIM_CONTROL_OPERATOR_BITS))); - - } while (c); -} - -static int notify_exec(struct mm_struct *mm) -{ - int ret = 0; - char *buf, *path; - struct vm_area_struct *vma; - struct file *exe_file; - - if (!sim_is_simulator()) - return 1; - - buf = (char *) __get_free_page(GFP_KERNEL); - if (buf == NULL) - return 0; - - exe_file = get_mm_exe_file(mm); - if (exe_file == NULL) - goto done_free; - - path = file_path(exe_file, buf, PAGE_SIZE); - if (IS_ERR(path)) - goto done_put; - - down_read(&mm->mmap_sem); - for (vma = current->mm->mmap; ; vma = vma->vm_next) { - if (vma == NULL) { - up_read(&mm->mmap_sem); - goto done_put; - } - if (vma->vm_file == exe_file) - break; - } - - /* - * Notify simulator of an ET_DYN object so we know the load address. - * The somewhat cryptic overuse of SIM_CONTROL_DLOPEN allows us - * to be backward-compatible with older simulator releases. - */ - if (vma->vm_start == (ELF_ET_DYN_BASE & PAGE_MASK)) { - char buf[64]; - int i; - - snprintf(buf, sizeof(buf), "0x%lx:@", vma->vm_start); - for (i = 0; ; ++i) { - char c = buf[i]; - __insn_mtspr(SPR_SIM_CONTROL, - (SIM_CONTROL_DLOPEN - | (c << _SIM_CONTROL_OPERATOR_BITS))); - if (c == '\0') { - ret = 1; /* success */ - break; - } - } - } - up_read(&mm->mmap_sem); - - sim_notify_exec(path); -done_put: - fput(exe_file); -done_free: - free_page((unsigned long)buf); - return ret; -} - -/* Notify a running simulator, if any, that we loaded an interpreter. */ -static void sim_notify_interp(unsigned long load_addr) -{ - size_t i; - for (i = 0; i < sizeof(load_addr); i++) { - unsigned char c = load_addr >> (i * 8); - __insn_mtspr(SPR_SIM_CONTROL, - (SIM_CONTROL_OS_INTERP - | (c << _SIM_CONTROL_OPERATOR_BITS))); - } -} - - -int arch_setup_additional_pages(struct linux_binprm *bprm, - int executable_stack) -{ - struct mm_struct *mm = current->mm; - int retval = 0; - - /* - * Notify the simulator that an exec just occurred. - * If we can't find the filename of the mapping, just use - * whatever was passed as the linux_binprm filename. - */ - if (!notify_exec(mm)) - sim_notify_exec(bprm->filename); - - down_write(&mm->mmap_sem); - - retval = setup_vdso_pages(); - -#ifndef __tilegx__ - /* - * Set up a user-interrupt mapping here; the user can't - * create one themselves since it is above TASK_SIZE. - * We make it unwritable by default, so the model for adding - * interrupt vectors always involves an mprotect. - */ - if (!retval) { - unsigned long addr = MEM_USER_INTRPT; - addr = mmap_region(NULL, addr, INTRPT_SIZE, - VM_READ|VM_EXEC| - VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 0, NULL); - if (addr > (unsigned long) -PAGE_SIZE) - retval = (int) addr; - } -#endif - - up_write(&mm->mmap_sem); - - return retval; -} - - -void elf_plat_init(struct pt_regs *regs, unsigned long load_addr) -{ - /* Zero all registers. */ - memset(regs, 0, sizeof(*regs)); - - /* Report the interpreter's load address. */ - sim_notify_interp(load_addr); -} diff --git a/arch/tile/mm/extable.c b/arch/tile/mm/extable.c deleted file mode 100644 index aeaf20c7aaa4..000000000000 --- a/arch/tile/mm/extable.c +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include - -int fixup_exception(struct pt_regs *regs) -{ - const struct exception_table_entry *fixup; - - fixup = search_exception_tables(regs->pc); - if (fixup) { - regs->pc = fixup->fixup; - return 1; - } - - return 0; -} diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c deleted file mode 100644 index f58fa06a2214..000000000000 --- a/arch/tile/mm/fault.c +++ /dev/null @@ -1,924 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * From i386 code copyright (C) 1995 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* For unblank_screen() */ -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -static noinline void force_sig_info_fault(const char *type, int si_signo, - int si_code, unsigned long address, - int fault_num, - struct task_struct *tsk, - struct pt_regs *regs) -{ - siginfo_t info; - - if (unlikely(tsk->pid < 2)) { - panic("Signal %d (code %d) at %#lx sent to %s!", - si_signo, si_code & 0xffff, address, - is_idle_task(tsk) ? "the idle task" : "init"); - } - - info.si_signo = si_signo; - info.si_errno = 0; - info.si_code = si_code; - info.si_addr = (void __user *)address; - info.si_trapno = fault_num; - trace_unhandled_signal(type, regs, address, si_signo); - force_sig_info(si_signo, &info, tsk); -} - -#ifndef __tilegx__ -/* - * Synthesize the fault a PL0 process would get by doing a word-load of - * an unaligned address or a high kernel address. - */ -SYSCALL_DEFINE1(cmpxchg_badaddr, unsigned long, address) -{ - struct pt_regs *regs = current_pt_regs(); - - if (address >= PAGE_OFFSET) - force_sig_info_fault("atomic segfault", SIGSEGV, SEGV_MAPERR, - address, INT_DTLB_MISS, current, regs); - else - force_sig_info_fault("atomic alignment fault", SIGBUS, - BUS_ADRALN, address, - INT_UNALIGN_DATA, current, regs); - - /* - * Adjust pc to point at the actual instruction, which is unusual - * for syscalls normally, but is appropriate when we are claiming - * that a syscall swint1 caused a page fault or bus error. - */ - regs->pc -= 8; - - /* - * Mark this as a caller-save interrupt, like a normal page fault, - * so that when we go through the signal handler path we will - * properly restore r0, r1, and r2 for the signal handler arguments. - */ - regs->flags |= PT_FLAGS_CALLER_SAVES; - - return 0; -} -#endif - -static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) -{ - unsigned index = pgd_index(address); - pgd_t *pgd_k; - pud_t *pud, *pud_k; - pmd_t *pmd, *pmd_k; - - pgd += index; - pgd_k = init_mm.pgd + index; - - if (!pgd_present(*pgd_k)) - return NULL; - - pud = pud_offset(pgd, address); - pud_k = pud_offset(pgd_k, address); - if (!pud_present(*pud_k)) - return NULL; - - pmd = pmd_offset(pud, address); - pmd_k = pmd_offset(pud_k, address); - if (!pmd_present(*pmd_k)) - return NULL; - if (!pmd_present(*pmd)) - set_pmd(pmd, *pmd_k); - else - BUG_ON(pmd_ptfn(*pmd) != pmd_ptfn(*pmd_k)); - return pmd_k; -} - -/* - * Handle a fault on the vmalloc area. - */ -static inline int vmalloc_fault(pgd_t *pgd, unsigned long address) -{ - pmd_t *pmd_k; - pte_t *pte_k; - - /* Make sure we are in vmalloc area */ - if (!(address >= VMALLOC_START && address < VMALLOC_END)) - return -1; - - /* - * Synchronize this task's top level page-table - * with the 'reference' page table. - */ - pmd_k = vmalloc_sync_one(pgd, address); - if (!pmd_k) - return -1; - pte_k = pte_offset_kernel(pmd_k, address); - if (!pte_present(*pte_k)) - return -1; - return 0; -} - -/* Wait until this PTE has completed migration. */ -static void wait_for_migration(pte_t *pte) -{ - if (pte_migrating(*pte)) { - /* - * Wait until the migrater fixes up this pte. - * We scale the loop count by the clock rate so we'll wait for - * a few seconds here. - */ - int retries = 0; - int bound = get_clock_rate(); - while (pte_migrating(*pte)) { - barrier(); - if (++retries > bound) - panic("Hit migrating PTE (%#llx) and page PFN %#lx still migrating", - pte->val, pte_pfn(*pte)); - } - } -} - -/* - * It's not generally safe to use "current" to get the page table pointer, - * since we might be running an oprofile interrupt in the middle of a - * task switch. - */ -static pgd_t *get_current_pgd(void) -{ - HV_Context ctx = hv_inquire_context(); - unsigned long pgd_pfn = ctx.page_table >> PAGE_SHIFT; - struct page *pgd_page = pfn_to_page(pgd_pfn); - BUG_ON(PageHighMem(pgd_page)); - return (pgd_t *) __va(ctx.page_table); -} - -/* - * We can receive a page fault from a migrating PTE at any time. - * Handle it by just waiting until the fault resolves. - * - * It's also possible to get a migrating kernel PTE that resolves - * itself during the downcall from hypervisor to Linux. We just check - * here to see if the PTE seems valid, and if so we retry it. - * - * NOTE! We MUST NOT take any locks for this case. We may be in an - * interrupt or a critical region, and must do as little as possible. - * Similarly, we can't use atomic ops here, since we may be handling a - * fault caused by an atomic op access. - * - * If we find a migrating PTE while we're in an NMI context, and we're - * at a PC that has a registered exception handler, we don't wait, - * since this thread may (e.g.) have been interrupted while migrating - * its own stack, which would then cause us to self-deadlock. - */ -static int handle_migrating_pte(pgd_t *pgd, int fault_num, - unsigned long address, unsigned long pc, - int is_kernel_mode, int write) -{ - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - pte_t pteval; - - if (pgd_addr_invalid(address)) - return 0; - - pgd += pgd_index(address); - pud = pud_offset(pgd, address); - if (!pud || !pud_present(*pud)) - return 0; - pmd = pmd_offset(pud, address); - if (!pmd || !pmd_present(*pmd)) - return 0; - pte = pmd_huge_page(*pmd) ? ((pte_t *)pmd) : - pte_offset_kernel(pmd, address); - pteval = *pte; - if (pte_migrating(pteval)) { - if (in_nmi() && search_exception_tables(pc)) - return 0; - wait_for_migration(pte); - return 1; - } - - if (!is_kernel_mode || !pte_present(pteval)) - return 0; - if (fault_num == INT_ITLB_MISS) { - if (pte_exec(pteval)) - return 1; - } else if (write) { - if (pte_write(pteval)) - return 1; - } else { - if (pte_read(pteval)) - return 1; - } - - return 0; -} - -/* - * This routine is responsible for faulting in user pages. - * It passes the work off to one of the appropriate routines. - * It returns true if the fault was successfully handled. - */ -static int handle_page_fault(struct pt_regs *regs, - int fault_num, - int is_page_fault, - unsigned long address, - int write) -{ - struct task_struct *tsk; - struct mm_struct *mm; - struct vm_area_struct *vma; - unsigned long stack_offset; - int fault; - int si_code; - int is_kernel_mode; - pgd_t *pgd; - unsigned int flags; - - /* on TILE, protection faults are always writes */ - if (!is_page_fault) - write = 1; - - flags = FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE; - - is_kernel_mode = !user_mode(regs); - - tsk = validate_current(); - - /* - * Check to see if we might be overwriting the stack, and bail - * out if so. The page fault code is a relatively likely - * place to get trapped in an infinite regress, and once we - * overwrite the whole stack, it becomes very hard to recover. - */ - stack_offset = stack_pointer & (THREAD_SIZE-1); - if (stack_offset < THREAD_SIZE / 8) { - pr_alert("Potential stack overrun: sp %#lx\n", stack_pointer); - show_regs(regs); - pr_alert("Killing current process %d/%s\n", - tsk->pid, tsk->comm); - do_group_exit(SIGKILL); - } - - /* - * Early on, we need to check for migrating PTE entries; - * see homecache.c. If we find a migrating PTE, we wait until - * the backing page claims to be done migrating, then we proceed. - * For kernel PTEs, we rewrite the PTE and return and retry. - * Otherwise, we treat the fault like a normal "no PTE" fault, - * rather than trying to patch up the existing PTE. - */ - pgd = get_current_pgd(); - if (handle_migrating_pte(pgd, fault_num, address, regs->pc, - is_kernel_mode, write)) - return 1; - - si_code = SEGV_MAPERR; - - /* - * We fault-in kernel-space virtual memory on-demand. The - * 'reference' page table is init_mm.pgd. - * - * NOTE! We MUST NOT take any locks for this case. We may - * be in an interrupt or a critical region, and should - * only copy the information from the master page table, - * nothing more. - * - * This verifies that the fault happens in kernel space - * and that the fault was not a protection fault. - */ - if (unlikely(address >= TASK_SIZE && - !is_arch_mappable_range(address, 0))) { - if (is_kernel_mode && is_page_fault && - vmalloc_fault(pgd, address) >= 0) - return 1; - /* - * Don't take the mm semaphore here. If we fixup a prefetch - * fault we could otherwise deadlock. - */ - mm = NULL; /* happy compiler */ - vma = NULL; - goto bad_area_nosemaphore; - } - - /* - * If we're trying to touch user-space addresses, we must - * be either at PL0, or else with interrupts enabled in the - * kernel, so either way we can re-enable interrupts here - * unless we are doing atomic access to user space with - * interrupts disabled. - */ - if (!(regs->flags & PT_FLAGS_DISABLE_IRQ)) - local_irq_enable(); - - mm = tsk->mm; - - /* - * If we're in an interrupt, have no user context or are running in an - * region with pagefaults disabled then we must not take the fault. - */ - if (pagefault_disabled() || !mm) { - vma = NULL; /* happy compiler */ - goto bad_area_nosemaphore; - } - - if (!is_kernel_mode) - flags |= FAULT_FLAG_USER; - - /* - * When running in the kernel we expect faults to occur only to - * addresses in user space. All other faults represent errors in the - * kernel and should generate an OOPS. Unfortunately, in the case of an - * erroneous fault occurring in a code path which already holds mmap_sem - * we will deadlock attempting to validate the fault against the - * address space. Luckily the kernel only validly references user - * space from well defined areas of code, which are listed in the - * exceptions table. - * - * As the vast majority of faults will be valid we will only perform - * the source reference check when there is a possibility of a deadlock. - * Attempt to lock the address space, if we cannot we then validate the - * source. If this is invalid we can skip the address space check, - * thus avoiding the deadlock. - */ - if (!down_read_trylock(&mm->mmap_sem)) { - if (is_kernel_mode && - !search_exception_tables(regs->pc)) { - vma = NULL; /* happy compiler */ - goto bad_area_nosemaphore; - } - -retry: - down_read(&mm->mmap_sem); - } - - vma = find_vma(mm, address); - if (!vma) - goto bad_area; - if (vma->vm_start <= address) - goto good_area; - if (!(vma->vm_flags & VM_GROWSDOWN)) - goto bad_area; - if (regs->sp < PAGE_OFFSET) { - /* - * accessing the stack below sp is always a bug. - */ - if (address < regs->sp) - goto bad_area; - } - if (expand_stack(vma, address)) - goto bad_area; - -/* - * Ok, we have a good vm_area for this memory access, so - * we can handle it.. - */ -good_area: - si_code = SEGV_ACCERR; - if (fault_num == INT_ITLB_MISS) { - if (!(vma->vm_flags & VM_EXEC)) - goto bad_area; - } else if (write) { -#ifdef TEST_VERIFY_AREA - if (!is_page_fault && regs->cs == KERNEL_CS) - pr_err("WP fault at " REGFMT "\n", regs->eip); -#endif - if (!(vma->vm_flags & VM_WRITE)) - goto bad_area; - flags |= FAULT_FLAG_WRITE; - } else { - if (!is_page_fault || !(vma->vm_flags & VM_READ)) - goto bad_area; - } - - /* - * If for any reason at all we couldn't handle the fault, - * make sure we exit gracefully rather than endlessly redo - * the fault. - */ - fault = handle_mm_fault(vma, address, flags); - - if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current)) - return 0; - - if (unlikely(fault & VM_FAULT_ERROR)) { - if (fault & VM_FAULT_OOM) - goto out_of_memory; - else if (fault & VM_FAULT_SIGSEGV) - goto bad_area; - else if (fault & VM_FAULT_SIGBUS) - goto do_sigbus; - BUG(); - } - if (flags & FAULT_FLAG_ALLOW_RETRY) { - if (fault & VM_FAULT_MAJOR) - tsk->maj_flt++; - else - tsk->min_flt++; - if (fault & VM_FAULT_RETRY) { - flags &= ~FAULT_FLAG_ALLOW_RETRY; - flags |= FAULT_FLAG_TRIED; - - /* - * No need to up_read(&mm->mmap_sem) as we would - * have already released it in __lock_page_or_retry - * in mm/filemap.c. - */ - goto retry; - } - } - -#if CHIP_HAS_TILE_DMA() - /* If this was a DMA TLB fault, restart the DMA engine. */ - switch (fault_num) { - case INT_DMATLB_MISS: - case INT_DMATLB_MISS_DWNCL: - case INT_DMATLB_ACCESS: - case INT_DMATLB_ACCESS_DWNCL: - __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__REQUEST_MASK); - break; - } -#endif - - up_read(&mm->mmap_sem); - return 1; - -/* - * Something tried to access memory that isn't in our memory map.. - * Fix it, but check if it's kernel or user first.. - */ -bad_area: - up_read(&mm->mmap_sem); - -bad_area_nosemaphore: - /* User mode accesses just cause a SIGSEGV */ - if (!is_kernel_mode) { - /* - * It's possible to have interrupts off here. - */ - local_irq_enable(); - - force_sig_info_fault("segfault", SIGSEGV, si_code, address, - fault_num, tsk, regs); - return 0; - } - -no_context: - /* Are we prepared to handle this kernel fault? */ - if (fixup_exception(regs)) - return 0; - -/* - * Oops. The kernel tried to access some bad page. We'll have to - * terminate things with extreme prejudice. - */ - - bust_spinlocks(1); - - /* FIXME: no lookup_address() yet */ -#ifdef SUPPORT_LOOKUP_ADDRESS - if (fault_num == INT_ITLB_MISS) { - pte_t *pte = lookup_address(address); - - if (pte && pte_present(*pte) && !pte_exec_kernel(*pte)) - pr_crit("kernel tried to execute non-executable page - exploit attempt? (uid: %d)\n", - current->uid); - } -#endif - if (address < PAGE_SIZE) - pr_alert("Unable to handle kernel NULL pointer dereference\n"); - else - pr_alert("Unable to handle kernel paging request\n"); - pr_alert(" at virtual address " REGFMT ", pc " REGFMT "\n", - address, regs->pc); - - show_regs(regs); - - if (unlikely(tsk->pid < 2)) { - panic("Kernel page fault running %s!", - is_idle_task(tsk) ? "the idle task" : "init"); - } - - /* - * More FIXME: we should probably copy the i386 here and - * implement a generic die() routine. Not today. - */ -#ifdef SUPPORT_DIE - die("Oops", regs); -#endif - bust_spinlocks(1); - - do_group_exit(SIGKILL); - -/* - * We ran out of memory, or some other thing happened to us that made - * us unable to handle the page fault gracefully. - */ -out_of_memory: - up_read(&mm->mmap_sem); - if (is_kernel_mode) - goto no_context; - pagefault_out_of_memory(); - return 0; - -do_sigbus: - up_read(&mm->mmap_sem); - - /* Kernel mode? Handle exceptions or die */ - if (is_kernel_mode) - goto no_context; - - force_sig_info_fault("bus error", SIGBUS, BUS_ADRERR, address, - fault_num, tsk, regs); - return 0; -} - -#ifndef __tilegx__ - -/* We must release ICS before panicking or we won't get anywhere. */ -#define ics_panic(fmt, ...) \ -do { \ - __insn_mtspr(SPR_INTERRUPT_CRITICAL_SECTION, 0); \ - panic(fmt, ##__VA_ARGS__); \ -} while (0) - -/* - * When we take an ITLB or DTLB fault or access violation in the - * supervisor while the critical section bit is set, the hypervisor is - * reluctant to write new values into the EX_CONTEXT_K_x registers, - * since that might indicate we have not yet squirreled the SPR - * contents away and can thus safely take a recursive interrupt. - * Accordingly, the hypervisor passes us the PC via SYSTEM_SAVE_K_2. - * - * Note that this routine is called before homecache_tlb_defer_enter(), - * which means that we can properly unlock any atomics that might - * be used there (good), but also means we must be very sensitive - * to not touch any data structures that might be located in memory - * that could migrate, as we could be entering the kernel on a dataplane - * cpu that has been deferring kernel TLB updates. This means, for - * example, that we can't migrate init_mm or its pgd. - */ -struct intvec_state do_page_fault_ics(struct pt_regs *regs, int fault_num, - unsigned long address, - unsigned long info) -{ - unsigned long pc = info & ~1; - int write = info & 1; - pgd_t *pgd = get_current_pgd(); - - /* Retval is 1 at first since we will handle the fault fully. */ - struct intvec_state state = { - do_page_fault, fault_num, address, write, 1 - }; - - /* Validate that we are plausibly in the right routine. */ - if ((pc & 0x7) != 0 || pc < PAGE_OFFSET || - (fault_num != INT_DTLB_MISS && - fault_num != INT_DTLB_ACCESS)) { - unsigned long old_pc = regs->pc; - regs->pc = pc; - ics_panic("Bad ICS page fault args: old PC %#lx, fault %d/%d at %#lx", - old_pc, fault_num, write, address); - } - - /* We might be faulting on a vmalloc page, so check that first. */ - if (fault_num != INT_DTLB_ACCESS && vmalloc_fault(pgd, address) >= 0) - return state; - - /* - * If we faulted with ICS set in sys_cmpxchg, we are providing - * a user syscall service that should generate a signal on - * fault. We didn't set up a kernel stack on initial entry to - * sys_cmpxchg, but instead had one set up by the fault, which - * (because sys_cmpxchg never releases ICS) came to us via the - * SYSTEM_SAVE_K_2 mechanism, and thus EX_CONTEXT_K_[01] are - * still referencing the original user code. We release the - * atomic lock and rewrite pt_regs so that it appears that we - * came from user-space directly, and after we finish the - * fault we'll go back to user space and re-issue the swint. - * This way the backtrace information is correct if we need to - * emit a stack dump at any point while handling this. - * - * Must match register use in sys_cmpxchg(). - */ - if (pc >= (unsigned long) sys_cmpxchg && - pc < (unsigned long) __sys_cmpxchg_end) { -#ifdef CONFIG_SMP - /* Don't unlock before we could have locked. */ - if (pc >= (unsigned long)__sys_cmpxchg_grab_lock) { - int *lock_ptr = (int *)(regs->regs[ATOMIC_LOCK_REG]); - __atomic_fault_unlock(lock_ptr); - } -#endif - regs->sp = regs->regs[27]; - } - - /* - * We can also fault in the atomic assembly, in which - * case we use the exception table to do the first-level fixup. - * We may re-fixup again in the real fault handler if it - * turns out the faulting address is just bad, and not, - * for example, migrating. - */ - else if (pc >= (unsigned long) __start_atomic_asm_code && - pc < (unsigned long) __end_atomic_asm_code) { - const struct exception_table_entry *fixup; -#ifdef CONFIG_SMP - /* Unlock the atomic lock. */ - int *lock_ptr = (int *)(regs->regs[ATOMIC_LOCK_REG]); - __atomic_fault_unlock(lock_ptr); -#endif - fixup = search_exception_tables(pc); - if (!fixup) - ics_panic("ICS atomic fault not in table: PC %#lx, fault %d", - pc, fault_num); - regs->pc = fixup->fixup; - regs->ex1 = PL_ICS_EX1(KERNEL_PL, 0); - } - - /* - * Now that we have released the atomic lock (if necessary), - * it's safe to spin if the PTE that caused the fault was migrating. - */ - if (fault_num == INT_DTLB_ACCESS) - write = 1; - if (handle_migrating_pte(pgd, fault_num, address, pc, 1, write)) - return state; - - /* Return zero so that we continue on with normal fault handling. */ - state.retval = 0; - return state; -} - -#endif /* !__tilegx__ */ - -/* - * This routine handles page faults. It determines the address, and the - * problem, and then passes it handle_page_fault() for normal DTLB and - * ITLB issues, and for DMA or SN processor faults when we are in user - * space. For the latter, if we're in kernel mode, we just save the - * interrupt away appropriately and return immediately. We can't do - * page faults for user code while in kernel mode. - */ -static inline void __do_page_fault(struct pt_regs *regs, int fault_num, - unsigned long address, unsigned long write) -{ - int is_page_fault; - -#ifdef CONFIG_KPROBES - /* - * This is to notify the fault handler of the kprobes. The - * exception code is redundant as it is also carried in REGS, - * but we pass it anyhow. - */ - if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1, - regs->faultnum, SIGSEGV) == NOTIFY_STOP) - return; -#endif - -#ifdef __tilegx__ - /* - * We don't need early do_page_fault_ics() support, since unlike - * Pro we don't need to worry about unlocking the atomic locks. - * There is only one current case in GX where we touch any memory - * under ICS other than our own kernel stack, and we handle that - * here. (If we crash due to trying to touch our own stack, - * we're in too much trouble for C code to help out anyway.) - */ - if (write & ~1) { - unsigned long pc = write & ~1; - if (pc >= (unsigned long) __start_unalign_asm_code && - pc < (unsigned long) __end_unalign_asm_code) { - struct thread_info *ti = current_thread_info(); - /* - * Our EX_CONTEXT is still what it was from the - * initial unalign exception, but now we've faulted - * on the JIT page. We would like to complete the - * page fault however is appropriate, and then retry - * the instruction that caused the unalign exception. - * Our state has been "corrupted" by setting the low - * bit in "sp", and stashing r0..r3 in the - * thread_info area, so we revert all of that, then - * continue as if this were a normal page fault. - */ - regs->sp &= ~1UL; - regs->regs[0] = ti->unalign_jit_tmp[0]; - regs->regs[1] = ti->unalign_jit_tmp[1]; - regs->regs[2] = ti->unalign_jit_tmp[2]; - regs->regs[3] = ti->unalign_jit_tmp[3]; - write &= 1; - } else { - pr_alert("%s/%d: ICS set at page fault at %#lx: %#lx\n", - current->comm, current->pid, pc, address); - show_regs(regs); - do_group_exit(SIGKILL); - } - } -#else - /* This case should have been handled by do_page_fault_ics(). */ - BUG_ON(write & ~1); -#endif - -#if CHIP_HAS_TILE_DMA() - /* - * If it's a DMA fault, suspend the transfer while we're - * handling the miss; we'll restart after it's handled. If we - * don't suspend, it's possible that this process could swap - * out and back in, and restart the engine since the DMA is - * still 'running'. - */ - if (fault_num == INT_DMATLB_MISS || - fault_num == INT_DMATLB_ACCESS || - fault_num == INT_DMATLB_MISS_DWNCL || - fault_num == INT_DMATLB_ACCESS_DWNCL) { - __insn_mtspr(SPR_DMA_CTR, SPR_DMA_CTR__SUSPEND_MASK); - while (__insn_mfspr(SPR_DMA_USER_STATUS) & - SPR_DMA_STATUS__BUSY_MASK) - ; - } -#endif - - /* Validate fault num and decide if this is a first-time page fault. */ - switch (fault_num) { - case INT_ITLB_MISS: - case INT_DTLB_MISS: -#if CHIP_HAS_TILE_DMA() - case INT_DMATLB_MISS: - case INT_DMATLB_MISS_DWNCL: -#endif - is_page_fault = 1; - break; - - case INT_DTLB_ACCESS: -#if CHIP_HAS_TILE_DMA() - case INT_DMATLB_ACCESS: - case INT_DMATLB_ACCESS_DWNCL: -#endif - is_page_fault = 0; - break; - - default: - panic("Bad fault number %d in do_page_fault", fault_num); - } - -#if CHIP_HAS_TILE_DMA() - if (!user_mode(regs)) { - struct async_tlb *async; - switch (fault_num) { -#if CHIP_HAS_TILE_DMA() - case INT_DMATLB_MISS: - case INT_DMATLB_ACCESS: - case INT_DMATLB_MISS_DWNCL: - case INT_DMATLB_ACCESS_DWNCL: - async = ¤t->thread.dma_async_tlb; - break; -#endif - default: - async = NULL; - } - if (async) { - - /* - * No vmalloc check required, so we can allow - * interrupts immediately at this point. - */ - local_irq_enable(); - - set_thread_flag(TIF_ASYNC_TLB); - if (async->fault_num != 0) { - panic("Second async fault %d; old fault was %d (%#lx/%ld)", - fault_num, async->fault_num, - address, write); - } - BUG_ON(fault_num == 0); - async->fault_num = fault_num; - async->is_fault = is_page_fault; - async->is_write = write; - async->address = address; - return; - } - } -#endif - - handle_page_fault(regs, fault_num, is_page_fault, address, write); -} - -void do_page_fault(struct pt_regs *regs, int fault_num, - unsigned long address, unsigned long write) -{ - __do_page_fault(regs, fault_num, address, write); -} - -#if CHIP_HAS_TILE_DMA() -/* - * This routine effectively re-issues asynchronous page faults - * when we are returning to user space. - */ -void do_async_page_fault(struct pt_regs *regs) -{ - struct async_tlb *async = ¤t->thread.dma_async_tlb; - - /* - * Clear thread flag early. If we re-interrupt while processing - * code here, we will reset it and recall this routine before - * returning to user space. - */ - clear_thread_flag(TIF_ASYNC_TLB); - - if (async->fault_num) { - /* - * Clear async->fault_num before calling the page-fault - * handler so that if we re-interrupt before returning - * from the function we have somewhere to put the - * information from the new interrupt. - */ - int fault_num = async->fault_num; - async->fault_num = 0; - handle_page_fault(regs, fault_num, async->is_fault, - async->address, async->is_write); - } -} -#endif /* CHIP_HAS_TILE_DMA() */ - - -void vmalloc_sync_all(void) -{ -#ifdef __tilegx__ - /* Currently all L1 kernel pmd's are static and shared. */ - BUILD_BUG_ON(pgd_index(VMALLOC_END - PAGE_SIZE) != - pgd_index(VMALLOC_START)); -#else - /* - * Note that races in the updates of insync and start aren't - * problematic: insync can only get set bits added, and updates to - * start are only improving performance (without affecting correctness - * if undone). - */ - static DECLARE_BITMAP(insync, PTRS_PER_PGD); - static unsigned long start = PAGE_OFFSET; - unsigned long address; - - BUILD_BUG_ON(PAGE_OFFSET & ~PGDIR_MASK); - for (address = start; address >= PAGE_OFFSET; address += PGDIR_SIZE) { - if (!test_bit(pgd_index(address), insync)) { - unsigned long flags; - struct list_head *pos; - - spin_lock_irqsave(&pgd_lock, flags); - list_for_each(pos, &pgd_list) - if (!vmalloc_sync_one(list_to_pgd(pos), - address)) { - /* Must be at first entry in list. */ - BUG_ON(pos != pgd_list.next); - break; - } - spin_unlock_irqrestore(&pgd_lock, flags); - if (pos != pgd_list.next) - set_bit(pgd_index(address), insync); - } - if (address == start && test_bit(pgd_index(address), insync)) - start = address + PGDIR_SIZE; - } -#endif -} diff --git a/arch/tile/mm/highmem.c b/arch/tile/mm/highmem.c deleted file mode 100644 index eca28551b22d..000000000000 --- a/arch/tile/mm/highmem.c +++ /dev/null @@ -1,277 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include - -#define kmap_get_pte(vaddr) \ - pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(vaddr), (vaddr)),\ - (vaddr)), (vaddr)) - - -void *kmap(struct page *page) -{ - void *kva; - unsigned long flags; - pte_t *ptep; - - might_sleep(); - if (!PageHighMem(page)) - return page_address(page); - kva = kmap_high(page); - - /* - * Rewrite the PTE under the lock. This ensures that the page - * is not currently migrating. - */ - ptep = kmap_get_pte((unsigned long)kva); - flags = homecache_kpte_lock(); - set_pte_at(&init_mm, kva, ptep, mk_pte(page, page_to_kpgprot(page))); - homecache_kpte_unlock(flags); - - return kva; -} -EXPORT_SYMBOL(kmap); - -void kunmap(struct page *page) -{ - if (in_interrupt()) - BUG(); - if (!PageHighMem(page)) - return; - kunmap_high(page); -} -EXPORT_SYMBOL(kunmap); - -/* - * Describe a single atomic mapping of a page on a given cpu at a - * given address, and allow it to be linked into a list. - */ -struct atomic_mapped_page { - struct list_head list; - struct page *page; - int cpu; - unsigned long va; -}; - -static spinlock_t amp_lock = __SPIN_LOCK_UNLOCKED(&_lock); -static struct list_head amp_list = LIST_HEAD_INIT(amp_list); - -/* - * Combining this structure with a per-cpu declaration lets us give - * each cpu an atomic_mapped_page structure per type. - */ -struct kmap_amps { - struct atomic_mapped_page per_type[KM_TYPE_NR]; -}; -static DEFINE_PER_CPU(struct kmap_amps, amps); - -/* - * Add a page and va, on this cpu, to the list of kmap_atomic pages, - * and write the new pte to memory. Writing the new PTE under the - * lock guarantees that it is either on the list before migration starts - * (if we won the race), or set_pte() sets the migrating bit in the PTE - * (if we lost the race). And doing it under the lock guarantees - * that when kmap_atomic_fix_one_pte() comes along, it finds a valid - * PTE in memory, iff the mapping is still on the amp_list. - * - * Finally, doing it under the lock lets us safely examine the page - * to see if it is immutable or not, for the generic kmap_atomic() case. - * If we examine it earlier we are exposed to a race where it looks - * writable earlier, but becomes immutable before we write the PTE. - */ -static void kmap_atomic_register(struct page *page, int type, - unsigned long va, pte_t *ptep, pte_t pteval) -{ - unsigned long flags; - struct atomic_mapped_page *amp; - - flags = homecache_kpte_lock(); - spin_lock(&_lock); - - /* With interrupts disabled, now fill in the per-cpu info. */ - amp = this_cpu_ptr(&s.per_type[type]); - amp->page = page; - amp->cpu = smp_processor_id(); - amp->va = va; - - /* For generic kmap_atomic(), choose the PTE writability now. */ - if (!pte_read(pteval)) - pteval = mk_pte(page, page_to_kpgprot(page)); - - list_add(&->list, &_list); - set_pte(ptep, pteval); - - spin_unlock(&_lock); - homecache_kpte_unlock(flags); -} - -/* - * Remove a page and va, on this cpu, from the list of kmap_atomic pages. - * Linear-time search, but we count on the lists being short. - * We don't need to adjust the PTE under the lock (as opposed to the - * kmap_atomic_register() case), since we're just unconditionally - * zeroing the PTE after it's off the list. - */ -static void kmap_atomic_unregister(struct page *page, unsigned long va) -{ - unsigned long flags; - struct atomic_mapped_page *amp; - int cpu = smp_processor_id(); - spin_lock_irqsave(&_lock, flags); - list_for_each_entry(amp, &_list, list) { - if (amp->page == page && amp->cpu == cpu && amp->va == va) - break; - } - BUG_ON(&->list == &_list); - list_del(&->list); - spin_unlock_irqrestore(&_lock, flags); -} - -/* Helper routine for kmap_atomic_fix_kpte(), below. */ -static void kmap_atomic_fix_one_kpte(struct atomic_mapped_page *amp, - int finished) -{ - pte_t *ptep = kmap_get_pte(amp->va); - if (!finished) { - set_pte(ptep, pte_mkmigrate(*ptep)); - flush_remote(0, 0, NULL, amp->va, PAGE_SIZE, PAGE_SIZE, - cpumask_of(amp->cpu), NULL, 0); - } else { - /* - * Rewrite a default kernel PTE for this page. - * We rely on the fact that set_pte() writes the - * present+migrating bits last. - */ - pte_t pte = mk_pte(amp->page, page_to_kpgprot(amp->page)); - set_pte(ptep, pte); - } -} - -/* - * This routine is a helper function for homecache_fix_kpte(); see - * its comments for more information on the "finished" argument here. - * - * Note that we hold the lock while doing the remote flushes, which - * will stall any unrelated cpus trying to do kmap_atomic operations. - * We could just update the PTEs under the lock, and save away copies - * of the structs (or just the va+cpu), then flush them after we - * release the lock, but it seems easier just to do it all under the lock. - */ -void kmap_atomic_fix_kpte(struct page *page, int finished) -{ - struct atomic_mapped_page *amp; - unsigned long flags; - spin_lock_irqsave(&_lock, flags); - list_for_each_entry(amp, &_list, list) { - if (amp->page == page) - kmap_atomic_fix_one_kpte(amp, finished); - } - spin_unlock_irqrestore(&_lock, flags); -} - -/* - * kmap_atomic/kunmap_atomic is significantly faster than kmap/kunmap - * because the kmap code must perform a global TLB invalidation when - * the kmap pool wraps. - * - * Note that they may be slower than on x86 (etc.) because unlike on - * those platforms, we do have to take a global lock to map and unmap - * pages on Tile (see above). - * - * When holding an atomic kmap is is not legal to sleep, so atomic - * kmaps are appropriate for short, tight code paths only. - */ -void *kmap_atomic_prot(struct page *page, pgprot_t prot) -{ - unsigned long vaddr; - int idx, type; - pte_t *pte; - - preempt_disable(); - pagefault_disable(); - - /* Avoid icache flushes by disallowing atomic executable mappings. */ - BUG_ON(pte_exec(prot)); - - if (!PageHighMem(page)) - return page_address(page); - - type = kmap_atomic_idx_push(); - idx = type + KM_TYPE_NR*smp_processor_id(); - vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); - pte = kmap_get_pte(vaddr); - BUG_ON(!pte_none(*pte)); - - /* Register that this page is mapped atomically on this cpu. */ - kmap_atomic_register(page, type, vaddr, pte, mk_pte(page, prot)); - - return (void *)vaddr; -} -EXPORT_SYMBOL(kmap_atomic_prot); - -void *kmap_atomic(struct page *page) -{ - /* PAGE_NONE is a magic value that tells us to check immutability. */ - return kmap_atomic_prot(page, PAGE_NONE); -} -EXPORT_SYMBOL(kmap_atomic); - -void __kunmap_atomic(void *kvaddr) -{ - unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; - - if (vaddr >= __fix_to_virt(FIX_KMAP_END) && - vaddr <= __fix_to_virt(FIX_KMAP_BEGIN)) { - pte_t *pte = kmap_get_pte(vaddr); - pte_t pteval = *pte; - int idx, type; - - type = kmap_atomic_idx(); - idx = type + KM_TYPE_NR*smp_processor_id(); - - /* - * Force other mappings to Oops if they try to access this pte - * without first remapping it. Keeping stale mappings around - * is a bad idea. - */ - BUG_ON(!pte_present(pteval) && !pte_migrating(pteval)); - kmap_atomic_unregister(pte_page(pteval), vaddr); - kpte_clear_flush(pte, vaddr); - kmap_atomic_idx_pop(); - } else { - /* Must be a lowmem page */ - BUG_ON(vaddr < PAGE_OFFSET); - BUG_ON(vaddr >= (unsigned long)high_memory); - } - - pagefault_enable(); - preempt_enable(); -} -EXPORT_SYMBOL(__kunmap_atomic); - -/* - * This API is supposed to allow us to map memory without a "struct page". - * Currently we don't support this, though this may change in the future. - */ -void *kmap_atomic_pfn(unsigned long pfn) -{ - return kmap_atomic(pfn_to_page(pfn)); -} -void *kmap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot) -{ - return kmap_atomic_prot(pfn_to_page(pfn), prot); -} diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c deleted file mode 100644 index 4432f31e8479..000000000000 --- a/arch/tile/mm/homecache.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * This code maintains the "home" for each page in the system. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "migrate.h" - - -/* - * The noallocl2 option suppresses all use of the L2 cache to cache - * locally from a remote home. - */ -static int __ro_after_init noallocl2; -static int __init set_noallocl2(char *str) -{ - noallocl2 = 1; - return 0; -} -early_param("noallocl2", set_noallocl2); - - -/* - * Update the irq_stat for cpus that we are going to interrupt - * with TLB or cache flushes. Also handle removing dataplane cpus - * from the TLB flush set, and setting dataplane_tlb_state instead. - */ -static void hv_flush_update(const struct cpumask *cache_cpumask, - struct cpumask *tlb_cpumask, - unsigned long tlb_va, unsigned long tlb_length, - HV_Remote_ASID *asids, int asidcount) -{ - struct cpumask mask; - int i, cpu; - - cpumask_clear(&mask); - if (cache_cpumask) - cpumask_or(&mask, &mask, cache_cpumask); - if (tlb_cpumask && tlb_length) { - cpumask_or(&mask, &mask, tlb_cpumask); - } - - for (i = 0; i < asidcount; ++i) - cpumask_set_cpu(asids[i].y * smp_width + asids[i].x, &mask); - - /* - * Don't bother to update atomically; losing a count - * here is not that critical. - */ - for_each_cpu(cpu, &mask) - ++per_cpu(irq_stat, cpu).irq_hv_flush_count; -} - -/* - * This wrapper function around hv_flush_remote() does several things: - * - * - Provides a return value error-checking panic path, since - * there's never any good reason for hv_flush_remote() to fail. - * - Accepts a 32-bit PFN rather than a 64-bit PA, which generally - * is the type that Linux wants to pass around anyway. - * - Canonicalizes that lengths of zero make cpumasks NULL. - * - Handles deferring TLB flushes for dataplane tiles. - * - Tracks remote interrupts in the per-cpu irq_cpustat_t. - * - * Note that we have to wait until the cache flush completes before - * updating the per-cpu last_cache_flush word, since otherwise another - * concurrent flush can race, conclude the flush has already - * completed, and start to use the page while it's still dirty - * remotely (running concurrently with the actual evict, presumably). - */ -void flush_remote(unsigned long cache_pfn, unsigned long cache_control, - const struct cpumask *cache_cpumask_orig, - HV_VirtAddr tlb_va, unsigned long tlb_length, - unsigned long tlb_pgsize, - const struct cpumask *tlb_cpumask_orig, - HV_Remote_ASID *asids, int asidcount) -{ - int rc; - struct cpumask cache_cpumask_copy, tlb_cpumask_copy; - struct cpumask *cache_cpumask, *tlb_cpumask; - HV_PhysAddr cache_pa; - - mb(); /* provided just to simplify "magic hypervisor" mode */ - - /* - * Canonicalize and copy the cpumasks. - */ - if (cache_cpumask_orig && cache_control) { - cpumask_copy(&cache_cpumask_copy, cache_cpumask_orig); - cache_cpumask = &cache_cpumask_copy; - } else { - cpumask_clear(&cache_cpumask_copy); - cache_cpumask = NULL; - } - if (cache_cpumask == NULL) - cache_control = 0; - if (tlb_cpumask_orig && tlb_length) { - cpumask_copy(&tlb_cpumask_copy, tlb_cpumask_orig); - tlb_cpumask = &tlb_cpumask_copy; - } else { - cpumask_clear(&tlb_cpumask_copy); - tlb_cpumask = NULL; - } - - hv_flush_update(cache_cpumask, tlb_cpumask, tlb_va, tlb_length, - asids, asidcount); - cache_pa = (HV_PhysAddr)cache_pfn << PAGE_SHIFT; - rc = hv_flush_remote(cache_pa, cache_control, - cpumask_bits(cache_cpumask), - tlb_va, tlb_length, tlb_pgsize, - cpumask_bits(tlb_cpumask), - asids, asidcount); - if (rc == 0) - return; - - pr_err("hv_flush_remote(%#llx, %#lx, %p [%*pb], %#lx, %#lx, %#lx, %p [%*pb], %p, %d) = %d\n", - cache_pa, cache_control, cache_cpumask, - cpumask_pr_args(&cache_cpumask_copy), - (unsigned long)tlb_va, tlb_length, tlb_pgsize, tlb_cpumask, - cpumask_pr_args(&tlb_cpumask_copy), asids, asidcount, rc); - panic("Unsafe to continue."); -} - -static void homecache_finv_page_va(void* va, int home) -{ - int cpu = get_cpu(); - if (home == cpu) { - finv_buffer_local(va, PAGE_SIZE); - } else if (home == PAGE_HOME_HASH) { - finv_buffer_remote(va, PAGE_SIZE, 1); - } else { - BUG_ON(home < 0 || home >= NR_CPUS); - finv_buffer_remote(va, PAGE_SIZE, 0); - } - put_cpu(); -} - -void homecache_finv_map_page(struct page *page, int home) -{ - unsigned long flags; - unsigned long va; - pte_t *ptep; - pte_t pte; - - if (home == PAGE_HOME_UNCACHED) - return; - local_irq_save(flags); -#ifdef CONFIG_HIGHMEM - va = __fix_to_virt(FIX_KMAP_BEGIN + kmap_atomic_idx_push() + - (KM_TYPE_NR * smp_processor_id())); -#else - va = __fix_to_virt(FIX_HOMECACHE_BEGIN + smp_processor_id()); -#endif - ptep = virt_to_kpte(va); - pte = pfn_pte(page_to_pfn(page), PAGE_KERNEL); - __set_pte(ptep, pte_set_home(pte, home)); - homecache_finv_page_va((void *)va, home); - __pte_clear(ptep); - hv_flush_page(va, PAGE_SIZE); -#ifdef CONFIG_HIGHMEM - kmap_atomic_idx_pop(); -#endif - local_irq_restore(flags); -} - -static void homecache_finv_page_home(struct page *page, int home) -{ - if (!PageHighMem(page) && home == page_home(page)) - homecache_finv_page_va(page_address(page), home); - else - homecache_finv_map_page(page, home); -} - -static inline bool incoherent_home(int home) -{ - return home == PAGE_HOME_IMMUTABLE || home == PAGE_HOME_INCOHERENT; -} - -static void homecache_finv_page_internal(struct page *page, int force_map) -{ - int home = page_home(page); - if (home == PAGE_HOME_UNCACHED) - return; - if (incoherent_home(home)) { - int cpu; - for_each_cpu(cpu, &cpu_cacheable_map) - homecache_finv_map_page(page, cpu); - } else if (force_map) { - /* Force if, e.g., the normal mapping is migrating. */ - homecache_finv_map_page(page, home); - } else { - homecache_finv_page_home(page, home); - } - sim_validate_lines_evicted(PFN_PHYS(page_to_pfn(page)), PAGE_SIZE); -} - -void homecache_finv_page(struct page *page) -{ - homecache_finv_page_internal(page, 0); -} - -void homecache_evict(const struct cpumask *mask) -{ - flush_remote(0, HV_FLUSH_EVICT_L2, mask, 0, 0, 0, NULL, NULL, 0); -} - -/* Report the home corresponding to a given PTE. */ -static int pte_to_home(pte_t pte) -{ - if (hv_pte_get_nc(pte)) - return PAGE_HOME_IMMUTABLE; - switch (hv_pte_get_mode(pte)) { - case HV_PTE_MODE_CACHE_TILE_L3: - return get_remote_cache_cpu(pte); - case HV_PTE_MODE_CACHE_NO_L3: - return PAGE_HOME_INCOHERENT; - case HV_PTE_MODE_UNCACHED: - return PAGE_HOME_UNCACHED; - case HV_PTE_MODE_CACHE_HASH_L3: - return PAGE_HOME_HASH; - } - panic("Bad PTE %#llx\n", pte.val); -} - -/* Update the home of a PTE if necessary (can also be used for a pgprot_t). */ -pte_t pte_set_home(pte_t pte, int home) -{ -#if CHIP_HAS_MMIO() - /* Check for MMIO mappings and pass them through. */ - if (hv_pte_get_mode(pte) == HV_PTE_MODE_MMIO) - return pte; -#endif - - - /* - * Only immutable pages get NC mappings. If we have a - * non-coherent PTE, but the underlying page is not - * immutable, it's likely the result of a forced - * caching setting running up against ptrace setting - * the page to be writable underneath. In this case, - * just keep the PTE coherent. - */ - if (hv_pte_get_nc(pte) && home != PAGE_HOME_IMMUTABLE) { - pte = hv_pte_clear_nc(pte); - pr_err("non-immutable page incoherently referenced: %#llx\n", - pte.val); - } - - switch (home) { - - case PAGE_HOME_UNCACHED: - pte = hv_pte_set_mode(pte, HV_PTE_MODE_UNCACHED); - break; - - case PAGE_HOME_INCOHERENT: - pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3); - break; - - case PAGE_HOME_IMMUTABLE: - /* - * We could home this page anywhere, since it's immutable, - * but by default just home it to follow "hash_default". - */ - BUG_ON(hv_pte_get_writable(pte)); - if (pte_get_forcecache(pte)) { - /* Upgrade "force any cpu" to "No L3" for immutable. */ - if (hv_pte_get_mode(pte) == HV_PTE_MODE_CACHE_TILE_L3 - && pte_get_anyhome(pte)) { - pte = hv_pte_set_mode(pte, - HV_PTE_MODE_CACHE_NO_L3); - } - } else - if (hash_default) - pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_HASH_L3); - else - pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3); - pte = hv_pte_set_nc(pte); - break; - - case PAGE_HOME_HASH: - pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_HASH_L3); - break; - - default: - BUG_ON(home < 0 || home >= NR_CPUS || - !cpu_is_valid_lotar(home)); - pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3); - pte = set_remote_cache_cpu(pte, home); - break; - } - - if (noallocl2) - pte = hv_pte_set_no_alloc_l2(pte); - - /* Simplify "no local and no l3" to "uncached" */ - if (hv_pte_get_no_alloc_l2(pte) && hv_pte_get_no_alloc_l1(pte) && - hv_pte_get_mode(pte) == HV_PTE_MODE_CACHE_NO_L3) { - pte = hv_pte_set_mode(pte, HV_PTE_MODE_UNCACHED); - } - - /* Checking this case here gives a better panic than from the hv. */ - BUG_ON(hv_pte_get_mode(pte) == 0); - - return pte; -} -EXPORT_SYMBOL(pte_set_home); - -/* - * The routines in this section are the "static" versions of the normal - * dynamic homecaching routines; they just set the home cache - * of a kernel page once, and require a full-chip cache/TLB flush, - * so they're not suitable for anything but infrequent use. - */ - -int page_home(struct page *page) -{ - if (PageHighMem(page)) { - return PAGE_HOME_HASH; - } else { - unsigned long kva = (unsigned long)page_address(page); - return pte_to_home(*virt_to_kpte(kva)); - } -} -EXPORT_SYMBOL(page_home); - -void homecache_change_page_home(struct page *page, int order, int home) -{ - int i, pages = (1 << order); - unsigned long kva; - - BUG_ON(PageHighMem(page)); - BUG_ON(page_count(page) > 1); - BUG_ON(page_mapcount(page) != 0); - kva = (unsigned long) page_address(page); - flush_remote(0, HV_FLUSH_EVICT_L2, &cpu_cacheable_map, - kva, pages * PAGE_SIZE, PAGE_SIZE, cpu_online_mask, - NULL, 0); - - for (i = 0; i < pages; ++i, kva += PAGE_SIZE) { - pte_t *ptep = virt_to_kpte(kva); - pte_t pteval = *ptep; - BUG_ON(!pte_present(pteval) || pte_huge(pteval)); - __set_pte(ptep, pte_set_home(pteval, home)); - } -} -EXPORT_SYMBOL(homecache_change_page_home); - -struct page *homecache_alloc_pages(gfp_t gfp_mask, - unsigned int order, int home) -{ - struct page *page; - BUG_ON(gfp_mask & __GFP_HIGHMEM); /* must be lowmem */ - page = alloc_pages(gfp_mask, order); - if (page) - homecache_change_page_home(page, order, home); - return page; -} -EXPORT_SYMBOL(homecache_alloc_pages); - -struct page *homecache_alloc_pages_node(int nid, gfp_t gfp_mask, - unsigned int order, int home) -{ - struct page *page; - BUG_ON(gfp_mask & __GFP_HIGHMEM); /* must be lowmem */ - page = alloc_pages_node(nid, gfp_mask, order); - if (page) - homecache_change_page_home(page, order, home); - return page; -} - -void __homecache_free_pages(struct page *page, unsigned int order) -{ - if (put_page_testzero(page)) { - homecache_change_page_home(page, order, PAGE_HOME_HASH); - if (order == 0) { - free_unref_page(page); - } else { - init_page_count(page); - __free_pages(page, order); - } - } -} -EXPORT_SYMBOL(__homecache_free_pages); - -void homecache_free_pages(unsigned long addr, unsigned int order) -{ - if (addr != 0) { - VM_BUG_ON(!virt_addr_valid((void *)addr)); - __homecache_free_pages(virt_to_page((void *)addr), order); - } -} -EXPORT_SYMBOL(homecache_free_pages); diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c deleted file mode 100644 index 0986d426a413..000000000000 --- a/arch/tile/mm/hugetlbpage.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * TILE Huge TLB Page Support for Kernel. - * Taken from i386 hugetlb implementation: - * Copyright (C) 2002, Rohit Seth - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_HUGETLB_SUPER_PAGES - -/* - * Provide an additional huge page size (in addition to the regular default - * huge page size) if no "hugepagesz" arguments are specified. - * Note that it must be smaller than the default huge page size so - * that it's possible to allocate them on demand from the buddy allocator. - * You can change this to 64K (on a 16K build), 256K, 1M, or 4M, - * or not define it at all. - */ -#define ADDITIONAL_HUGE_SIZE (1024 * 1024UL) - -/* "Extra" page-size multipliers, one per level of the page table. */ -int huge_shift[HUGE_SHIFT_ENTRIES] = { -#ifdef ADDITIONAL_HUGE_SIZE -#define ADDITIONAL_HUGE_SHIFT __builtin_ctzl(ADDITIONAL_HUGE_SIZE / PAGE_SIZE) - [HUGE_SHIFT_PAGE] = ADDITIONAL_HUGE_SHIFT -#endif -}; - -#endif - -pte_t *huge_pte_alloc(struct mm_struct *mm, - unsigned long addr, unsigned long sz) -{ - pgd_t *pgd; - pud_t *pud; - - addr &= -sz; /* Mask off any low bits in the address. */ - - pgd = pgd_offset(mm, addr); - pud = pud_alloc(mm, pgd, addr); - -#ifdef CONFIG_HUGETLB_SUPER_PAGES - if (sz >= PGDIR_SIZE) { - BUG_ON(sz != PGDIR_SIZE && - sz != PGDIR_SIZE << huge_shift[HUGE_SHIFT_PGDIR]); - return (pte_t *)pud; - } else { - pmd_t *pmd = pmd_alloc(mm, pud, addr); - if (sz >= PMD_SIZE) { - BUG_ON(sz != PMD_SIZE && - sz != (PMD_SIZE << huge_shift[HUGE_SHIFT_PMD])); - return (pte_t *)pmd; - } - else { - if (sz != PAGE_SIZE << huge_shift[HUGE_SHIFT_PAGE]) - panic("Unexpected page size %#lx\n", sz); - return pte_alloc_map(mm, pmd, addr); - } - } -#else - BUG_ON(sz != PMD_SIZE); - return (pte_t *) pmd_alloc(mm, pud, addr); -#endif -} - -static pte_t *get_pte(pte_t *base, int index, int level) -{ - pte_t *ptep = base + index; -#ifdef CONFIG_HUGETLB_SUPER_PAGES - if (!pte_present(*ptep) && huge_shift[level] != 0) { - unsigned long mask = -1UL << huge_shift[level]; - pte_t *super_ptep = base + (index & mask); - pte_t pte = *super_ptep; - if (pte_present(pte) && pte_super(pte)) - ptep = super_ptep; - } -#endif - return ptep; -} - -pte_t *huge_pte_offset(struct mm_struct *mm, - unsigned long addr, unsigned long sz) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; -#ifdef CONFIG_HUGETLB_SUPER_PAGES - pte_t *pte; -#endif - - /* Get the top-level page table entry. */ - pgd = (pgd_t *)get_pte((pte_t *)mm->pgd, pgd_index(addr), 0); - - /* We don't have four levels. */ - pud = pud_offset(pgd, addr); -#ifndef __PAGETABLE_PUD_FOLDED -# error support fourth page table level -#endif - if (!pud_present(*pud)) - return NULL; - - /* Check for an L0 huge PTE, if we have three levels. */ -#ifndef __PAGETABLE_PMD_FOLDED - if (pud_huge(*pud)) - return (pte_t *)pud; - - pmd = (pmd_t *)get_pte((pte_t *)pud_page_vaddr(*pud), - pmd_index(addr), 1); - if (!pmd_present(*pmd)) - return NULL; -#else - pmd = pmd_offset(pud, addr); -#endif - - /* Check for an L1 huge PTE. */ - if (pmd_huge(*pmd)) - return (pte_t *)pmd; - -#ifdef CONFIG_HUGETLB_SUPER_PAGES - /* Check for an L2 huge PTE. */ - pte = get_pte((pte_t *)pmd_page_vaddr(*pmd), pte_index(addr), 2); - if (!pte_present(*pte)) - return NULL; - if (pte_super(*pte)) - return pte; -#endif - - return NULL; -} - -int pmd_huge(pmd_t pmd) -{ - return !!(pmd_val(pmd) & _PAGE_HUGE_PAGE); -} - -int pud_huge(pud_t pud) -{ - return !!(pud_val(pud) & _PAGE_HUGE_PAGE); -} - -#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA -static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file, - unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - struct vm_unmapped_area_info info; - - info.flags = 0; - info.length = len; - info.low_limit = TASK_UNMAPPED_BASE; - info.high_limit = TASK_SIZE; - info.align_mask = PAGE_MASK & ~huge_page_mask(h); - info.align_offset = 0; - return vm_unmapped_area(&info); -} - -static unsigned long hugetlb_get_unmapped_area_topdown(struct file *file, - unsigned long addr0, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - struct vm_unmapped_area_info info; - unsigned long addr; - - info.flags = VM_UNMAPPED_AREA_TOPDOWN; - info.length = len; - info.low_limit = PAGE_SIZE; - info.high_limit = current->mm->mmap_base; - info.align_mask = PAGE_MASK & ~huge_page_mask(h); - info.align_offset = 0; - addr = vm_unmapped_area(&info); - - /* - * A failed mmap() very likely causes application failure, - * so fall back to the bottom-up function here. This scenario - * can happen with large stack limits and large mmap() - * allocations. - */ - if (addr & ~PAGE_MASK) { - VM_BUG_ON(addr != -ENOMEM); - info.flags = 0; - info.low_limit = TASK_UNMAPPED_BASE; - info.high_limit = TASK_SIZE; - addr = vm_unmapped_area(&info); - } - - return addr; -} - -unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) -{ - struct hstate *h = hstate_file(file); - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma; - - if (len & ~huge_page_mask(h)) - return -EINVAL; - if (len > TASK_SIZE) - return -ENOMEM; - - if (flags & MAP_FIXED) { - if (prepare_hugepage_range(file, addr, len)) - return -EINVAL; - return addr; - } - - if (addr) { - addr = ALIGN(addr, huge_page_size(h)); - vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && - (!vma || addr + len <= vm_start_gap(vma))) - return addr; - } - if (current->mm->get_unmapped_area == arch_get_unmapped_area) - return hugetlb_get_unmapped_area_bottomup(file, addr, len, - pgoff, flags); - else - return hugetlb_get_unmapped_area_topdown(file, addr, len, - pgoff, flags); -} -#endif /* HAVE_ARCH_HUGETLB_UNMAPPED_AREA */ - -#ifdef CONFIG_HUGETLB_SUPER_PAGES -static __init int __setup_hugepagesz(unsigned long ps) -{ - int log_ps = __builtin_ctzl(ps); - int level, base_shift; - - if ((1UL << log_ps) != ps || (log_ps & 1) != 0) { - pr_warn("Not enabling %ld byte huge pages; must be a power of four\n", - ps); - return -EINVAL; - } - - if (ps > 64*1024*1024*1024UL) { - pr_warn("Not enabling %ld MB huge pages; largest legal value is 64 GB\n", - ps >> 20); - return -EINVAL; - } else if (ps >= PUD_SIZE) { - static long hv_jpage_size; - if (hv_jpage_size == 0) - hv_jpage_size = hv_sysconf(HV_SYSCONF_PAGE_SIZE_JUMBO); - if (hv_jpage_size != PUD_SIZE) { - pr_warn("Not enabling >= %ld MB huge pages: hypervisor reports size %ld\n", - PUD_SIZE >> 20, hv_jpage_size); - return -EINVAL; - } - level = 0; - base_shift = PUD_SHIFT; - } else if (ps >= PMD_SIZE) { - level = 1; - base_shift = PMD_SHIFT; - } else if (ps > PAGE_SIZE) { - level = 2; - base_shift = PAGE_SHIFT; - } else { - pr_err("hugepagesz: huge page size %ld too small\n", ps); - return -EINVAL; - } - - if (log_ps != base_shift) { - int shift_val = log_ps - base_shift; - if (huge_shift[level] != 0) { - int old_shift = base_shift + huge_shift[level]; - pr_warn("Not enabling %ld MB huge pages; already have size %ld MB\n", - ps >> 20, (1UL << old_shift) >> 20); - return -EINVAL; - } - if (hv_set_pte_super_shift(level, shift_val) != 0) { - pr_warn("Not enabling %ld MB huge pages; no hypervisor support\n", - ps >> 20); - return -EINVAL; - } - printk(KERN_DEBUG "Enabled %ld MB huge pages\n", ps >> 20); - huge_shift[level] = shift_val; - } - - hugetlb_add_hstate(log_ps - PAGE_SHIFT); - - return 0; -} - -static bool saw_hugepagesz; - -static __init int setup_hugepagesz(char *opt) -{ - int rc; - - if (!saw_hugepagesz) { - saw_hugepagesz = true; - memset(huge_shift, 0, sizeof(huge_shift)); - } - rc = __setup_hugepagesz(memparse(opt, NULL)); - if (rc) - hugetlb_bad_size(); - return rc; -} -__setup("hugepagesz=", setup_hugepagesz); - -#ifdef ADDITIONAL_HUGE_SIZE -/* - * Provide an additional huge page size if no "hugepagesz" args are given. - * In that case, all the cores have properly set up their hv super_shift - * already, but we need to notify the hugetlb code to enable the - * new huge page size from the Linux point of view. - */ -static __init int add_default_hugepagesz(void) -{ - if (!saw_hugepagesz) { - BUILD_BUG_ON(ADDITIONAL_HUGE_SIZE >= PMD_SIZE || - ADDITIONAL_HUGE_SIZE <= PAGE_SIZE); - BUILD_BUG_ON((PAGE_SIZE << ADDITIONAL_HUGE_SHIFT) != - ADDITIONAL_HUGE_SIZE); - BUILD_BUG_ON(ADDITIONAL_HUGE_SHIFT & 1); - hugetlb_add_hstate(ADDITIONAL_HUGE_SHIFT); - } - return 0; -} -arch_initcall(add_default_hugepagesz); -#endif - -#endif /* CONFIG_HUGETLB_SUPER_PAGES */ diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c deleted file mode 100644 index 5f757e04bcd2..000000000000 --- a/arch/tile/mm/init.c +++ /dev/null @@ -1,956 +0,0 @@ -/* - * Copyright (C) 1995 Linus Torvalds - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "migrate.h" - -#define clear_pgd(pmdptr) (*(pmdptr) = hv_pte(0)) - -#ifndef __tilegx__ -unsigned long VMALLOC_RESERVE = CONFIG_VMALLOC_RESERVE; -EXPORT_SYMBOL(VMALLOC_RESERVE); -#endif - -/* Create an L2 page table */ -static pte_t * __init alloc_pte(void) -{ - return __alloc_bootmem(L2_KERNEL_PGTABLE_SIZE, HV_PAGE_TABLE_ALIGN, 0); -} - -/* - * L2 page tables per controller. We allocate these all at once from - * the bootmem allocator and store them here. This saves on kernel L2 - * page table memory, compared to allocating a full 64K page per L2 - * page table, and also means that in cases where we use huge pages, - * we are guaranteed to later be able to shatter those huge pages and - * switch to using these page tables instead, without requiring - * further allocation. Each l2_ptes[] entry points to the first page - * table for the first hugepage-size piece of memory on the - * controller; other page tables are just indexed directly, i.e. the - * L2 page tables are contiguous in memory for each controller. - */ -static pte_t *l2_ptes[MAX_NUMNODES]; -static int num_l2_ptes[MAX_NUMNODES]; - -static void init_prealloc_ptes(int node, int pages) -{ - BUG_ON(pages & (PTRS_PER_PTE - 1)); - if (pages) { - num_l2_ptes[node] = pages; - l2_ptes[node] = __alloc_bootmem(pages * sizeof(pte_t), - HV_PAGE_TABLE_ALIGN, 0); - } -} - -pte_t *get_prealloc_pte(unsigned long pfn) -{ - int node = pfn_to_nid(pfn); - pfn &= ~(-1UL << (NR_PA_HIGHBIT_SHIFT - PAGE_SHIFT)); - BUG_ON(node >= MAX_NUMNODES); - BUG_ON(pfn >= num_l2_ptes[node]); - return &l2_ptes[node][pfn]; -} - -/* - * What caching do we expect pages from the heap to have when - * they are allocated during bootup? (Once we've installed the - * "real" swapper_pg_dir.) - */ -static int initial_heap_home(void) -{ - if (hash_default) - return PAGE_HOME_HASH; - return smp_processor_id(); -} - -/* - * Place a pointer to an L2 page table in a middle page - * directory entry. - */ -static void __init assign_pte(pmd_t *pmd, pte_t *page_table) -{ - phys_addr_t pa = __pa(page_table); - unsigned long l2_ptfn = pa >> HV_LOG2_PAGE_TABLE_ALIGN; - pte_t pteval = hv_pte_set_ptfn(__pgprot(_PAGE_TABLE), l2_ptfn); - BUG_ON((pa & (HV_PAGE_TABLE_ALIGN-1)) != 0); - pteval = pte_set_home(pteval, initial_heap_home()); - *(pte_t *)pmd = pteval; - if (page_table != (pte_t *)pmd_page_vaddr(*pmd)) - BUG(); -} - -#ifdef __tilegx__ - -static inline pmd_t *alloc_pmd(void) -{ - return __alloc_bootmem(L1_KERNEL_PGTABLE_SIZE, HV_PAGE_TABLE_ALIGN, 0); -} - -static inline void assign_pmd(pud_t *pud, pmd_t *pmd) -{ - assign_pte((pmd_t *)pud, (pte_t *)pmd); -} - -#endif /* __tilegx__ */ - -/* Replace the given pmd with a full PTE table. */ -void __init shatter_pmd(pmd_t *pmd) -{ - pte_t *pte = get_prealloc_pte(pte_pfn(*(pte_t *)pmd)); - assign_pte(pmd, pte); -} - -#ifdef __tilegx__ -static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va) -{ - pud_t *pud = pud_offset(&pgtables[pgd_index(va)], va); - if (pud_none(*pud)) - assign_pmd(pud, alloc_pmd()); - return pmd_offset(pud, va); -} -#else -static pmd_t *__init get_pmd(pgd_t pgtables[], unsigned long va) -{ - return pmd_offset(pud_offset(&pgtables[pgd_index(va)], va), va); -} -#endif - -/* - * This function initializes a certain range of kernel virtual memory - * with new bootmem page tables, everywhere page tables are missing in - * the given range. - */ - -/* - * NOTE: The pagetables are allocated contiguous on the physical space - * so we can cache the place of the first one and move around without - * checking the pgd every time. - */ -static void __init page_table_range_init(unsigned long start, - unsigned long end, pgd_t *pgd) -{ - unsigned long vaddr; - start = round_down(start, PMD_SIZE); - end = round_up(end, PMD_SIZE); - for (vaddr = start; vaddr < end; vaddr += PMD_SIZE) { - pmd_t *pmd = get_pmd(pgd, vaddr); - if (pmd_none(*pmd)) - assign_pte(pmd, alloc_pte()); - } -} - - -static int __initdata ktext_hash = 1; /* .text pages */ -static int __initdata kdata_hash = 1; /* .data and .bss pages */ -int __ro_after_init hash_default = 1; /* kernel allocator pages */ -EXPORT_SYMBOL(hash_default); -int __ro_after_init kstack_hash = 1; /* if no homecaching, use h4h */ - -/* - * CPUs to use to for striping the pages of kernel data. If hash-for-home - * is available, this is only relevant if kcache_hash sets up the - * .data and .bss to be page-homed, and we don't want the default mode - * of using the full set of kernel cpus for the striping. - */ -static __initdata struct cpumask kdata_mask; -static __initdata int kdata_arg_seen; - -int __ro_after_init kdata_huge; /* if no homecaching, small pages */ - - -/* Combine a generic pgprot_t with cache home to get a cache-aware pgprot. */ -static pgprot_t __init construct_pgprot(pgprot_t prot, int home) -{ - prot = pte_set_home(prot, home); - if (home == PAGE_HOME_IMMUTABLE) { - if (ktext_hash) - prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_HASH_L3); - else - prot = hv_pte_set_mode(prot, HV_PTE_MODE_CACHE_NO_L3); - } - return prot; -} - -/* - * For a given kernel data VA, how should it be cached? - * We return the complete pgprot_t with caching bits set. - */ -static pgprot_t __init init_pgprot(ulong address) -{ - int cpu; - unsigned long page; - enum { CODE_DELTA = MEM_SV_START - PAGE_OFFSET }; - - /* For kdata=huge, everything is just hash-for-home. */ - if (kdata_huge) - return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); - - /* - * We map the aliased pages of permanent text so we can - * update them if necessary, for ftrace, etc. - */ - if (address < (ulong) _sinittext - CODE_DELTA) - return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); - - /* We map read-only data non-coherent for performance. */ - if ((address >= (ulong) __start_rodata && - address < (ulong) __end_rodata) || - address == (ulong) empty_zero_page) { - return construct_pgprot(PAGE_KERNEL_RO, PAGE_HOME_IMMUTABLE); - } - -#ifndef __tilegx__ - /* Force the atomic_locks[] array page to be hash-for-home. */ - if (address == (ulong) atomic_locks) - return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); -#endif - - /* - * Everything else that isn't data or bss is heap, so mark it - * with the initial heap home (hash-for-home, or this cpu). This - * includes any addresses after the loaded image and any address before - * __init_end, since we already captured the case of text before - * _sinittext, and __pa(einittext) is approximately __pa(__init_begin). - * - * All the LOWMEM pages that we mark this way will get their - * struct page homecache properly marked later, in set_page_homes(). - * The HIGHMEM pages we leave with a default zero for their - * homes, but with a zero free_time we don't have to actually - * do a flush action the first time we use them, either. - */ - if (address >= (ulong) _end || address < (ulong) __init_end) - return construct_pgprot(PAGE_KERNEL, initial_heap_home()); - - /* Use hash-for-home if requested for data/bss. */ - if (kdata_hash) - return construct_pgprot(PAGE_KERNEL, PAGE_HOME_HASH); - - /* - * Otherwise we just hand out consecutive cpus. To avoid - * requiring this function to hold state, we just walk forward from - * __end_rodata by PAGE_SIZE, skipping the readonly and init data, to - * reach the requested address, while walking cpu home around - * kdata_mask. This is typically no more than a dozen or so iterations. - */ - page = (((ulong)__end_rodata) + PAGE_SIZE - 1) & PAGE_MASK; - BUG_ON(address < page || address >= (ulong)_end); - cpu = cpumask_first(&kdata_mask); - for (; page < address; page += PAGE_SIZE) { - if (page >= (ulong)&init_thread_union && - page < (ulong)&init_thread_union + THREAD_SIZE) - continue; - if (page == (ulong)empty_zero_page) - continue; -#ifndef __tilegx__ - if (page == (ulong)atomic_locks) - continue; -#endif - cpu = cpumask_next(cpu, &kdata_mask); - if (cpu == NR_CPUS) - cpu = cpumask_first(&kdata_mask); - } - return construct_pgprot(PAGE_KERNEL, cpu); -} - -/* - * This function sets up how we cache the kernel text. If we have - * hash-for-home support, normally that is used instead (see the - * kcache_hash boot flag for more information). But if we end up - * using a page-based caching technique, this option sets up the - * details of that. In addition, the "ktext=nocache" option may - * always be used to disable local caching of text pages, if desired. - */ - -static int __initdata ktext_arg_seen; -static int __initdata ktext_small; -static int __initdata ktext_local; -static int __initdata ktext_all; -static int __initdata ktext_nondataplane; -static int __initdata ktext_nocache; -static struct cpumask __initdata ktext_mask; - -static int __init setup_ktext(char *str) -{ - if (str == NULL) - return -EINVAL; - - /* If you have a leading "nocache", turn off ktext caching */ - if (strncmp(str, "nocache", 7) == 0) { - ktext_nocache = 1; - pr_info("ktext: disabling local caching of kernel text\n"); - str += 7; - if (*str == ',') - ++str; - if (*str == '\0') - return 0; - } - - ktext_arg_seen = 1; - - /* Default setting: use a huge page */ - if (strcmp(str, "huge") == 0) - pr_info("ktext: using one huge locally cached page\n"); - - /* Pay TLB cost but get no cache benefit: cache small pages locally */ - else if (strcmp(str, "local") == 0) { - ktext_small = 1; - ktext_local = 1; - pr_info("ktext: using small pages with local caching\n"); - } - - /* Neighborhood cache ktext pages on all cpus. */ - else if (strcmp(str, "all") == 0) { - ktext_small = 1; - ktext_all = 1; - pr_info("ktext: using maximal caching neighborhood\n"); - } - - - /* Neighborhood ktext pages on specified mask */ - else if (cpulist_parse(str, &ktext_mask) == 0) { - if (cpumask_weight(&ktext_mask) > 1) { - ktext_small = 1; - pr_info("ktext: using caching neighborhood %*pbl with small pages\n", - cpumask_pr_args(&ktext_mask)); - } else { - pr_info("ktext: caching on cpu %*pbl with one huge page\n", - cpumask_pr_args(&ktext_mask)); - } - } - - else if (*str) - return -EINVAL; - - return 0; -} - -early_param("ktext", setup_ktext); - - -static inline pgprot_t ktext_set_nocache(pgprot_t prot) -{ - if (!ktext_nocache) - prot = hv_pte_set_nc(prot); - else - prot = hv_pte_set_no_alloc_l2(prot); - return prot; -} - -/* Temporary page table we use for staging. */ -static pgd_t pgtables[PTRS_PER_PGD] - __attribute__((aligned(HV_PAGE_TABLE_ALIGN))); - -/* - * This maps the physical memory to kernel virtual address space, a total - * of max_low_pfn pages, by creating page tables starting from address - * PAGE_OFFSET. - * - * This routine transitions us from using a set of compiled-in large - * pages to using some more precise caching, including removing access - * to code pages mapped at PAGE_OFFSET (executed only at MEM_SV_START) - * marking read-only data as locally cacheable, striping the remaining - * .data and .bss across all the available tiles, and removing access - * to pages above the top of RAM (thus ensuring a page fault from a bad - * virtual address rather than a hypervisor shoot down for accessing - * memory outside the assigned limits). - */ -static void __init kernel_physical_mapping_init(pgd_t *pgd_base) -{ - unsigned long long irqmask; - unsigned long address, pfn; - pmd_t *pmd; - pte_t *pte; - int pte_ofs; - const struct cpumask *my_cpu_mask = cpumask_of(smp_processor_id()); - struct cpumask kstripe_mask; - int rc, i; - - if (ktext_arg_seen && ktext_hash) { - pr_warn("warning: \"ktext\" boot argument ignored if \"kcache_hash\" sets up text hash-for-home\n"); - ktext_small = 0; - } - - if (kdata_arg_seen && kdata_hash) { - pr_warn("warning: \"kdata\" boot argument ignored if \"kcache_hash\" sets up data hash-for-home\n"); - } - - if (kdata_huge && !hash_default) { - pr_warn("warning: disabling \"kdata=huge\"; requires kcache_hash=all or =allbutstack\n"); - kdata_huge = 0; - } - - /* - * Set up a mask for cpus to use for kernel striping. - * This is normally all cpus, but minus dataplane cpus if any. - * If the dataplane covers the whole chip, we stripe over - * the whole chip too. - */ - cpumask_copy(&kstripe_mask, cpu_possible_mask); - if (!kdata_arg_seen) - kdata_mask = kstripe_mask; - - /* Allocate and fill in L2 page tables */ - for (i = 0; i < MAX_NUMNODES; ++i) { -#ifdef CONFIG_HIGHMEM - unsigned long end_pfn = node_lowmem_end_pfn[i]; -#else - unsigned long end_pfn = node_end_pfn[i]; -#endif - unsigned long end_huge_pfn = 0; - - /* Pre-shatter the last huge page to allow per-cpu pages. */ - if (kdata_huge) - end_huge_pfn = end_pfn - (HPAGE_SIZE >> PAGE_SHIFT); - - pfn = node_start_pfn[i]; - - /* Allocate enough memory to hold L2 page tables for node. */ - init_prealloc_ptes(i, end_pfn - pfn); - - address = (unsigned long) pfn_to_kaddr(pfn); - while (pfn < end_pfn) { - BUG_ON(address & (HPAGE_SIZE-1)); - pmd = get_pmd(pgtables, address); - pte = get_prealloc_pte(pfn); - if (pfn < end_huge_pfn) { - pgprot_t prot = init_pgprot(address); - *(pte_t *)pmd = pte_mkhuge(pfn_pte(pfn, prot)); - for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE; - pfn++, pte_ofs++, address += PAGE_SIZE) - pte[pte_ofs] = pfn_pte(pfn, prot); - } else { - if (kdata_huge) - printk(KERN_DEBUG "pre-shattered huge page at %#lx\n", - address); - for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE; - pfn++, pte_ofs++, address += PAGE_SIZE) { - pgprot_t prot = init_pgprot(address); - pte[pte_ofs] = pfn_pte(pfn, prot); - } - assign_pte(pmd, pte); - } - } - } - - /* - * Set or check ktext_map now that we have cpu_possible_mask - * and kstripe_mask to work with. - */ - if (ktext_all) - cpumask_copy(&ktext_mask, cpu_possible_mask); - else if (ktext_nondataplane) - ktext_mask = kstripe_mask; - else if (!cpumask_empty(&ktext_mask)) { - /* Sanity-check any mask that was requested */ - struct cpumask bad; - cpumask_andnot(&bad, &ktext_mask, cpu_possible_mask); - cpumask_and(&ktext_mask, &ktext_mask, cpu_possible_mask); - if (!cpumask_empty(&bad)) - pr_info("ktext: not using unavailable cpus %*pbl\n", - cpumask_pr_args(&bad)); - if (cpumask_empty(&ktext_mask)) { - pr_warn("ktext: no valid cpus; caching on %d\n", - smp_processor_id()); - cpumask_copy(&ktext_mask, - cpumask_of(smp_processor_id())); - } - } - - address = MEM_SV_START; - pmd = get_pmd(pgtables, address); - pfn = 0; /* code starts at PA 0 */ - if (ktext_small) { - /* Allocate an L2 PTE for the kernel text */ - int cpu = 0; - pgprot_t prot = construct_pgprot(PAGE_KERNEL_EXEC, - PAGE_HOME_IMMUTABLE); - - if (ktext_local) { - if (ktext_nocache) - prot = hv_pte_set_mode(prot, - HV_PTE_MODE_UNCACHED); - else - prot = hv_pte_set_mode(prot, - HV_PTE_MODE_CACHE_NO_L3); - } else { - prot = hv_pte_set_mode(prot, - HV_PTE_MODE_CACHE_TILE_L3); - cpu = cpumask_first(&ktext_mask); - - prot = ktext_set_nocache(prot); - } - - BUG_ON(address != (unsigned long)_text); - pte = NULL; - for (; address < (unsigned long)_einittext; - pfn++, address += PAGE_SIZE) { - pte_ofs = pte_index(address); - if (pte_ofs == 0) { - if (pte) - assign_pte(pmd++, pte); - pte = alloc_pte(); - } - if (!ktext_local) { - prot = set_remote_cache_cpu(prot, cpu); - cpu = cpumask_next(cpu, &ktext_mask); - if (cpu == NR_CPUS) - cpu = cpumask_first(&ktext_mask); - } - pte[pte_ofs] = pfn_pte(pfn, prot); - } - if (pte) - assign_pte(pmd, pte); - } else { - pte_t pteval = pfn_pte(0, PAGE_KERNEL_EXEC); - pteval = pte_mkhuge(pteval); - if (ktext_hash) { - pteval = hv_pte_set_mode(pteval, - HV_PTE_MODE_CACHE_HASH_L3); - pteval = ktext_set_nocache(pteval); - } else - if (cpumask_weight(&ktext_mask) == 1) { - pteval = set_remote_cache_cpu(pteval, - cpumask_first(&ktext_mask)); - pteval = hv_pte_set_mode(pteval, - HV_PTE_MODE_CACHE_TILE_L3); - pteval = ktext_set_nocache(pteval); - } else if (ktext_nocache) - pteval = hv_pte_set_mode(pteval, - HV_PTE_MODE_UNCACHED); - else - pteval = hv_pte_set_mode(pteval, - HV_PTE_MODE_CACHE_NO_L3); - for (; address < (unsigned long)_einittext; - pfn += PFN_DOWN(HPAGE_SIZE), address += HPAGE_SIZE) - *(pte_t *)(pmd++) = pfn_pte(pfn, pteval); - } - - /* Set swapper_pgprot here so it is flushed to memory right away. */ - swapper_pgprot = init_pgprot((unsigned long)swapper_pg_dir); - - /* - * Since we may be changing the caching of the stack and page - * table itself, we invoke an assembly helper to do the - * following steps: - * - * - flush the cache so we start with an empty slate - * - install pgtables[] as the real page table - * - flush the TLB so the new page table takes effect - */ - irqmask = interrupt_mask_save_mask(); - interrupt_mask_set_mask(-1ULL); - rc = flush_and_install_context(__pa(pgtables), - init_pgprot((unsigned long)pgtables), - __this_cpu_read(current_asid), - cpumask_bits(my_cpu_mask)); - interrupt_mask_restore_mask(irqmask); - BUG_ON(rc != 0); - - /* Copy the page table back to the normal swapper_pg_dir. */ - memcpy(pgd_base, pgtables, sizeof(pgtables)); - __install_page_table(pgd_base, __this_cpu_read(current_asid), - swapper_pgprot); - - /* - * We just read swapper_pgprot and thus brought it into the cache, - * with its new home & caching mode. When we start the other CPUs, - * they're going to reference swapper_pgprot via their initial fake - * VA-is-PA mappings, which cache everything locally. At that - * time, if it's in our cache with a conflicting home, the - * simulator's coherence checker will complain. So, flush it out - * of our cache; we're not going to ever use it again anyway. - */ - __insn_finv(&swapper_pgprot); -} - -/* - * devmem_is_allowed() checks to see if /dev/mem access to a certain address - * is valid. The argument is a physical page number. - * - * On Tile, the only valid things for which we can just hand out unchecked - * PTEs are the kernel code and data. Anything else might change its - * homing with time, and we wouldn't know to adjust the /dev/mem PTEs. - * Note that init_thread_union is released to heap soon after boot, - * so we include it in the init data. - * - * For TILE-Gx, we might want to consider allowing access to PA - * regions corresponding to PCI space, etc. - */ -int devmem_is_allowed(unsigned long pagenr) -{ - return pagenr < kaddr_to_pfn(_end) && - !(pagenr >= kaddr_to_pfn(&init_thread_union) || - pagenr < kaddr_to_pfn(__init_end)) && - !(pagenr >= kaddr_to_pfn(_sinittext) || - pagenr <= kaddr_to_pfn(_einittext-1)); -} - -#ifdef CONFIG_HIGHMEM -static void __init permanent_kmaps_init(pgd_t *pgd_base) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; - unsigned long vaddr; - - vaddr = PKMAP_BASE; - page_table_range_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, pgd_base); - - pgd = swapper_pg_dir + pgd_index(vaddr); - pud = pud_offset(pgd, vaddr); - pmd = pmd_offset(pud, vaddr); - pte = pte_offset_kernel(pmd, vaddr); - pkmap_page_table = pte; -} -#endif /* CONFIG_HIGHMEM */ - - -#ifndef CONFIG_64BIT -static void __init init_free_pfn_range(unsigned long start, unsigned long end) -{ - unsigned long pfn; - struct page *page = pfn_to_page(start); - - for (pfn = start; pfn < end; ) { - /* Optimize by freeing pages in large batches */ - int order = __ffs(pfn); - int count, i; - struct page *p; - - if (order >= MAX_ORDER) - order = MAX_ORDER-1; - count = 1 << order; - while (pfn + count > end) { - count >>= 1; - --order; - } - for (p = page, i = 0; i < count; ++i, ++p) { - __ClearPageReserved(p); - /* - * Hacky direct set to avoid unnecessary - * lock take/release for EVERY page here. - */ - p->_refcount.counter = 0; - p->_mapcount.counter = -1; - } - init_page_count(page); - __free_pages(page, order); - adjust_managed_page_count(page, count); - - page += count; - pfn += count; - } -} - -static void __init set_non_bootmem_pages_init(void) -{ - struct zone *z; - for_each_zone(z) { - unsigned long start, end; - int nid = z->zone_pgdat->node_id; -#ifdef CONFIG_HIGHMEM - int idx = zone_idx(z); -#endif - - start = z->zone_start_pfn; - end = start + z->spanned_pages; - start = max(start, node_free_pfn[nid]); - start = max(start, max_low_pfn); - -#ifdef CONFIG_HIGHMEM - if (idx == ZONE_HIGHMEM) - totalhigh_pages += z->spanned_pages; -#endif - if (kdata_huge) { - unsigned long percpu_pfn = node_percpu_pfn[nid]; - if (start < percpu_pfn && end > percpu_pfn) - end = percpu_pfn; - } -#ifdef CONFIG_PCI - if (start <= pci_reserve_start_pfn && - end > pci_reserve_start_pfn) { - if (end > pci_reserve_end_pfn) - init_free_pfn_range(pci_reserve_end_pfn, end); - end = pci_reserve_start_pfn; - } -#endif - init_free_pfn_range(start, end); - } -} -#endif - -/* - * paging_init() sets up the page tables - note that all of lowmem is - * already mapped by head.S. - */ -void __init paging_init(void) -{ -#ifdef __tilegx__ - pud_t *pud; -#endif - pgd_t *pgd_base = swapper_pg_dir; - - kernel_physical_mapping_init(pgd_base); - - /* Fixed mappings, only the page table structure has to be created. */ - page_table_range_init(fix_to_virt(__end_of_fixed_addresses - 1), - FIXADDR_TOP, pgd_base); - -#ifdef CONFIG_HIGHMEM - permanent_kmaps_init(pgd_base); -#endif - -#ifdef __tilegx__ - /* - * Since GX allocates just one pmd_t array worth of vmalloc space, - * we go ahead and allocate it statically here, then share it - * globally. As a result we don't have to worry about any task - * changing init_mm once we get up and running, and there's no - * need for e.g. vmalloc_sync_all(). - */ - BUILD_BUG_ON(pgd_index(VMALLOC_START) != pgd_index(VMALLOC_END - 1)); - pud = pud_offset(pgd_base + pgd_index(VMALLOC_START), VMALLOC_START); - assign_pmd(pud, alloc_pmd()); -#endif -} - - -/* - * Walk the kernel page tables and derive the page_home() from - * the PTEs, so that set_pte() can properly validate the caching - * of all PTEs it sees. - */ -void __init set_page_homes(void) -{ -} - -static void __init set_max_mapnr_init(void) -{ -#ifdef CONFIG_FLATMEM - max_mapnr = max_low_pfn; -#endif -} - -void __init mem_init(void) -{ - int i; -#ifndef __tilegx__ - void *last; -#endif - -#ifdef CONFIG_FLATMEM - BUG_ON(!mem_map); -#endif - -#ifdef CONFIG_HIGHMEM - /* check that fixmap and pkmap do not overlap */ - if (PKMAP_ADDR(LAST_PKMAP-1) >= FIXADDR_START) { - pr_err("fixmap and kmap areas overlap - this will crash\n"); - pr_err("pkstart: %lxh pkend: %lxh fixstart %lxh\n", - PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP-1), FIXADDR_START); - BUG(); - } -#endif - - set_max_mapnr_init(); - - /* this will put all bootmem onto the freelists */ - free_all_bootmem(); - -#ifndef CONFIG_64BIT - /* count all remaining LOWMEM and give all HIGHMEM to page allocator */ - set_non_bootmem_pages_init(); -#endif - - mem_init_print_info(NULL); - - /* - * In debug mode, dump some interesting memory mappings. - */ -#ifdef CONFIG_HIGHMEM - printk(KERN_DEBUG " KMAP %#lx - %#lx\n", - FIXADDR_START, FIXADDR_TOP + PAGE_SIZE - 1); - printk(KERN_DEBUG " PKMAP %#lx - %#lx\n", - PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP) - 1); -#endif - printk(KERN_DEBUG " VMALLOC %#lx - %#lx\n", - _VMALLOC_START, _VMALLOC_END - 1); -#ifdef __tilegx__ - for (i = MAX_NUMNODES-1; i >= 0; --i) { - struct pglist_data *node = &node_data[i]; - if (node->node_present_pages) { - unsigned long start = (unsigned long) - pfn_to_kaddr(node->node_start_pfn); - unsigned long end = start + - (node->node_present_pages << PAGE_SHIFT); - printk(KERN_DEBUG " MEM%d %#lx - %#lx\n", - i, start, end - 1); - } - } -#else - last = high_memory; - for (i = MAX_NUMNODES-1; i >= 0; --i) { - if ((unsigned long)vbase_map[i] != -1UL) { - printk(KERN_DEBUG " LOWMEM%d %#lx - %#lx\n", - i, (unsigned long) (vbase_map[i]), - (unsigned long) (last-1)); - last = vbase_map[i]; - } - } -#endif - -#ifndef __tilegx__ - /* - * Convert from using one lock for all atomic operations to - * one per cpu. - */ - __init_atomic_per_cpu(); -#endif -} - -struct kmem_cache *pgd_cache; - -void __init pgtable_cache_init(void) -{ - pgd_cache = kmem_cache_create("pgd", SIZEOF_PGD, SIZEOF_PGD, 0, NULL); - if (!pgd_cache) - panic("pgtable_cache_init(): Cannot create pgd cache"); -} - -static long __ro_after_init initfree = 1; -static bool __ro_after_init set_initfree_done; - -/* Select whether to free (1) or mark unusable (0) the __init pages. */ -static int __init set_initfree(char *str) -{ - long val; - if (kstrtol(str, 0, &val) == 0) { - set_initfree_done = true; - initfree = val; - pr_info("initfree: %s free init pages\n", - initfree ? "will" : "won't"); - } - return 1; -} -__setup("initfree=", set_initfree); - -static void free_init_pages(char *what, unsigned long begin, unsigned long end) -{ - unsigned long addr = (unsigned long) begin; - - /* Prefer user request first */ - if (!set_initfree_done) { - if (debug_pagealloc_enabled()) - initfree = 0; - } - if (kdata_huge && !initfree) { - pr_warn("Warning: ignoring initfree=0: incompatible with kdata=huge\n"); - initfree = 1; - } - end = (end + PAGE_SIZE - 1) & PAGE_MASK; - local_flush_tlb_pages(NULL, begin, PAGE_SIZE, end - begin); - for (addr = begin; addr < end; addr += PAGE_SIZE) { - /* - * Note we just reset the home here directly in the - * page table. We know this is safe because our caller - * just flushed the caches on all the other cpus, - * and they won't be touching any of these pages. - */ - int pfn = kaddr_to_pfn((void *)addr); - struct page *page = pfn_to_page(pfn); - pte_t *ptep = virt_to_kpte(addr); - if (!initfree) { - /* - * If debugging page accesses then do not free - * this memory but mark them not present - any - * buggy init-section access will create a - * kernel page fault: - */ - pte_clear(&init_mm, addr, ptep); - continue; - } - if (pte_huge(*ptep)) - BUG_ON(!kdata_huge); - else - set_pte_at(&init_mm, addr, ptep, - pfn_pte(pfn, PAGE_KERNEL)); - memset((void *)addr, POISON_FREE_INITMEM, PAGE_SIZE); - free_reserved_page(page); - } - pr_info("Freeing %s: %ldk freed\n", what, (end - begin) >> 10); -} - -void free_initmem(void) -{ - const unsigned long text_delta = MEM_SV_START - PAGE_OFFSET; - - /* - * Evict the cache on all cores to avoid incoherence. - * We are guaranteed that no one will touch the init pages any more. - */ - homecache_evict(&cpu_cacheable_map); - - /* Free the data pages that we won't use again after init. */ - free_init_pages("unused kernel data", - (unsigned long)__init_begin, - (unsigned long)__init_end); - - /* - * Free the pages mapped from 0xc0000000 that correspond to code - * pages from MEM_SV_START that we won't use again after init. - */ - free_init_pages("unused kernel text", - (unsigned long)_sinittext - text_delta, - (unsigned long)_einittext - text_delta); - /* Do a global TLB flush so everyone sees the changes. */ - flush_tlb_all(); -} diff --git a/arch/tile/mm/migrate.h b/arch/tile/mm/migrate.h deleted file mode 100644 index 91683d97917e..000000000000 --- a/arch/tile/mm/migrate.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Structure definitions for migration, exposed here for use by - * arch/tile/kernel/asm-offsets.c. - */ - -#ifndef MM_MIGRATE_H -#define MM_MIGRATE_H - -#include -#include - -/* - * This function is used as a helper when setting up the initial - * page table (swapper_pg_dir). - * - * You must mask ALL interrupts prior to invoking this code, since - * you can't legally touch the stack during the cache flush. - */ -extern int flush_and_install_context(HV_PhysAddr page_table, HV_PTE access, - HV_ASID asid, - const unsigned long *cpumask); - -/* - * This function supports migration as a "helper" as follows: - * - * - Set the stack PTE itself to "migrating". - * - Do a global TLB flush for (va,length) and the specified ASIDs. - * - Do a cache-evict on all necessary cpus. - * - Write the new stack PTE. - * - * Note that any non-NULL pointers must not point to the page that - * is handled by the stack_pte itself. - * - * You must mask ALL interrupts prior to invoking this code, since - * you can't legally touch the stack during the cache flush. - */ -extern int homecache_migrate_stack_and_flush(pte_t stack_pte, unsigned long va, - size_t length, pte_t *stack_ptep, - const struct cpumask *cache_cpumask, - const struct cpumask *tlb_cpumask, - HV_Remote_ASID *asids, - int asidcount); - -#endif /* MM_MIGRATE_H */ diff --git a/arch/tile/mm/migrate_32.S b/arch/tile/mm/migrate_32.S deleted file mode 100644 index 772085491bf9..000000000000 --- a/arch/tile/mm/migrate_32.S +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * This routine is a helper for migrating the home of a set of pages to - * a new cpu. See the documentation in homecache.c for more information. - */ - -#include -#include -#include -#include -#include -#include -#include - - .text - -/* - * First, some definitions that apply to all the code in the file. - */ - -/* Locals (caller-save) */ -#define r_tmp r10 -#define r_save_sp r11 - -/* What we save where in the stack frame; must include all callee-saves. */ -#define FRAME_SP 4 -#define FRAME_R30 8 -#define FRAME_R31 12 -#define FRAME_R32 16 -#define FRAME_R33 20 -#define FRAME_R34 24 -#define FRAME_SIZE 28 - - - - -/* - * On entry: - * - * r0 low word of the new context PA to install (moved to r_context_lo) - * r1 high word of the new context PA to install (moved to r_context_hi) - * r2 low word of PTE to use for context access (moved to r_access_lo) - * r3 high word of PTE to use for context access (moved to r_access_lo) - * r4 ASID to use for new context (moved to r_asid) - * r5 pointer to cpumask with just this cpu set in it (r_my_cpumask) - */ - -/* Arguments (caller-save) */ -#define r_context_lo_in r0 -#define r_context_hi_in r1 -#define r_access_lo_in r2 -#define r_access_hi_in r3 -#define r_asid_in r4 -#define r_my_cpumask r5 - -/* Locals (callee-save); must not be more than FRAME_xxx above. */ -#define r_context_lo r30 -#define r_context_hi r31 -#define r_access_lo r32 -#define r_access_hi r33 -#define r_asid r34 - -STD_ENTRY(flush_and_install_context) - /* - * Create a stack frame; we can't touch it once we flush the - * cache until we install the new page table and flush the TLB. - */ - { - move r_save_sp, sp - sw sp, lr - addi sp, sp, -FRAME_SIZE - } - addi r_tmp, sp, FRAME_SP - { - sw r_tmp, r_save_sp - addi r_tmp, sp, FRAME_R30 - } - { - sw r_tmp, r30 - addi r_tmp, sp, FRAME_R31 - } - { - sw r_tmp, r31 - addi r_tmp, sp, FRAME_R32 - } - { - sw r_tmp, r32 - addi r_tmp, sp, FRAME_R33 - } - { - sw r_tmp, r33 - addi r_tmp, sp, FRAME_R34 - } - sw r_tmp, r34 - - /* Move some arguments to callee-save registers. */ - { - move r_context_lo, r_context_lo_in - move r_context_hi, r_context_hi_in - } - { - move r_access_lo, r_access_lo_in - move r_access_hi, r_access_hi_in - } - move r_asid, r_asid_in - - /* First, flush our L2 cache. */ - { - move r0, zero /* cache_pa */ - move r1, zero - } - { - auli r2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */ - move r3, r_my_cpumask /* cache_cpumask */ - } - { - move r4, zero /* tlb_va */ - move r5, zero /* tlb_length */ - } - { - move r6, zero /* tlb_pgsize */ - move r7, zero /* tlb_cpumask */ - } - { - move r8, zero /* asids */ - move r9, zero /* asidcount */ - } - jal _hv_flush_remote - bnz r0, .Ldone - - /* Now install the new page table. */ - { - move r0, r_context_lo - move r1, r_context_hi - } - { - move r2, r_access_lo - move r3, r_access_hi - } - { - move r4, r_asid - moveli r5, HV_CTX_DIRECTIO | CTX_PAGE_FLAG - } - jal _hv_install_context - bnz r0, .Ldone - - /* Finally, flush the TLB. */ - { - movei r0, 0 /* preserve_global */ - jal hv_flush_all - } - -.Ldone: - /* Restore the callee-saved registers and return. */ - addli lr, sp, FRAME_SIZE - { - lw lr, lr - addli r_tmp, sp, FRAME_R30 - } - { - lw r30, r_tmp - addli r_tmp, sp, FRAME_R31 - } - { - lw r31, r_tmp - addli r_tmp, sp, FRAME_R32 - } - { - lw r32, r_tmp - addli r_tmp, sp, FRAME_R33 - } - { - lw r33, r_tmp - addli r_tmp, sp, FRAME_R34 - } - { - lw r34, r_tmp - addi sp, sp, FRAME_SIZE - } - jrp lr - STD_ENDPROC(flush_and_install_context) diff --git a/arch/tile/mm/migrate_64.S b/arch/tile/mm/migrate_64.S deleted file mode 100644 index a49eee38f872..000000000000 --- a/arch/tile/mm/migrate_64.S +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright 2011 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * This routine is a helper for migrating the home of a set of pages to - * a new cpu. See the documentation in homecache.c for more information. - */ - -#include -#include -#include -#include -#include -#include -#include - - .text - -/* - * First, some definitions that apply to all the code in the file. - */ - -/* Locals (caller-save) */ -#define r_tmp r10 -#define r_save_sp r11 - -/* What we save where in the stack frame; must include all callee-saves. */ -#define FRAME_SP 8 -#define FRAME_R30 16 -#define FRAME_R31 24 -#define FRAME_R32 32 -#define FRAME_SIZE 40 - - - - -/* - * On entry: - * - * r0 the new context PA to install (moved to r_context) - * r1 PTE to use for context access (moved to r_access) - * r2 ASID to use for new context (moved to r_asid) - * r3 pointer to cpumask with just this cpu set in it (r_my_cpumask) - */ - -/* Arguments (caller-save) */ -#define r_context_in r0 -#define r_access_in r1 -#define r_asid_in r2 -#define r_my_cpumask r3 - -/* Locals (callee-save); must not be more than FRAME_xxx above. */ -#define r_context r30 -#define r_access r31 -#define r_asid r32 - -/* - * Caller-save locals and frame constants are the same as - * for homecache_migrate_stack_and_flush. - */ - -STD_ENTRY(flush_and_install_context) - /* - * Create a stack frame; we can't touch it once we flush the - * cache until we install the new page table and flush the TLB. - */ - { - move r_save_sp, sp - st sp, lr - addi sp, sp, -FRAME_SIZE - } - addi r_tmp, sp, FRAME_SP - { - st r_tmp, r_save_sp - addi r_tmp, sp, FRAME_R30 - } - { - st r_tmp, r30 - addi r_tmp, sp, FRAME_R31 - } - { - st r_tmp, r31 - addi r_tmp, sp, FRAME_R32 - } - st r_tmp, r32 - - /* Move some arguments to callee-save registers. */ - { - move r_context, r_context_in - move r_access, r_access_in - } - move r_asid, r_asid_in - - /* First, flush our L2 cache. */ - { - move r0, zero /* cache_pa */ - moveli r1, hw2_last(HV_FLUSH_EVICT_L2) /* cache_control */ - } - { - shl16insli r1, r1, hw1(HV_FLUSH_EVICT_L2) - move r2, r_my_cpumask /* cache_cpumask */ - } - { - shl16insli r1, r1, hw0(HV_FLUSH_EVICT_L2) - move r3, zero /* tlb_va */ - } - { - move r4, zero /* tlb_length */ - move r5, zero /* tlb_pgsize */ - } - { - move r6, zero /* tlb_cpumask */ - move r7, zero /* asids */ - } - { - move r8, zero /* asidcount */ - jal _hv_flush_remote - } - bnez r0, 1f - - /* Now install the new page table. */ - { - move r0, r_context - move r1, r_access - } - { - move r2, r_asid - moveli r3, HV_CTX_DIRECTIO | CTX_PAGE_FLAG - } - jal _hv_install_context - bnez r0, 1f - - /* Finally, flush the TLB. */ - { - movei r0, 0 /* preserve_global */ - jal hv_flush_all - } - -1: /* Restore the callee-saved registers and return. */ - addli lr, sp, FRAME_SIZE - { - ld lr, lr - addli r_tmp, sp, FRAME_R30 - } - { - ld r30, r_tmp - addli r_tmp, sp, FRAME_R31 - } - { - ld r31, r_tmp - addli r_tmp, sp, FRAME_R32 - } - { - ld r32, r_tmp - addi sp, sp, FRAME_SIZE - } - jrp lr - STD_ENDPROC(flush_and_install_context) diff --git a/arch/tile/mm/mmap.c b/arch/tile/mm/mmap.c deleted file mode 100644 index 8ab28167c44b..000000000000 --- a/arch/tile/mm/mmap.c +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - * - * Taken from the i386 architecture and simplified. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Top of mmap area (just below the process stack). - * - * Leave an at least ~128 MB hole. - */ -#define MIN_GAP (128*1024*1024) -#define MAX_GAP (TASK_SIZE/6*5) - -static inline unsigned long mmap_base(struct mm_struct *mm) -{ - unsigned long gap = rlimit(RLIMIT_STACK); - unsigned long random_factor = 0; - - if (current->flags & PF_RANDOMIZE) - random_factor = get_random_int() % (1024*1024); - - if (gap < MIN_GAP) - gap = MIN_GAP; - else if (gap > MAX_GAP) - gap = MAX_GAP; - - return PAGE_ALIGN(TASK_SIZE - gap - random_factor); -} - -/* - * This function, called very early during the creation of a new - * process VM image, sets up which VM layout function to use: - */ -void arch_pick_mmap_layout(struct mm_struct *mm) -{ -#if !defined(__tilegx__) - int is_32bit = 1; -#elif defined(CONFIG_COMPAT) - int is_32bit = is_compat_task(); -#else - int is_32bit = 0; -#endif - unsigned long random_factor = 0UL; - - /* - * 8 bits of randomness in 32bit mmaps, 24 address space bits - * 12 bits of randomness in 64bit mmaps, 28 address space bits - */ - if (current->flags & PF_RANDOMIZE) { - if (is_32bit) - random_factor = get_random_int() % (1<<8); - else - random_factor = get_random_int() % (1<<12); - - random_factor <<= PAGE_SHIFT; - } - - /* - * Use standard layout if the expected stack growth is unlimited - * or we are running native 64 bits. - */ - if (rlimit(RLIMIT_STACK) == RLIM_INFINITY) { - mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; - mm->get_unmapped_area = arch_get_unmapped_area; - } else { - mm->mmap_base = mmap_base(mm); - mm->get_unmapped_area = arch_get_unmapped_area_topdown; - } -} - -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - return randomize_page(mm->brk, 0x02000000); -} diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c deleted file mode 100644 index ec5576fd3a86..000000000000 --- a/arch/tile/mm/pgtable.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define K(x) ((x) << (PAGE_SHIFT-10)) - -/** - * shatter_huge_page() - ensure a given address is mapped by a small page. - * - * This function converts a huge PTE mapping kernel LOWMEM into a bunch - * of small PTEs with the same caching. No cache flush required, but we - * must do a global TLB flush. - * - * Any caller that wishes to modify a kernel mapping that might - * have been made with a huge page should call this function, - * since doing so properly avoids race conditions with installing the - * newly-shattered page and then flushing all the TLB entries. - * - * @addr: Address at which to shatter any existing huge page. - */ -void shatter_huge_page(unsigned long addr) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - unsigned long flags = 0; /* happy compiler */ -#ifdef __PAGETABLE_PMD_FOLDED - struct list_head *pos; -#endif - - /* Get a pointer to the pmd entry that we need to change. */ - addr &= HPAGE_MASK; - BUG_ON(pgd_addr_invalid(addr)); - BUG_ON(addr < PAGE_OFFSET); /* only for kernel LOWMEM */ - pgd = swapper_pg_dir + pgd_index(addr); - pud = pud_offset(pgd, addr); - BUG_ON(!pud_present(*pud)); - pmd = pmd_offset(pud, addr); - BUG_ON(!pmd_present(*pmd)); - if (!pmd_huge_page(*pmd)) - return; - - spin_lock_irqsave(&init_mm.page_table_lock, flags); - if (!pmd_huge_page(*pmd)) { - /* Lost the race to convert the huge page. */ - spin_unlock_irqrestore(&init_mm.page_table_lock, flags); - return; - } - - /* Shatter the huge page into the preallocated L2 page table. */ - pmd_populate_kernel(&init_mm, pmd, get_prealloc_pte(pmd_pfn(*pmd))); - -#ifdef __PAGETABLE_PMD_FOLDED - /* Walk every pgd on the system and update the pmd there. */ - spin_lock(&pgd_lock); - list_for_each(pos, &pgd_list) { - pmd_t *copy_pmd; - pgd = list_to_pgd(pos) + pgd_index(addr); - pud = pud_offset(pgd, addr); - copy_pmd = pmd_offset(pud, addr); - __set_pmd(copy_pmd, *pmd); - } - spin_unlock(&pgd_lock); -#endif - - /* Tell every cpu to notice the change. */ - flush_remote(0, 0, NULL, addr, HPAGE_SIZE, HPAGE_SIZE, - cpu_possible_mask, NULL, 0); - - /* Hold the lock until the TLB flush is finished to avoid races. */ - spin_unlock_irqrestore(&init_mm.page_table_lock, flags); -} - -/* - * List of all pgd's needed so it can invalidate entries in both cached - * and uncached pgd's. This is essentially codepath-based locking - * against pageattr.c; it is the unique case in which a valid change - * of kernel pagetables can't be lazily synchronized by vmalloc faults. - * vmalloc faults work because attached pagetables are never freed. - * - * The lock is always taken with interrupts disabled, unlike on x86 - * and other platforms, because we need to take the lock in - * shatter_huge_page(), which may be called from an interrupt context. - * We are not at risk from the tlbflush IPI deadlock that was seen on - * x86, since we use the flush_remote() API to have the hypervisor do - * the TLB flushes regardless of irq disabling. - */ -DEFINE_SPINLOCK(pgd_lock); -LIST_HEAD(pgd_list); - -static inline void pgd_list_add(pgd_t *pgd) -{ - list_add(pgd_to_list(pgd), &pgd_list); -} - -static inline void pgd_list_del(pgd_t *pgd) -{ - list_del(pgd_to_list(pgd)); -} - -#define KERNEL_PGD_INDEX_START pgd_index(PAGE_OFFSET) -#define KERNEL_PGD_PTRS (PTRS_PER_PGD - KERNEL_PGD_INDEX_START) - -static void pgd_ctor(pgd_t *pgd) -{ - unsigned long flags; - - memset(pgd, 0, KERNEL_PGD_INDEX_START*sizeof(pgd_t)); - spin_lock_irqsave(&pgd_lock, flags); - -#ifndef __tilegx__ - /* - * Check that the user interrupt vector has no L2. - * It never should for the swapper, and new page tables - * should always start with an empty user interrupt vector. - */ - BUG_ON(((u64 *)swapper_pg_dir)[pgd_index(MEM_USER_INTRPT)] != 0); -#endif - - memcpy(pgd + KERNEL_PGD_INDEX_START, - swapper_pg_dir + KERNEL_PGD_INDEX_START, - KERNEL_PGD_PTRS * sizeof(pgd_t)); - - pgd_list_add(pgd); - spin_unlock_irqrestore(&pgd_lock, flags); -} - -static void pgd_dtor(pgd_t *pgd) -{ - unsigned long flags; /* can be called from interrupt context */ - - spin_lock_irqsave(&pgd_lock, flags); - pgd_list_del(pgd); - spin_unlock_irqrestore(&pgd_lock, flags); -} - -pgd_t *pgd_alloc(struct mm_struct *mm) -{ - pgd_t *pgd = kmem_cache_alloc(pgd_cache, GFP_KERNEL); - if (pgd) - pgd_ctor(pgd); - return pgd; -} - -void pgd_free(struct mm_struct *mm, pgd_t *pgd) -{ - pgd_dtor(pgd); - kmem_cache_free(pgd_cache, pgd); -} - - -#define L2_USER_PGTABLE_PAGES (1 << L2_USER_PGTABLE_ORDER) - -struct page *pgtable_alloc_one(struct mm_struct *mm, unsigned long address, - int order) -{ - gfp_t flags = GFP_KERNEL|__GFP_ZERO; - struct page *p; - int i; - - p = alloc_pages(flags, L2_USER_PGTABLE_ORDER); - if (p == NULL) - return NULL; - - if (!pgtable_page_ctor(p)) { - __free_pages(p, L2_USER_PGTABLE_ORDER); - return NULL; - } - - /* - * Make every page have a page_count() of one, not just the first. - * We don't use __GFP_COMP since it doesn't look like it works - * correctly with tlb_remove_page(). - */ - for (i = 1; i < order; ++i) { - init_page_count(p+i); - inc_zone_page_state(p+i, NR_PAGETABLE); - } - - return p; -} - -/* - * Free page immediately (used in __pte_alloc if we raced with another - * process). We have to correct whatever pte_alloc_one() did before - * returning the pages to the allocator. - */ -void pgtable_free(struct mm_struct *mm, struct page *p, int order) -{ - int i; - - pgtable_page_dtor(p); - __free_page(p); - - for (i = 1; i < order; ++i) { - __free_page(p+i); - dec_zone_page_state(p+i, NR_PAGETABLE); - } -} - -void __pgtable_free_tlb(struct mmu_gather *tlb, struct page *pte, - unsigned long address, int order) -{ - int i; - - pgtable_page_dtor(pte); - tlb_remove_page(tlb, pte); - - for (i = 1; i < order; ++i) { - tlb_remove_page(tlb, pte + i); - dec_zone_page_state(pte + i, NR_PAGETABLE); - } -} - -#ifndef __tilegx__ - -/* - * FIXME: needs to be atomic vs hypervisor writes. For now we make the - * window of vulnerability a bit smaller by doing an unlocked 8-bit update. - */ -int ptep_test_and_clear_young(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep) -{ -#if HV_PTE_INDEX_ACCESSED < 8 || HV_PTE_INDEX_ACCESSED >= 16 -# error Code assumes HV_PTE "accessed" bit in second byte -#endif - u8 *tmp = (u8 *)ptep; - u8 second_byte = tmp[1]; - if (!(second_byte & (1 << (HV_PTE_INDEX_ACCESSED - 8)))) - return 0; - tmp[1] = second_byte & ~(1 << (HV_PTE_INDEX_ACCESSED - 8)); - return 1; -} - -/* - * This implementation is atomic vs hypervisor writes, since the hypervisor - * always writes the low word (where "accessed" and "dirty" are) and this - * routine only writes the high word. - */ -void ptep_set_wrprotect(struct mm_struct *mm, - unsigned long addr, pte_t *ptep) -{ -#if HV_PTE_INDEX_WRITABLE < 32 -# error Code assumes HV_PTE "writable" bit in high word -#endif - u32 *tmp = (u32 *)ptep; - tmp[1] = tmp[1] & ~(1 << (HV_PTE_INDEX_WRITABLE - 32)); -} - -#endif - -/* - * Return a pointer to the PTE that corresponds to the given - * address in the given page table. A NULL page table just uses - * the standard kernel page table; the preferred API in this case - * is virt_to_kpte(). - * - * The returned pointer can point to a huge page in other levels - * of the page table than the bottom, if the huge page is present - * in the page table. For bottom-level PTEs, the returned pointer - * can point to a PTE that is either present or not. - */ -pte_t *virt_to_pte(struct mm_struct* mm, unsigned long addr) -{ - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - - if (pgd_addr_invalid(addr)) - return NULL; - - pgd = mm ? pgd_offset(mm, addr) : swapper_pg_dir + pgd_index(addr); - pud = pud_offset(pgd, addr); - if (!pud_present(*pud)) - return NULL; - if (pud_huge_page(*pud)) - return (pte_t *)pud; - pmd = pmd_offset(pud, addr); - if (!pmd_present(*pmd)) - return NULL; - if (pmd_huge_page(*pmd)) - return (pte_t *)pmd; - return pte_offset_kernel(pmd, addr); -} -EXPORT_SYMBOL(virt_to_pte); - -pte_t *virt_to_kpte(unsigned long kaddr) -{ - BUG_ON(kaddr < PAGE_OFFSET); - return virt_to_pte(NULL, kaddr); -} -EXPORT_SYMBOL(virt_to_kpte); - -pgprot_t set_remote_cache_cpu(pgprot_t prot, int cpu) -{ - unsigned int width = smp_width; - int x = cpu % width; - int y = cpu / width; - BUG_ON(y >= smp_height); - BUG_ON(hv_pte_get_mode(prot) != HV_PTE_MODE_CACHE_TILE_L3); - BUG_ON(cpu < 0 || cpu >= NR_CPUS); - BUG_ON(!cpu_is_valid_lotar(cpu)); - return hv_pte_set_lotar(prot, HV_XY_TO_LOTAR(x, y)); -} - -int get_remote_cache_cpu(pgprot_t prot) -{ - HV_LOTAR lotar = hv_pte_get_lotar(prot); - int x = HV_LOTAR_X(lotar); - int y = HV_LOTAR_Y(lotar); - BUG_ON(hv_pte_get_mode(prot) != HV_PTE_MODE_CACHE_TILE_L3); - return x + y * smp_width; -} - -/* - * Convert a kernel VA to a PA and homing information. - */ -int va_to_cpa_and_pte(void *va, unsigned long long *cpa, pte_t *pte) -{ - struct page *page = virt_to_page(va); - pte_t null_pte = { 0 }; - - *cpa = __pa(va); - - /* Note that this is not writing a page table, just returning a pte. */ - *pte = pte_set_home(null_pte, page_home(page)); - - return 0; /* return non-zero if not hfh? */ -} -EXPORT_SYMBOL(va_to_cpa_and_pte); - -void __set_pte(pte_t *ptep, pte_t pte) -{ -#ifdef __tilegx__ - *ptep = pte; -#else -# if HV_PTE_INDEX_PRESENT >= 32 || HV_PTE_INDEX_MIGRATING >= 32 -# error Must write the present and migrating bits last -# endif - if (pte_present(pte)) { - ((u32 *)ptep)[1] = (u32)(pte_val(pte) >> 32); - barrier(); - ((u32 *)ptep)[0] = (u32)(pte_val(pte)); - } else { - ((u32 *)ptep)[0] = (u32)(pte_val(pte)); - barrier(); - ((u32 *)ptep)[1] = (u32)(pte_val(pte) >> 32); - } -#endif /* __tilegx__ */ -} - -void set_pte(pte_t *ptep, pte_t pte) -{ - if (pte_present(pte) && - (!CHIP_HAS_MMIO() || hv_pte_get_mode(pte) != HV_PTE_MODE_MMIO)) { - /* The PTE actually references physical memory. */ - unsigned long pfn = pte_pfn(pte); - if (pfn_valid(pfn)) { - /* Update the home of the PTE from the struct page. */ - pte = pte_set_home(pte, page_home(pfn_to_page(pfn))); - } else if (hv_pte_get_mode(pte) == 0) { - /* remap_pfn_range(), etc, must supply PTE mode. */ - panic("set_pte(): out-of-range PFN and mode 0\n"); - } - } - - __set_pte(ptep, pte); -} - -/* Can this mm load a PTE with cached_priority set? */ -static inline int mm_is_priority_cached(struct mm_struct *mm) -{ - return mm->context.priority_cached != 0; -} - -/* - * Add a priority mapping to an mm_context and - * notify the hypervisor if this is the first one. - */ -void start_mm_caching(struct mm_struct *mm) -{ - if (!mm_is_priority_cached(mm)) { - mm->context.priority_cached = -1UL; - hv_set_caching(-1UL); - } -} - -/* - * Validate and return the priority_cached flag. We know if it's zero - * that we don't need to scan, since we immediately set it non-zero - * when we first consider a MAP_CACHE_PRIORITY mapping. - * - * We only _try_ to acquire the mmap_sem semaphore; if we can't acquire it, - * since we're in an interrupt context (servicing switch_mm) we don't - * worry about it and don't unset the "priority_cached" field. - * Presumably we'll come back later and have more luck and clear - * the value then; for now we'll just keep the cache marked for priority. - */ -static unsigned long update_priority_cached(struct mm_struct *mm) -{ - if (mm->context.priority_cached && down_write_trylock(&mm->mmap_sem)) { - struct vm_area_struct *vm; - for (vm = mm->mmap; vm; vm = vm->vm_next) { - if (hv_pte_get_cached_priority(vm->vm_page_prot)) - break; - } - if (vm == NULL) - mm->context.priority_cached = 0; - up_write(&mm->mmap_sem); - } - return mm->context.priority_cached; -} - -/* Set caching correctly for an mm that we are switching to. */ -void check_mm_caching(struct mm_struct *prev, struct mm_struct *next) -{ - if (!mm_is_priority_cached(next)) { - /* - * If the new mm doesn't use priority caching, just see if we - * need the hv_set_caching(), or can assume it's already zero. - */ - if (mm_is_priority_cached(prev)) - hv_set_caching(0); - } else { - hv_set_caching(update_priority_cached(next)); - } -} - -#if CHIP_HAS_MMIO() - -/* Map an arbitrary MMIO address, homed according to pgprot, into VA space. */ -void __iomem *ioremap_prot(resource_size_t phys_addr, unsigned long size, - pgprot_t home) -{ - void *addr; - struct vm_struct *area; - unsigned long offset, last_addr; - pgprot_t pgprot; - - /* Don't allow wraparound or zero size */ - last_addr = phys_addr + size - 1; - if (!size || last_addr < phys_addr) - return NULL; - - /* Create a read/write, MMIO VA mapping homed at the requested shim. */ - pgprot = PAGE_KERNEL; - pgprot = hv_pte_set_mode(pgprot, HV_PTE_MODE_MMIO); - pgprot = hv_pte_set_lotar(pgprot, hv_pte_get_lotar(home)); - - /* - * Mappings have to be page-aligned - */ - offset = phys_addr & ~PAGE_MASK; - phys_addr &= PAGE_MASK; - size = PAGE_ALIGN(last_addr+1) - phys_addr; - - /* - * Ok, go for it.. - */ - area = get_vm_area(size, VM_IOREMAP /* | other flags? */); - if (!area) - return NULL; - area->phys_addr = phys_addr; - addr = area->addr; - if (ioremap_page_range((unsigned long)addr, (unsigned long)addr + size, - phys_addr, pgprot)) { - free_vm_area(area); - return NULL; - } - return (__force void __iomem *) (offset + (char *)addr); -} -EXPORT_SYMBOL(ioremap_prot); - -#if !defined(CONFIG_PCI) || !defined(CONFIG_TILEGX) -/* ioremap is conditionally declared in pci_gx.c */ - -void __iomem *ioremap(resource_size_t phys_addr, unsigned long size) -{ - return NULL; -} -EXPORT_SYMBOL(ioremap); - -#endif - -/* Unmap an MMIO VA mapping. */ -void iounmap(volatile void __iomem *addr_in) -{ - volatile void __iomem *addr = (volatile void __iomem *) - (PAGE_MASK & (unsigned long __force)addr_in); -#if 1 - vunmap((void * __force)addr); -#else - /* x86 uses this complicated flow instead of vunmap(). Is - * there any particular reason we should do the same? */ - struct vm_struct *p, *o; - - /* Use the vm area unlocked, assuming the caller - ensures there isn't another iounmap for the same address - in parallel. Reuse of the virtual address is prevented by - leaving it in the global lists until we're done with it. - cpa takes care of the direct mappings. */ - p = find_vm_area((void *)addr); - - if (!p) { - pr_err("iounmap: bad address %p\n", addr); - dump_stack(); - return; - } - - /* Finally remove it */ - o = remove_vm_area((void *)addr); - BUG_ON(p != o || o == NULL); - kfree(p); -#endif -} -EXPORT_SYMBOL(iounmap); - -#endif /* CHIP_HAS_MMIO() */ diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 8b14bd326d4a..5b997138e092 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2319,25 +2319,6 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82865_HB, DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82875_HB, quirk_unhide_mch_dev6); -#ifdef CONFIG_TILEPRO -/* - * The Tilera TILEmpower tilepro platform needs to set the link speed - * to 2.5GT(Giga-Transfers)/s (Gen 1). The default link speed - * setting is 5GT/s (Gen 2). 0x98 is the Link Control2 PCIe - * capability register of the PEX8624 PCIe switch. The switch - * supports link speed auto negotiation, but falsely sets - * the link speed to 5GT/s. - */ -static void quirk_tile_plx_gen1(struct pci_dev *dev) -{ - if (tile_plx_gen1) { - pci_write_config_dword(dev, 0x98, 0x1); - mdelay(50); - } -} -DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_PLX, 0x8624, quirk_tile_plx_gen1); -#endif /* CONFIG_TILEPRO */ - #ifdef CONFIG_PCI_MSI /* Some chipsets do not support MSI. We cannot easily rely on setting * PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually diff --git a/samples/kprobes/kprobe_example.c b/samples/kprobes/kprobe_example.c index 67de3b774bc9..02be8984c32f 100644 --- a/samples/kprobes/kprobe_example.c +++ b/samples/kprobes/kprobe_example.c @@ -38,10 +38,6 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs) pr_info("<%s> pre_handler: p->addr = 0x%p, epc = 0x%lx, status = 0x%lx\n", p->symbol_name, p->addr, regs->cp0_epc, regs->cp0_status); #endif -#ifdef CONFIG_TILEGX - pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx, ex1 = 0x%lx\n", - p->symbol_name, p->addr, regs->pc, regs->ex1); -#endif #ifdef CONFIG_ARM64 pr_info("<%s> pre_handler: p->addr = 0x%p, pc = 0x%lx," " pstate = 0x%lx\n", @@ -72,10 +68,6 @@ static void handler_post(struct kprobe *p, struct pt_regs *regs, pr_info("<%s> post_handler: p->addr = 0x%p, status = 0x%lx\n", p->symbol_name, p->addr, regs->cp0_status); #endif -#ifdef CONFIG_TILEGX - pr_info("<%s> post_handler: p->addr = 0x%p, ex1 = 0x%lx\n", - p->symbol_name, p->addr, regs->ex1); -#endif #ifdef CONFIG_ARM64 pr_info("<%s> post_handler: p->addr = 0x%p, pstate = 0x%lx\n", p->symbol_name, p->addr, (long)regs->pstate); diff --git a/tools/arch/tile/include/asm/barrier.h b/tools/arch/tile/include/asm/barrier.h deleted file mode 100644 index 7ad02a591b43..000000000000 --- a/tools/arch/tile/include/asm/barrier.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef _TOOLS_LINUX_ASM_TILE_BARRIER_H -#define _TOOLS_LINUX_ASM_TILE_BARRIER_H -/* - * FIXME: This came from tools/perf/perf-sys.h, where it was first introduced - * in 620830b6954913647b7c7f68920cf48eddf6ad92, more work needed to make it - * more closely follow the Linux kernel arch/tile/include/asm/barrier.h file. - * Probably when we continue work on tools/ Kconfig support to have all the - * CONFIG_ needed for properly doing that. - */ - -#define mb() asm volatile ("mf" ::: "memory") -#define wmb() mb() -#define rmb() mb() - -#endif /* _TOOLS_LINUX_ASM_TILE_BARRIER_H */ diff --git a/tools/arch/tile/include/uapi/asm/bitsperlong.h b/tools/arch/tile/include/uapi/asm/bitsperlong.h deleted file mode 100644 index 57cca78c0fbb..000000000000 --- a/tools/arch/tile/include/uapi/asm/bitsperlong.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -/* - * Copyright 2010 Tilera Corporation. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, version 2. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for - * more details. - */ - -#ifndef _ASM_TILE_BITSPERLONG_H -#define _ASM_TILE_BITSPERLONG_H - -#ifdef __LP64__ -# define __BITS_PER_LONG 64 -#else -# define __BITS_PER_LONG 32 -#endif - -#include - -#endif /* _ASM_TILE_BITSPERLONG_H */ diff --git a/tools/arch/tile/include/uapi/asm/mman.h b/tools/arch/tile/include/uapi/asm/mman.h deleted file mode 100644 index 65ec92925c6c..000000000000 --- a/tools/arch/tile/include/uapi/asm/mman.h +++ /dev/null @@ -1,16 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef TOOLS_ARCH_TILE_UAPI_ASM_MMAN_FIX_H -#define TOOLS_ARCH_TILE_UAPI_ASM_MMAN_FIX_H -#define MAP_DENYWRITE 0x0800 -#define MAP_EXECUTABLE 0x1000 -#define MAP_GROWSDOWN 0x0100 -#define MAP_HUGETLB 0x4000 -#define MAP_LOCKED 0x0200 -#define MAP_NONBLOCK 0x0080 -#define MAP_NORESERVE 0x0400 -#define MAP_POPULATE 0x0040 -#define MAP_STACK MAP_GROWSDOWN -#include -/* MAP_32BIT is undefined on tile, fix it for perf */ -#define MAP_32BIT 0 -#endif diff --git a/tools/scripts/Makefile.arch b/tools/scripts/Makefile.arch index 78d90a249e88..b10b7a27c33f 100644 --- a/tools/scripts/Makefile.arch +++ b/tools/scripts/Makefile.arch @@ -4,8 +4,7 @@ HOSTARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ -e /arm64/!s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ -e s/parisc64/parisc/ \ -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ - -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ \ - -e s/tile.*/tile/ ) + -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ ) ifndef ARCH ARCH := $(HOSTARCH) @@ -34,14 +33,6 @@ ifeq ($(ARCH),sh64) SRCARCH := sh endif -# Additional ARCH settings for tile -ifeq ($(ARCH),tilepro) - SRCARCH := tile -endif -ifeq ($(ARCH),tilegx) - SRCARCH := tile -endif - LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) ifeq ($(LP64), 1) IS_64_BIT := 1 diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 0c8b61f8398e..8809f244bb7c 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -3683,8 +3683,6 @@ sub read_depends { # what directory to look at. if ($arch eq "i386" || $arch eq "x86_64") { $arch = "x86"; - } elsif ($arch =~ /^tile/) { - $arch = "tile"; } my $kconfig = "$builddir/arch/$arch/Kconfig"; -- cgit v1.3-14-g43fede From 171a48717beeacb66be85c1e8e401111d3a0262c Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Mar 2018 08:29:39 -0700 Subject: selftests: fib_tests: Use an alias for ip command Replace 'ip -netns testns' with the alias IP. Shortens the line lengths and makes running the commands manually a bit easier. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 169 ++++++++++++++++--------------- 1 file changed, 85 insertions(+), 84 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index b617985ecdc1..953254439e39 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -7,6 +7,7 @@ ret=0 PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} +IP="ip -netns testns" log_test() { @@ -32,19 +33,19 @@ setup() { set -e ip netns add testns - ip -netns testns link set dev lo up + $IP link set dev lo up - ip -netns testns link add dummy0 type dummy - ip -netns testns link set dev dummy0 up - ip -netns testns address add 198.51.100.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:1::1/64 dev dummy0 + $IP link add dummy0 type dummy + $IP link set dev dummy0 up + $IP address add 198.51.100.1/24 dev dummy0 + $IP -6 address add 2001:db8:1::1/64 dev dummy0 set +e } cleanup() { - ip -netns testns link del dev dummy0 &> /dev/null + $IP link del dev dummy0 &> /dev/null ip netns del testns } @@ -56,19 +57,19 @@ fib_unreg_unicast_test() setup echo " Start point" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 0 "IPv6 fibmatch" set -e - ip -netns testns link del dev dummy0 + $IP link del dev dummy0 set +e echo " Nexthop device deleted" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 2 "IPv4 fibmatch - no route" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 2 "IPv6 fibmatch - no route" cleanup @@ -83,43 +84,43 @@ fib_unreg_multipath_test() setup set -e - ip -netns testns link add dummy1 type dummy - ip -netns testns link set dev dummy1 up - ip -netns testns address add 192.0.2.1/24 dev dummy1 - ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 + $IP link add dummy1 type dummy + $IP link set dev dummy1 up + $IP address add 192.0.2.1/24 dev dummy1 + $IP -6 address add 2001:db8:2::1/64 dev dummy1 - ip -netns testns route add 203.0.113.0/24 \ + $IP route add 203.0.113.0/24 \ nexthop via 198.51.100.2 dev dummy0 \ nexthop via 192.0.2.2 dev dummy1 - ip -netns testns -6 route add 2001:db8:3::/64 \ + $IP -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 set +e echo " Start point" - ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null + $IP route get fibmatch 203.0.113.1 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null log_test $? 0 "IPv6 fibmatch" set -e - ip -netns testns link del dev dummy0 + $IP link del dev dummy0 set +e echo " One nexthop device deleted" - ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null + $IP route get fibmatch 203.0.113.1 &> /dev/null log_test $? 2 "IPv4 - multipath route removed on delete" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null # In IPv6 we do not flush the entire multipath route. log_test $? 0 "IPv6 - multipath down to single path" set -e - ip -netns testns link del dev dummy1 + $IP link del dev dummy1 set +e echo " Second nexthop device deleted" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null log_test $? 2 "IPv6 - no route" cleanup @@ -139,19 +140,19 @@ fib_down_unicast_test() setup echo " Start point" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 0 "IPv6 fibmatch" set -e - ip -netns testns link set dev dummy0 down + $IP link set dev dummy0 down set +e echo " Route deleted on down" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 2 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 2 "IPv6 fibmatch" cleanup @@ -162,31 +163,31 @@ fib_down_multipath_test_do() local down_dev=$1 local up_dev=$2 - ip -netns testns route get fibmatch 203.0.113.1 \ + $IP route get fibmatch 203.0.113.1 \ oif $down_dev &> /dev/null log_test $? 2 "IPv4 fibmatch on down device" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ + $IP -6 route get fibmatch 2001:db8:3::1 \ oif $down_dev &> /dev/null log_test $? 2 "IPv6 fibmatch on down device" - ip -netns testns route get fibmatch 203.0.113.1 \ + $IP route get fibmatch 203.0.113.1 \ oif $up_dev &> /dev/null log_test $? 0 "IPv4 fibmatch on up device" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 \ + $IP -6 route get fibmatch 2001:db8:3::1 \ oif $up_dev &> /dev/null log_test $? 0 "IPv6 fibmatch on up device" - ip -netns testns route get fibmatch 203.0.113.1 | \ + $IP route get fibmatch 203.0.113.1 | \ grep $down_dev | grep -q "dead linkdown" log_test $? 0 "IPv4 flags on down device" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ + $IP -6 route get fibmatch 2001:db8:3::1 | \ grep $down_dev | grep -q "dead linkdown" log_test $? 0 "IPv6 flags on down device" - ip -netns testns route get fibmatch 203.0.113.1 | \ + $IP route get fibmatch 203.0.113.1 | \ grep $up_dev | grep -q "dead linkdown" log_test $? 1 "IPv4 flags on up device" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 | \ + $IP -6 route get fibmatch 2001:db8:3::1 | \ grep $up_dev | grep -q "dead linkdown" log_test $? 1 "IPv6 flags on up device" } @@ -199,53 +200,53 @@ fib_down_multipath_test() setup set -e - ip -netns testns link add dummy1 type dummy - ip -netns testns link set dev dummy1 up + $IP link add dummy1 type dummy + $IP link set dev dummy1 up - ip -netns testns address add 192.0.2.1/24 dev dummy1 - ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy1 + $IP address add 192.0.2.1/24 dev dummy1 + $IP -6 address add 2001:db8:2::1/64 dev dummy1 - ip -netns testns route add 203.0.113.0/24 \ + $IP route add 203.0.113.0/24 \ nexthop via 198.51.100.2 dev dummy0 \ nexthop via 192.0.2.2 dev dummy1 - ip -netns testns -6 route add 2001:db8:3::/64 \ + $IP -6 route add 2001:db8:3::/64 \ nexthop via 2001:db8:1::2 dev dummy0 \ nexthop via 2001:db8:2::2 dev dummy1 set +e echo " Verify start point" - ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null + $IP route get fibmatch 203.0.113.1 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null log_test $? 0 "IPv6 fibmatch" set -e - ip -netns testns link set dev dummy0 down + $IP link set dev dummy0 down set +e echo " One device down, one up" fib_down_multipath_test_do "dummy0" "dummy1" set -e - ip -netns testns link set dev dummy0 up - ip -netns testns link set dev dummy1 down + $IP link set dev dummy0 up + $IP link set dev dummy1 down set +e echo " Other device down and up" fib_down_multipath_test_do "dummy1" "dummy0" set -e - ip -netns testns link set dev dummy0 down + $IP link set dev dummy0 down set +e echo " Both devices down" - ip -netns testns route get fibmatch 203.0.113.1 &> /dev/null + $IP route get fibmatch 203.0.113.1 &> /dev/null log_test $? 2 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:3::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:3::1 &> /dev/null log_test $? 2 "IPv6 fibmatch" - ip -netns testns link del dev dummy1 + $IP link del dev dummy1 cleanup } @@ -264,55 +265,55 @@ fib_carrier_local_test() setup set -e - ip -netns testns link set dev dummy0 carrier on + $IP link set dev dummy0 carrier on set +e echo " Start point" - ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null + $IP route get fibmatch 198.51.100.1 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 198.51.100.1 | \ + $IP route get fibmatch 198.51.100.1 | \ grep -q "linkdown" log_test $? 1 "IPv4 - no linkdown flag" - ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ + $IP -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" log_test $? 1 "IPv6 - no linkdown flag" set -e - ip -netns testns link set dev dummy0 carrier off + $IP link set dev dummy0 carrier off sleep 1 set +e echo " Carrier off on nexthop" - ip -netns testns route get fibmatch 198.51.100.1 &> /dev/null + $IP route get fibmatch 198.51.100.1 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::1 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 198.51.100.1 | \ + $IP route get fibmatch 198.51.100.1 | \ grep -q "linkdown" log_test $? 1 "IPv4 - linkdown flag set" - ip -netns testns -6 route get fibmatch 2001:db8:1::1 | \ + $IP -6 route get fibmatch 2001:db8:1::1 | \ grep -q "linkdown" log_test $? 1 "IPv6 - linkdown flag set" set -e - ip -netns testns address add 192.0.2.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 + $IP address add 192.0.2.1/24 dev dummy0 + $IP -6 address add 2001:db8:2::1/64 dev dummy0 set +e echo " Route to local address with carrier down" - ip -netns testns route get fibmatch 192.0.2.1 &> /dev/null + $IP route get fibmatch 192.0.2.1 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:2::1 &> /dev/null + $IP -6 route get fibmatch 2001:db8:2::1 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 192.0.2.1 | \ + $IP route get fibmatch 192.0.2.1 | \ grep -q "linkdown" log_test $? 1 "IPv4 linkdown flag set" - ip -netns testns -6 route get fibmatch 2001:db8:2::1 | \ + $IP -6 route get fibmatch 2001:db8:2::1 | \ grep -q "linkdown" log_test $? 1 "IPv6 linkdown flag set" @@ -329,54 +330,54 @@ fib_carrier_unicast_test() setup set -e - ip -netns testns link set dev dummy0 carrier on + $IP link set dev dummy0 carrier on set +e echo " Start point" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 198.51.100.2 | \ + $IP route get fibmatch 198.51.100.2 | \ grep -q "linkdown" log_test $? 1 "IPv4 no linkdown flag" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ + $IP -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" log_test $? 1 "IPv6 no linkdown flag" set -e - ip -netns testns link set dev dummy0 carrier off + $IP link set dev dummy0 carrier off set +e echo " Carrier down" - ip -netns testns route get fibmatch 198.51.100.2 &> /dev/null + $IP route get fibmatch 198.51.100.2 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:1::2 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 198.51.100.2 | \ + $IP route get fibmatch 198.51.100.2 | \ grep -q "linkdown" log_test $? 0 "IPv4 linkdown flag set" - ip -netns testns -6 route get fibmatch 2001:db8:1::2 | \ + $IP -6 route get fibmatch 2001:db8:1::2 | \ grep -q "linkdown" log_test $? 0 "IPv6 linkdown flag set" set -e - ip -netns testns address add 192.0.2.1/24 dev dummy0 - ip -netns testns -6 address add 2001:db8:2::1/64 dev dummy0 + $IP address add 192.0.2.1/24 dev dummy0 + $IP -6 address add 2001:db8:2::1/64 dev dummy0 set +e echo " Second address added with carrier down" - ip -netns testns route get fibmatch 192.0.2.2 &> /dev/null + $IP route get fibmatch 192.0.2.2 &> /dev/null log_test $? 0 "IPv4 fibmatch" - ip -netns testns -6 route get fibmatch 2001:db8:2::2 &> /dev/null + $IP -6 route get fibmatch 2001:db8:2::2 &> /dev/null log_test $? 0 "IPv6 fibmatch" - ip -netns testns route get fibmatch 192.0.2.2 | \ + $IP route get fibmatch 192.0.2.2 | \ grep -q "linkdown" log_test $? 0 "IPv4 linkdown flag set" - ip -netns testns -6 route get fibmatch 2001:db8:2::2 | \ + $IP -6 route get fibmatch 2001:db8:2::2 | \ grep -q "linkdown" log_test $? 0 "IPv6 linkdown flag set" -- cgit v1.3-14-g43fede From a511858c7536fab15a59a0a2aee14c5a909da23a Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Mar 2018 08:29:40 -0700 Subject: selftests: fib_tests: Allow user to run a specific test Allow a user to run just a specific fib test by setting the TEST environment variable. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index 953254439e39..cfdeb35bfed5 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -392,9 +392,13 @@ fib_carrier_test() fib_test() { - fib_unreg_test - fib_down_test - fib_carrier_test + if [ -n "$TEST" ]; then + eval $TEST + else + fib_unreg_test + fib_down_test + fib_carrier_test + fi } if [ "$(id -u)" -ne 0 ];then -- cgit v1.3-14-g43fede From 654d3a7821e838dd7608d88922d8d3db9bdb95b4 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 13 Mar 2018 08:29:41 -0700 Subject: selftests: fib_tests: Add IPv6 nexthop spec tests Add series of tests for valid and invalid nexthop specs for IPv6. $ TEST=fib_nexthop_test ./fib_tests.sh ... IPv6 nexthop tests TEST: Directly connected nexthop, unicast address [ OK ] TEST: Directly connected nexthop, unicast address with device [ OK ] TEST: Gateway is linklocal address [ OK ] TEST: Gateway is linklocal address, no device [ OK ] TEST: Gateway can not be local unicast address [ OK ] TEST: Gateway can not be local unicast address, with device [ OK ] TEST: Gateway can not be a local linklocal address [ OK ] TEST: Gateway can be local address in a VRF [ OK ] TEST: Gateway can be local address in a VRF, with device [ OK ] TEST: Gateway can be local linklocal address in a VRF [ OK ] TEST: Redirect to VRF lookup [ OK ] TEST: VRF route, gateway can be local address in default VRF [ OK ] TEST: VRF route, gateway can not be a local address [ OK ] TEST: VRF route, gateway can not be a local addr with device [ OK ] Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 180 ++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh index cfdeb35bfed5..9164e60d4b66 100755 --- a/tools/testing/selftests/net/fib_tests.sh +++ b/tools/testing/selftests/net/fib_tests.sh @@ -6,6 +6,7 @@ ret=0 +VERBOSE=${VERBOSE:=0} PAUSE_ON_FAIL=${PAUSE_ON_FAIL:=no} IP="ip -netns testns" @@ -16,10 +17,10 @@ log_test() local msg="$3" if [ ${rc} -eq ${expected} ]; then - printf " %-60s [ OK ]\n" "${msg}" + printf " TEST: %-60s [ OK ]\n" "${msg}" else ret=1 - printf " %-60s [FAIL]\n" "${msg}" + printf " TEST: %-60s [FAIL]\n" "${msg}" if [ "${PAUSE_ON_FAIL}" = "yes" ]; then echo echo "hit enter to continue, 'q' to quit" @@ -49,6 +50,28 @@ cleanup() ip netns del testns } +get_linklocal() +{ + local dev=$1 + local addr + + addr=$($IP -6 -br addr show dev ${dev} | \ + awk '{ + for (i = 3; i <= NF; ++i) { + if ($i ~ /^fe80/) + print $i + } + }' + ) + addr=${addr/\/*} + + [ -z "$addr" ] && return 1 + + echo $addr + + return 0 +} + fib_unreg_unicast_test() { echo @@ -390,6 +413,158 @@ fib_carrier_test() fib_carrier_unicast_test } +################################################################################ +# Tests on nexthop spec + +# run 'ip route add' with given spec +add_rt() +{ + local desc="$1" + local erc=$2 + local vrf=$3 + local pfx=$4 + local gw=$5 + local dev=$6 + local cmd out rc + + [ "$vrf" = "-" ] && vrf="default" + [ -n "$gw" ] && gw="via $gw" + [ -n "$dev" ] && dev="dev $dev" + + cmd="$IP route add vrf $vrf $pfx $gw $dev" + if [ "$VERBOSE" = "1" ]; then + printf "\n COMMAND: $cmd\n" + fi + + out=$(eval $cmd 2>&1) + rc=$? + if [ "$VERBOSE" = "1" -a -n "$out" ]; then + echo " $out" + fi + log_test $rc $erc "$desc" +} + +fib4_nexthop() +{ + echo + echo "IPv4 nexthop tests" + + echo "<<< write me >>>" +} + +fib6_nexthop() +{ + local lldummy=$(get_linklocal dummy0) + local llv1=$(get_linklocal dummy0) + + if [ -z "$lldummy" ]; then + echo "Failed to get linklocal address for dummy0" + return 1 + fi + if [ -z "$llv1" ]; then + echo "Failed to get linklocal address for veth1" + return 1 + fi + + echo + echo "IPv6 nexthop tests" + + add_rt "Directly connected nexthop, unicast address" 0 \ + - 2001:db8:101::/64 2001:db8:1::2 + add_rt "Directly connected nexthop, unicast address with device" 0 \ + - 2001:db8:102::/64 2001:db8:1::2 "dummy0" + add_rt "Gateway is linklocal address" 0 \ + - 2001:db8:103::1/64 $llv1 "veth0" + + # fails because LL address requires a device + add_rt "Gateway is linklocal address, no device" 2 \ + - 2001:db8:104::1/64 $llv1 + + # local address can not be a gateway + add_rt "Gateway can not be local unicast address" 2 \ + - 2001:db8:105::/64 2001:db8:1::1 + add_rt "Gateway can not be local unicast address, with device" 2 \ + - 2001:db8:106::/64 2001:db8:1::1 "dummy0" + add_rt "Gateway can not be a local linklocal address" 2 \ + - 2001:db8:107::1/64 $lldummy "dummy0" + + # VRF tests + add_rt "Gateway can be local address in a VRF" 0 \ + - 2001:db8:108::/64 2001:db8:51::2 + add_rt "Gateway can be local address in a VRF, with device" 0 \ + - 2001:db8:109::/64 2001:db8:51::2 "veth0" + add_rt "Gateway can be local linklocal address in a VRF" 0 \ + - 2001:db8:110::1/64 $llv1 "veth0" + + add_rt "Redirect to VRF lookup" 0 \ + - 2001:db8:111::/64 "" "red" + + add_rt "VRF route, gateway can be local address in default VRF" 0 \ + red 2001:db8:112::/64 2001:db8:51::1 + + # local address in same VRF fails + add_rt "VRF route, gateway can not be a local address" 2 \ + red 2001:db8:113::1/64 2001:db8:2::1 + add_rt "VRF route, gateway can not be a local addr with device" 2 \ + red 2001:db8:114::1/64 2001:db8:2::1 "dummy1" +} + +# Default VRF: +# dummy0 - 198.51.100.1/24 2001:db8:1::1/64 +# veth0 - 192.0.2.1/24 2001:db8:51::1/64 +# +# VRF red: +# dummy1 - 192.168.2.1/24 2001:db8:2::1/64 +# veth1 - 192.0.2.2/24 2001:db8:51::2/64 +# +# [ dummy0 veth0 ]--[ veth1 dummy1 ] + +fib_nexthop_test() +{ + setup + + set -e + + $IP -4 rule add pref 32765 table local + $IP -4 rule del pref 0 + $IP -6 rule add pref 32765 table local + $IP -6 rule del pref 0 + + $IP link add red type vrf table 1 + $IP link set red up + $IP -4 route add vrf red unreachable default metric 4278198272 + $IP -6 route add vrf red unreachable default metric 4278198272 + + $IP link add veth0 type veth peer name veth1 + $IP link set dev veth0 up + $IP address add 192.0.2.1/24 dev veth0 + $IP -6 address add 2001:db8:51::1/64 dev veth0 + + $IP link set dev veth1 vrf red up + $IP address add 192.0.2.2/24 dev veth1 + $IP -6 address add 2001:db8:51::2/64 dev veth1 + + $IP link add dummy1 type dummy + $IP link set dev dummy1 vrf red up + $IP address add 192.168.2.1/24 dev dummy1 + $IP -6 address add 2001:db8:2::1/64 dev dummy1 + set +e + + sleep 1 + fib4_nexthop + fib6_nexthop + + ( + $IP link del dev dummy1 + $IP link del veth0 + $IP link del red + ) 2>/dev/null + cleanup +} + +################################################################################ +# + fib_test() { if [ -n "$TEST" ]; then @@ -398,6 +573,7 @@ fib_test() fib_unreg_test fib_down_test fib_carrier_test + fib_nexthop_test fi } -- cgit v1.3-14-g43fede From 5dce837944de76b5ba9cff6d2a3ecde6f4838665 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 16 Mar 2018 10:41:14 -0700 Subject: selftests/txtimestamp: Add more configurable parameters Add a way to configure if poll() should wait forever for an event, the number of packets that should be sent for each and if there should be any delay between packets. Signed-off-by: Vinicius Costa Gomes Signed-off-by: David S. Miller --- .../selftests/networking/timestamping/txtimestamp.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/networking/timestamping/txtimestamp.c b/tools/testing/selftests/networking/timestamping/txtimestamp.c index 5df07047ca86..81a98a240456 100644 --- a/tools/testing/selftests/networking/timestamping/txtimestamp.c +++ b/tools/testing/selftests/networking/timestamping/txtimestamp.c @@ -68,9 +68,11 @@ static int cfg_num_pkts = 4; static int do_ipv4 = 1; static int do_ipv6 = 1; static int cfg_payload_len = 10; +static int cfg_poll_timeout = 100; static bool cfg_show_payload; static bool cfg_do_pktinfo; static bool cfg_loop_nodata; +static bool cfg_no_delay; static uint16_t dest_port = 9000; static struct sockaddr_in daddr; @@ -171,7 +173,7 @@ static void __poll(int fd) memset(&pollfd, 0, sizeof(pollfd)); pollfd.fd = fd; - ret = poll(&pollfd, 1, 100); + ret = poll(&pollfd, 1, cfg_poll_timeout); if (ret != 1) error(1, errno, "poll"); } @@ -371,7 +373,8 @@ static void do_test(int family, unsigned int opt) error(1, errno, "send"); /* wait for all errors to be queued, else ACKs arrive OOO */ - usleep(50 * 1000); + if (!cfg_no_delay) + usleep(50 * 1000); __poll(fd); @@ -392,6 +395,9 @@ static void __attribute__((noreturn)) usage(const char *filepath) " -4: only IPv4\n" " -6: only IPv6\n" " -h: show this message\n" + " -c N: number of packets for each test\n" + " -D: no delay between packets\n" + " -F: poll() waits forever for an event\n" " -I: request PKTINFO\n" " -l N: send N bytes at a time\n" " -n: set no-payload option\n" @@ -409,7 +415,7 @@ static void parse_opt(int argc, char **argv) int proto_count = 0; char c; - while ((c = getopt(argc, argv, "46hIl:np:rRux")) != -1) { + while ((c = getopt(argc, argv, "46c:DFhIl:np:rRux")) != -1) { switch (c) { case '4': do_ipv6 = 0; @@ -417,6 +423,15 @@ static void parse_opt(int argc, char **argv) case '6': do_ipv4 = 0; break; + case 'c': + cfg_num_pkts = strtoul(optarg, NULL, 10); + break; + case 'D': + cfg_no_delay = true; + break; + case 'F': + cfg_poll_timeout = -1; + break; case 'I': cfg_do_pktinfo = true; break; -- cgit v1.3-14-g43fede From 380e29a6b71fac7ce7a437ab2f7e305c3de8076f Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:38 +0100 Subject: selftests: pmtu: Reverse return codes of functions David suggests it's more intuitive to return non-zero on failures, and zero on success. No need to introduce tail 'return 0' in functions, they will return the exit code of the last command anyway. Suggested-by: David Ahern Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 6c19c148cef8..65842a2afa55 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -26,14 +26,12 @@ vti6_b_addr="fd00:2::b" vti6_mask="64" setup_namespaces() { - ip netns add ${NS_A} || return 0 + ip netns add ${NS_A} || return 1 ip netns add ${NS_B} - - return 1 } setup_veth() { - ${ns_a} ip link add veth_a type veth peer name veth_b || return 0 + ${ns_a} ip link add veth_a type veth peer name veth_b || return 1 ${ns_a} ip link set veth_b netns ${NS_B} ${ns_a} ip addr add ${veth6_a_addr}/${veth6_mask} dev veth_a @@ -41,12 +39,10 @@ setup_veth() { ${ns_a} ip link set veth_a up ${ns_b} ip link set veth_b up - - return 1 } setup_vti6() { - ${ns_a} ip link add vti_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 || return 0 + ${ns_a} ip link add vti_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 || return 1 ${ns_b} ip link add vti_b type vti6 local ${veth6_b_addr} remote ${veth6_a_addr} key 10 ${ns_a} ip addr add ${vti6_a_addr}/${vti6_mask} dev vti_a @@ -56,12 +52,10 @@ setup_vti6() { ${ns_b} ip link set vti_b up sleep 1 - - return 1 } setup_xfrm() { - ${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 0 + ${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1 ${ns_a} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel ${ns_a} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel ${ns_a} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel @@ -70,8 +64,6 @@ setup_xfrm() { ${ns_b} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel ${ns_b} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel ${ns_b} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel - - return 1 } setup() { @@ -79,13 +71,13 @@ setup() { [ "$(id -u)" -ne 0 ] && echo "SKIP: need to run as root" && exit 0 - setup_namespaces && echo "SKIP: namespaces not supported" && exit 0 - setup_veth && echo "SKIP: veth not supported" && exit 0 + setup_namespaces || { echo "SKIP: namespaces not supported"; exit 0; } + setup_veth || { echo "SKIP: veth not supported"; exit 0; } case ${tunnel_type} in "vti6") - setup_vti6 && echo "SKIP: vti6 not supported" && exit 0 - setup_xfrm && echo "SKIP: xfrm not supported" && exit 0 + setup_vti6 || { echo "SKIP: vti6 not supported"; exit 0; } + setup_xfrm || { echo "SKIP: xfrm not supported"; exit 0; } ;; *) ;; -- cgit v1.3-14-g43fede From 822d2f86c485113dc5df7648e97aaef3607c4479 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:39 +0100 Subject: selftests: pmtu: Use namespace command prefix to fetch route mtu In 7af137b72131 ("selftests: net: Introduce first PMTU test") I accidentally assumed route_get_* helpers would run from a single namespace. Make them a bit more generic, by passing the namespace command prefix as a parameter instead. Fixes: 7af137b72131 ("selftests: net: Introduce first PMTU test") Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 65842a2afa55..0d010f982272 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -98,15 +98,17 @@ mtu() { } route_get_dst_exception() { - dst="${1}" + ns_cmd="${1}" + dst="${2}" - ${ns_a} ip route get "${dst}" + ${ns_cmd} ip route get "${dst}" } route_get_dst_pmtu_from_exception() { - dst="${1}" + ns_cmd="${1}" + dst="${2}" - exception="$(route_get_dst_exception ${dst})" + exception="$(route_get_dst_exception "${ns_cmd}" ${dst})" next=0 for i in ${exception}; do [ ${next} -eq 1 ] && echo "${i}" && return @@ -125,7 +127,7 @@ test_pmtu_vti6_exception() { ${ns_a} ping6 -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null # Check that exception was created - if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" = "" ]; then + if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" = "" ]; then echo "FAIL: Tunnel exceeding link layer MTU didn't create route exception" exit 1 fi @@ -133,14 +135,14 @@ test_pmtu_vti6_exception() { # Decrease tunnel MTU, check for PMTU decrease in route exception mtu "${ns_a}" vti_a 3000 - if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" -ne 3000 ]; then + if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 3000 ]; then echo "FAIL: Decreasing tunnel MTU didn't decrease route exception PMTU" exit 1 fi # Increase tunnel MTU, check for PMTU increase in route exception mtu "${ns_a}" vti_a 9000 - if [ "$(route_get_dst_pmtu_from_exception ${vti6_b_addr})" -ne 9000 ]; then + if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 9000 ]; then echo "FAIL: Increasing tunnel MTU didn't increase route exception PMTU" exit 1 fi -- cgit v1.3-14-g43fede From f2c929feeccd3d56be284b9e24e04cd3c4779a4f Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:40 +0100 Subject: selftests: pmtu: Factor out MTU parsing helper ...so that it can be used for any iproute command output. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 0d010f982272..2d33e533ad36 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -97,6 +97,16 @@ mtu() { ${ns_cmd} ip link set dev ${dev} mtu ${mtu} } +mtu_parse() { + input="${1}" + + next=0 + for i in ${input}; do + [ ${next} -eq 1 ] && echo "${i}" && return + [ "${i}" = "mtu" ] && next=1 + done +} + route_get_dst_exception() { ns_cmd="${1}" dst="${2}" @@ -108,12 +118,7 @@ route_get_dst_pmtu_from_exception() { ns_cmd="${1}" dst="${2}" - exception="$(route_get_dst_exception "${ns_cmd}" ${dst})" - next=0 - for i in ${exception}; do - [ ${next} -eq 1 ] && echo "${i}" && return - [ "${i}" = "mtu" ] && next=1 - done + mtu_parse "$(route_get_dst_exception "${ns_cmd}" ${dst})" } test_pmtu_vti6_exception() { -- cgit v1.3-14-g43fede From 36455bd1e977ef1ccd8e89018bd14d0a5b96b4e5 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:41 +0100 Subject: selftests: pmtu: Introduce support for multiple tests Introduce list of tests and their descriptions, and loop on it in main body. Tests will now just take care of calling setup with a list of "units" they need, and return 0 on success, 1 on failure, 2 if the test had to be skipped. Main script body will take care of displaying results and cleaning up after every test. Introduce guard variable so that we don't clean up twice in case of interrupts or unexpected failures. The pmtu_vti6_exception test can now run its third step even if the previous one failed, as we can return values from it. Also introduce support to display test descriptions, and display aligned OK/FAIL/SKIP test outcomes. Buffer error strings so that in case of failure we can display them right under the outcome for each test. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 87 ++++++++++++++++++++++++++----------- 1 file changed, 61 insertions(+), 26 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 2d33e533ad36..733de6053b5c 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -5,13 +5,16 @@ # # Tests currently implemented: # -# - test_pmtu_vti6_exception +# - pmtu_vti6_exception # Set up vti6 tunnel on top of veth, with xfrm states and policies, in two # namespaces with matching endpoints. Check that route exception is # created by exceeding link layer MTU with ping to other endpoint. Then # decrease and increase MTU of tunnel, checking that route exception PMTU # changes accordingly +tests=" + pmtu_vti6_exception vti6: PMTU exceptions" + NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" ns_a="ip netns exec ${NS_A}" @@ -25,6 +28,19 @@ vti6_a_addr="fd00:2::a" vti6_b_addr="fd00:2::b" vti6_mask="64" +cleanup_done=1 +err_buf= + +err() { + err_buf="${err_buf}${1} +" +} + +err_flush() { + echo -n "${err_buf}" + err_buf= +} + setup_namespaces() { ip netns add ${NS_A} || return 1 ip netns add ${NS_B} @@ -67,26 +83,19 @@ setup_xfrm() { } setup() { - tunnel_type="$1" - - [ "$(id -u)" -ne 0 ] && echo "SKIP: need to run as root" && exit 0 - - setup_namespaces || { echo "SKIP: namespaces not supported"; exit 0; } - setup_veth || { echo "SKIP: veth not supported"; exit 0; } + [ "$(id -u)" -ne 0 ] && echo " need to run as root" && return 1 - case ${tunnel_type} in - "vti6") - setup_vti6 || { echo "SKIP: vti6 not supported"; exit 0; } - setup_xfrm || { echo "SKIP: xfrm not supported"; exit 0; } - ;; - *) - ;; - esac + cleanup_done=0 + for arg do + eval setup_${arg} || { echo " ${arg} not supported"; return 1; } + done } cleanup() { + [ ${cleanup_done} -eq 1 ] && return ip netns del ${NS_A} 2 > /dev/null ip netns del ${NS_B} 2 > /dev/null + cleanup_done=1 } mtu() { @@ -122,7 +131,8 @@ route_get_dst_pmtu_from_exception() { } test_pmtu_vti6_exception() { - setup vti6 + setup namespaces veth vti6 xfrm || return 2 + fail=0 # Create route exception by exceeding link layer MTU mtu "${ns_a}" veth_a 4000 @@ -133,30 +143,55 @@ test_pmtu_vti6_exception() { # Check that exception was created if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" = "" ]; then - echo "FAIL: Tunnel exceeding link layer MTU didn't create route exception" - exit 1 + err " tunnel exceeding link layer MTU didn't create route exception" + return 1 fi # Decrease tunnel MTU, check for PMTU decrease in route exception mtu "${ns_a}" vti_a 3000 if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 3000 ]; then - echo "FAIL: Decreasing tunnel MTU didn't decrease route exception PMTU" - exit 1 + err " decreasing tunnel MTU didn't decrease route exception PMTU" + fail=1 fi # Increase tunnel MTU, check for PMTU increase in route exception mtu "${ns_a}" vti_a 9000 if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 9000 ]; then - echo "FAIL: Increasing tunnel MTU didn't increase route exception PMTU" - exit 1 + err " increasing tunnel MTU didn't increase route exception PMTU" + fail=1 fi - echo "PASS" + return ${fail} } trap cleanup EXIT -test_pmtu_vti6_exception - -exit 0 +exitcode=0 +desc=0 +IFS=" +" +for t in ${tests}; do + [ $desc -eq 0 ] && name="${t}" && desc=1 && continue || desc=0 + + ( + unset IFS + eval test_${name} + ret=$? + cleanup + + if [ $ret -eq 0 ]; then + printf "TEST: %-60s [ OK ]\n" "${t}" + elif [ $ret -eq 1 ]; then + printf "TEST: %-60s [FAIL]\n" "${t}" + err_flush + exit 1 + elif [ $ret -eq 2 ]; then + printf "TEST: %-60s [SKIP]\n" "${t}" + err_flush + fi + ) + [ $? -ne 0 ] && exitcode=1 +done + +exit ${exitcode} -- cgit v1.3-14-g43fede From a41c789bdcc1e3d8fe0d82ee80c22aa4f4508004 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:42 +0100 Subject: selftests: pmtu: Add pmtu_vti4_default_mtu test This test checks that the MTU assigned by default to a vti (IPv4) interface created on top of veth is simply veth's MTU minus the length of the encapsulated IPv4 header. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 86 +++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 13 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 733de6053b5c..be13b3232c12 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -1,7 +1,8 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 # -# Check that route PMTU values match expectations +# Check that route PMTU values match expectations, and that initial device MTU +# values are assigned correctly # # Tests currently implemented: # @@ -11,19 +12,32 @@ # created by exceeding link layer MTU with ping to other endpoint. Then # decrease and increase MTU of tunnel, checking that route exception PMTU # changes accordingly +# +# - pmtu_vti4_default_mtu +# Set up vti4 tunnel on top of veth, in two namespaces with matching +# endpoints. Check that MTU assigned to vti interface is the MTU of the +# lower layer (veth) minus additional lower layer headers (zero, for veth) +# minus IPv4 header length tests=" - pmtu_vti6_exception vti6: PMTU exceptions" + pmtu_vti6_exception vti6: PMTU exceptions + pmtu_vti4_default_mtu vti4: default MTU assignment" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" ns_a="ip netns exec ${NS_A}" ns_b="ip netns exec ${NS_B}" +veth4_a_addr="192.168.1.1" +veth4_b_addr="192.168.1.2" +veth4_mask="24" veth6_a_addr="fd00:1::a" veth6_b_addr="fd00:1::b" veth6_mask="64" +vti4_a_addr="192.168.2.1" +vti4_b_addr="192.168.2.2" +vti4_mask="24" vti6_a_addr="fd00:2::a" vti6_b_addr="fd00:2::b" vti6_mask="64" @@ -50,6 +64,9 @@ setup_veth() { ${ns_a} ip link add veth_a type veth peer name veth_b || return 1 ${ns_a} ip link set veth_b netns ${NS_B} + ${ns_a} ip addr add ${veth4_a_addr}/${veth4_mask} dev veth_a + ${ns_b} ip addr add ${veth4_b_addr}/${veth4_mask} dev veth_b + ${ns_a} ip addr add ${veth6_a_addr}/${veth6_mask} dev veth_a ${ns_b} ip addr add ${veth6_b_addr}/${veth6_mask} dev veth_b @@ -57,19 +74,36 @@ setup_veth() { ${ns_b} ip link set veth_b up } -setup_vti6() { - ${ns_a} ip link add vti_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 || return 1 - ${ns_b} ip link add vti_b type vti6 local ${veth6_b_addr} remote ${veth6_a_addr} key 10 +setup_vti() { + proto=${1} + veth_a_addr="${2}" + veth_b_addr="${3}" + vti_a_addr="${4}" + vti_b_addr="${5}" + vti_mask=${6} - ${ns_a} ip addr add ${vti6_a_addr}/${vti6_mask} dev vti_a - ${ns_b} ip addr add ${vti6_b_addr}/${vti6_mask} dev vti_b + [ ${proto} -eq 6 ] && vti_type="vti6" || vti_type="vti" - ${ns_a} ip link set vti_a up - ${ns_b} ip link set vti_b up + ${ns_a} ip link add vti${proto}_a type ${vti_type} local ${veth_a_addr} remote ${veth_b_addr} key 10 || return 1 + ${ns_b} ip link add vti${proto}_b type ${vti_type} local ${veth_b_addr} remote ${veth_a_addr} key 10 + + ${ns_a} ip addr add ${vti_a_addr}/${vti_mask} dev vti${proto}_a + ${ns_b} ip addr add ${vti_b_addr}/${vti_mask} dev vti${proto}_b + + ${ns_a} ip link set vti${proto}_a up + ${ns_b} ip link set vti${proto}_b up sleep 1 } +setup_vti4() { + setup_vti 4 ${veth4_a_addr} ${veth4_b_addr} ${vti4_a_addr} ${vti4_b_addr} ${vti4_mask} +} + +setup_vti6() { + setup_vti 6 ${veth6_a_addr} ${veth6_b_addr} ${vti6_a_addr} ${vti6_b_addr} ${vti6_mask} +} + setup_xfrm() { ${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1 ${ns_a} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel @@ -116,6 +150,20 @@ mtu_parse() { done } +link_get() { + ns_cmd="${1}" + name="${2}" + + ${ns_cmd} ip link show dev "${name}" +} + +link_get_mtu() { + ns_cmd="${1}" + name="${2}" + + mtu_parse "$(link_get "${ns_cmd}" ${name})" +} + route_get_dst_exception() { ns_cmd="${1}" dst="${2}" @@ -137,8 +185,8 @@ test_pmtu_vti6_exception() { # Create route exception by exceeding link layer MTU mtu "${ns_a}" veth_a 4000 mtu "${ns_b}" veth_b 4000 - mtu "${ns_a}" vti_a 5000 - mtu "${ns_b}" vti_b 5000 + mtu "${ns_a}" vti6_a 5000 + mtu "${ns_b}" vti6_b 5000 ${ns_a} ping6 -q -i 0.1 -w 2 -s 60000 ${vti6_b_addr} > /dev/null # Check that exception was created @@ -148,7 +196,7 @@ test_pmtu_vti6_exception() { fi # Decrease tunnel MTU, check for PMTU decrease in route exception - mtu "${ns_a}" vti_a 3000 + mtu "${ns_a}" vti6_a 3000 if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 3000 ]; then err " decreasing tunnel MTU didn't decrease route exception PMTU" @@ -156,7 +204,7 @@ test_pmtu_vti6_exception() { fi # Increase tunnel MTU, check for PMTU increase in route exception - mtu "${ns_a}" vti_a 9000 + mtu "${ns_a}" vti6_a 9000 if [ "$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti6_b_addr})" -ne 9000 ]; then err " increasing tunnel MTU didn't increase route exception PMTU" fail=1 @@ -165,6 +213,18 @@ test_pmtu_vti6_exception() { return ${fail} } +test_pmtu_vti4_default_mtu() { + setup namespaces veth vti4 || return 2 + + # Check that MTU of vti device is MTU of veth minus IPv4 header length + veth_mtu="$(link_get_mtu "${ns_a}" veth_a)" + vti4_mtu="$(link_get_mtu "${ns_a}" vti4_a)" + if [ $((veth_mtu - vti4_mtu)) -ne 20 ]; then + err " vti MTU ${vti4_mtu} is not veth MTU ${veth_mtu} minus IPv4 header length" + return 1 + fi +} + trap cleanup EXIT exitcode=0 -- cgit v1.3-14-g43fede From 35b49424b8a49edb6de6e7ec54bd8edb568031c2 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:43 +0100 Subject: selftests: pmtu: Add pmtu_vti6_default_mtu test Same as pmtu_vti4_default_mtu, but on IPv6 with vti6. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index be13b3232c12..5d9af22b360a 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -18,10 +18,14 @@ # endpoints. Check that MTU assigned to vti interface is the MTU of the # lower layer (veth) minus additional lower layer headers (zero, for veth) # minus IPv4 header length +# +# - pmtu_vti6_default_mtu +# Same as above, for IPv6 tests=" pmtu_vti6_exception vti6: PMTU exceptions - pmtu_vti4_default_mtu vti4: default MTU assignment" + pmtu_vti4_default_mtu vti4: default MTU assignment + pmtu_vti6_default_mtu vti6: default MTU assignment" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" @@ -225,6 +229,18 @@ test_pmtu_vti4_default_mtu() { fi } +test_pmtu_vti6_default_mtu() { + setup namespaces veth vti6 || return 2 + + # Check that MTU of vti device is MTU of veth minus IPv6 header length + veth_mtu="$(link_get_mtu "${ns_a}" veth_a)" + vti6_mtu="$(link_get_mtu "${ns_a}" vti6_a)" + if [ $((veth_mtu - vti6_mtu)) -ne 40 ]; then + err " vti MTU ${vti6_mtu} is not veth MTU ${veth_mtu} minus IPv6 header length" + return 1 + fi +} + trap cleanup EXIT exitcode=0 -- cgit v1.3-14-g43fede From 5e84430bb83e8241c485ccce728ff5e5e80789eb Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:44 +0100 Subject: selftests: pmtu: Add test_pmtu_vti4_exception test This test checks that PMTU exceptions are created only when needed on IPv4 routes with vti and xfrm, and their PMTU value is checked as well. We can't adopt the same approach as test_pmtu_vti6_exception() here, because on IPv4 administrative MTU changes won't be reflected directly on PMTU. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 80 ++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 10 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 5d9af22b360a..ba11433d17d8 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -6,6 +6,14 @@ # # Tests currently implemented: # +# - pmtu_vti4_exception +# Set up vti tunnel on top of veth, with xfrm states and policies, in two +# namespaces with matching endpoints. Check that route exception is not +# created if link layer MTU is not exceeded, then exceed it and check that +# exception is created with the expected PMTU. The approach described +# below for IPv6 doesn't apply here, because, on IPv4, administrative MTU +# changes alone won't affect PMTU +# # - pmtu_vti6_exception # Set up vti6 tunnel on top of veth, with xfrm states and policies, in two # namespaces with matching endpoints. Check that route exception is @@ -24,6 +32,7 @@ tests=" pmtu_vti6_exception vti6: PMTU exceptions + pmtu_vti4_exception vti4: PMTU exceptions pmtu_vti4_default_mtu vti4: default MTU assignment pmtu_vti6_default_mtu vti6: default MTU assignment" @@ -109,15 +118,27 @@ setup_vti6() { } setup_xfrm() { - ${ns_a} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1 - ${ns_a} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel - ${ns_a} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel - ${ns_a} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel - - ${ns_b} ip -6 xfrm state add src ${veth6_a_addr} dst ${veth6_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel - ${ns_b} ip -6 xfrm state add src ${veth6_b_addr} dst ${veth6_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel - ${ns_b} ip -6 xfrm policy add dir out mark 10 tmpl src ${veth6_b_addr} dst ${veth6_a_addr} proto esp mode tunnel - ${ns_b} ip -6 xfrm policy add dir in mark 10 tmpl src ${veth6_a_addr} dst ${veth6_b_addr} proto esp mode tunnel + proto=${1} + veth_a_addr="${2}" + veth_b_addr="${3}" + + ${ns_a} ip -${proto} xfrm state add src ${veth_a_addr} dst ${veth_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel || return 1 + ${ns_a} ip -${proto} xfrm state add src ${veth_b_addr} dst ${veth_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_a} ip -${proto} xfrm policy add dir out mark 10 tmpl src ${veth_a_addr} dst ${veth_b_addr} proto esp mode tunnel + ${ns_a} ip -${proto} xfrm policy add dir in mark 10 tmpl src ${veth_b_addr} dst ${veth_a_addr} proto esp mode tunnel + + ${ns_b} ip -${proto} xfrm state add src ${veth_a_addr} dst ${veth_b_addr} spi 0x1000 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_b} ip -${proto} xfrm state add src ${veth_b_addr} dst ${veth_a_addr} spi 0x1001 proto esp aead "rfc4106(gcm(aes))" 0x0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f 128 mode tunnel + ${ns_b} ip -${proto} xfrm policy add dir out mark 10 tmpl src ${veth_b_addr} dst ${veth_a_addr} proto esp mode tunnel + ${ns_b} ip -${proto} xfrm policy add dir in mark 10 tmpl src ${veth_a_addr} dst ${veth_b_addr} proto esp mode tunnel +} + +setup_xfrm4() { + setup_xfrm 4 ${veth4_a_addr} ${veth4_b_addr} +} + +setup_xfrm6() { + setup_xfrm 6 ${veth6_a_addr} ${veth6_b_addr} } setup() { @@ -182,8 +203,47 @@ route_get_dst_pmtu_from_exception() { mtu_parse "$(route_get_dst_exception "${ns_cmd}" ${dst})" } +test_pmtu_vti4_exception() { + setup namespaces veth vti4 xfrm4 || return 2 + + veth_mtu=1500 + vti_mtu=$((veth_mtu - 20)) + + # SPI SN IV ICV pad length next header + esp_payload_rfc4106=$((vti_mtu - 4 - 4 - 8 - 16 - 1 - 1)) + ping_payload=$((esp_payload_rfc4106 - 28)) + + mtu "${ns_a}" veth_a ${veth_mtu} + mtu "${ns_b}" veth_b ${veth_mtu} + mtu "${ns_a}" vti4_a ${vti_mtu} + mtu "${ns_b}" vti4_b ${vti_mtu} + + # Send DF packet without exceeding link layer MTU, check that no + # exception is created + ${ns_a} ping -q -M want -i 0.1 -w 2 -s ${ping_payload} ${vti4_b_addr} > /dev/null + pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})" + if [ "${pmtu}" != "" ]; then + err " unexpected exception created with PMTU ${pmtu} for IP payload length ${esp_payload_rfc4106}" + return 1 + fi + + # Now exceed link layer MTU by one byte, check that exception is created + ${ns_a} ping -q -M want -i 0.1 -w 2 -s $((ping_payload + 1)) ${vti4_b_addr} > /dev/null + pmtu="$(route_get_dst_pmtu_from_exception "${ns_a}" ${vti4_b_addr})" + if [ "${pmtu}" = "" ]; then + err " exception not created for IP payload length $((esp_payload_rfc4106 + 1))" + return 1 + fi + + # ...with the right PMTU value + if [ ${pmtu} -ne ${esp_payload_rfc4106} ]; then + err " wrong PMTU ${pmtu} in exception, expected: ${esp_payload_rfc4106}" + return 1 + fi +} + test_pmtu_vti6_exception() { - setup namespaces veth vti6 xfrm || return 2 + setup namespaces veth vti6 xfrm6 || return 2 fail=0 # Create route exception by exceeding link layer MTU -- cgit v1.3-14-g43fede From 719e121574497436e39536c2a888b901fbe30cfe Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:45 +0100 Subject: selftests: pmtu: Add pmtu_vti4_link_add_mtu test This test checks that MTU given on vti link creation is actually configured, and that tunnel is not created with an invalid MTU value. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 45 ++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index ba11433d17d8..d9f7ef2c213d 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -29,12 +29,17 @@ # # - pmtu_vti6_default_mtu # Same as above, for IPv6 +# +# - pmtu_vti4_link_add_mtu +# Set up vti4 interface passing MTU value at link creation, check MTU is +# configured, and that link is not created with invalid MTU values tests=" pmtu_vti6_exception vti6: PMTU exceptions pmtu_vti4_exception vti4: PMTU exceptions pmtu_vti4_default_mtu vti4: default MTU assignment - pmtu_vti6_default_mtu vti6: default MTU assignment" + pmtu_vti6_default_mtu vti6: default MTU assignment + pmtu_vti4_link_add_mtu vti4: MTU setting on link creation" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" @@ -301,6 +306,44 @@ test_pmtu_vti6_default_mtu() { fi } +test_pmtu_vti4_link_add_mtu() { + setup namespaces || return 2 + + ${ns_a} ip link add vti4_a type vti local ${veth4_a_addr} remote ${veth4_b_addr} key 10 + [ $? -ne 0 ] && err " vti not supported" && return 2 + ${ns_a} ip link del vti4_a + + fail=0 + + min=68 + max=$((65528 - 20)) + # Check invalid values first + for v in $((min - 1)) $((max + 1)); do + ${ns_a} ip link add vti4_a mtu ${v} type vti local ${veth4_a_addr} remote ${veth4_b_addr} key 10 2>/dev/null + # This can fail, or MTU can be adjusted to a proper value + [ $? -ne 0 ] && continue + mtu="$(link_get_mtu "${ns_a}" vti4_a)" + if [ ${mtu} -lt ${min} -o ${mtu} -gt ${max} ]; then + err " vti tunnel created with invalid MTU ${mtu}" + fail=1 + fi + ${ns_a} ip link del vti4_a + done + + # Now check valid values + for v in ${min} 1300 ${max}; do + ${ns_a} ip link add vti4_a mtu ${v} type vti local ${veth4_a_addr} remote ${veth4_b_addr} key 10 + mtu="$(link_get_mtu "${ns_a}" vti4_a)" + ${ns_a} ip link del vti4_a + if [ "${mtu}" != "${v}" ]; then + err " vti MTU ${mtu} doesn't match configured value ${v}" + fail=1 + fi + done + + return ${fail} +} + trap cleanup EXIT exitcode=0 -- cgit v1.3-14-g43fede From 8b6022fc7839e3ba2255bb264b16b0fffe961212 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:46 +0100 Subject: selftests: pmtu: Add pmtu_vti6_link_add_mtu test Same as pmtu_vti4_link_add_mtu test, but for IPv6. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 44 ++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index d9f7ef2c213d..cd12a1f5c003 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -33,13 +33,17 @@ # - pmtu_vti4_link_add_mtu # Set up vti4 interface passing MTU value at link creation, check MTU is # configured, and that link is not created with invalid MTU values +# +# - pmtu_vti6_link_add_mtu +# Same as above, for IPv6 tests=" pmtu_vti6_exception vti6: PMTU exceptions pmtu_vti4_exception vti4: PMTU exceptions pmtu_vti4_default_mtu vti4: default MTU assignment pmtu_vti6_default_mtu vti6: default MTU assignment - pmtu_vti4_link_add_mtu vti4: MTU setting on link creation" + pmtu_vti4_link_add_mtu vti4: MTU setting on link creation + pmtu_vti6_link_add_mtu vti6: MTU setting on link creation" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" @@ -344,6 +348,44 @@ test_pmtu_vti4_link_add_mtu() { return ${fail} } +test_pmtu_vti6_link_add_mtu() { + setup namespaces || return 2 + + ${ns_a} ip link add vti6_a type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 + [ $? -ne 0 ] && err " vti6 not supported" && return 2 + ${ns_a} ip link del vti6_a + + fail=0 + + min=1280 + max=$((65535 - 40)) + # Check invalid values first + for v in $((min - 1)) $((max + 1)); do + ${ns_a} ip link add vti6_a mtu ${v} type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 2>/dev/null + # This can fail, or MTU can be adjusted to a proper value + [ $? -ne 0 ] && continue + mtu="$(link_get_mtu "${ns_a}" vti6_a)" + if [ ${mtu} -lt ${min} -o ${mtu} -gt ${max} ]; then + err " vti6 tunnel created with invalid MTU ${v}" + fail=1 + fi + ${ns_a} ip link del vti6_a + done + + # Now check valid values + for v in 1280 1300 $((65535 - 40)); do + ${ns_a} ip link add vti6_a mtu ${v} type vti6 local ${veth6_a_addr} remote ${veth6_b_addr} key 10 + mtu="$(link_get_mtu "${ns_a}" vti6_a)" + ${ns_a} ip link del vti6_a + if [ "${mtu}" != "${v}" ]; then + err " vti6 MTU ${mtu} doesn't match configured value ${v}" + fail=1 + fi + done + + return ${fail} +} + trap cleanup EXIT exitcode=0 -- cgit v1.3-14-g43fede From 1fad59ea1c34b14f080725fc4cdfc6160651e371 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sat, 17 Mar 2018 02:31:47 +0100 Subject: selftests: pmtu: Add pmtu_vti6_link_change_mtu test This test checks that MTU configured from userspace is used on link creation and changes, and that when it's not passed from userspace, it's calculated properly from the MTU of the lower layer. Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 67 +++++++++++++++++++++++++++++++++---- 1 file changed, 61 insertions(+), 6 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index cd12a1f5c003..92197c05bac4 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -36,14 +36,21 @@ # # - pmtu_vti6_link_add_mtu # Same as above, for IPv6 +# +# - pmtu_vti6_link_change_mtu +# Set up two dummy interfaces with different MTUs, create a vti6 tunnel +# and check that configured MTU is used on link creation and changes, and +# that MTU is properly calculated instead when MTU is not configured from +# userspace tests=" - pmtu_vti6_exception vti6: PMTU exceptions - pmtu_vti4_exception vti4: PMTU exceptions - pmtu_vti4_default_mtu vti4: default MTU assignment - pmtu_vti6_default_mtu vti6: default MTU assignment - pmtu_vti4_link_add_mtu vti4: MTU setting on link creation - pmtu_vti6_link_add_mtu vti6: MTU setting on link creation" + pmtu_vti6_exception vti6: PMTU exceptions + pmtu_vti4_exception vti4: PMTU exceptions + pmtu_vti4_default_mtu vti4: default MTU assignment + pmtu_vti6_default_mtu vti6: default MTU assignment + pmtu_vti4_link_add_mtu vti4: MTU setting on link creation + pmtu_vti6_link_add_mtu vti6: MTU setting on link creation + pmtu_vti6_link_change_mtu vti6: MTU changes on link changes" NS_A="ns-$(mktemp -u XXXXXX)" NS_B="ns-$(mktemp -u XXXXXX)" @@ -64,6 +71,10 @@ vti6_a_addr="fd00:2::a" vti6_b_addr="fd00:2::b" vti6_mask="64" +dummy6_0_addr="fc00:1000::0" +dummy6_1_addr="fc00:1001::0" +dummy6_mask="64" + cleanup_done=1 err_buf= @@ -386,6 +397,50 @@ test_pmtu_vti6_link_add_mtu() { return ${fail} } +test_pmtu_vti6_link_change_mtu() { + setup namespaces || return 2 + + ${ns_a} ip link add dummy0 mtu 1500 type dummy + [ $? -ne 0 ] && err " dummy not supported" && return 2 + ${ns_a} ip link add dummy1 mtu 3000 type dummy + ${ns_a} ip link set dummy0 up + ${ns_a} ip link set dummy1 up + + ${ns_a} ip addr add ${dummy6_0_addr}/${dummy6_mask} dev dummy0 + ${ns_a} ip addr add ${dummy6_1_addr}/${dummy6_mask} dev dummy1 + + fail=0 + + # Create vti6 interface bound to device, passing MTU, check it + ${ns_a} ip link add vti6_a mtu 1300 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr} + mtu="$(link_get_mtu "${ns_a}" vti6_a)" + if [ ${mtu} -ne 1300 ]; then + err " vti6 MTU ${mtu} doesn't match configured value 1300" + fail=1 + fi + + # Move to another device with different MTU, without passing MTU, check + # MTU is adjusted + echo "${ns_a} ip link set vti6_a type vti6 remote ${dummy6_1_addr} local ${dummy6_1_addr}" > /dev/kmsg + ${ns_a} ip link set vti6_a type vti6 remote ${dummy6_1_addr} local ${dummy6_1_addr} + mtu="$(link_get_mtu "${ns_a}" vti6_a)" + if [ ${mtu} -ne $((3000 - 40)) ]; then + err " vti MTU ${mtu} is not dummy MTU 3000 minus IPv6 header length" + fail=1 + fi + + # Move it back, passing MTU, check MTU is not overridden + echo "${ns_a} ip link set vti6_a mtu 1280 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr}" > /dev/kmsg + ${ns_a} ip link set vti6_a mtu 1280 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr} + mtu="$(link_get_mtu "${ns_a}" vti6_a)" + if [ ${mtu} -ne 1280 ]; then + err " vti6 MTU ${mtu} doesn't match configured value 1280" + fail=1 + fi + + return ${fail} +} + trap cleanup EXIT exitcode=0 -- cgit v1.3-14-g43fede From e3c72f3d37e4745dc3a6ae69f5fc2bd4c31ca4eb Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sun, 18 Mar 2018 21:58:12 +0100 Subject: selftests: pmtu: Drop prints to kernel log from pmtu_vti6_link_change_mtu Reported-by: David Ahern Fixes: 1fad59ea1c34 ("selftests: pmtu: Add pmtu_vti6_link_change_mtu test") Signed-off-by: Stefano Brivio Signed-off-by: David S. Miller --- tools/testing/selftests/net/pmtu.sh | 2 -- 1 file changed, 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/pmtu.sh b/tools/testing/selftests/net/pmtu.sh index 92197c05bac4..1e428781a625 100755 --- a/tools/testing/selftests/net/pmtu.sh +++ b/tools/testing/selftests/net/pmtu.sh @@ -421,7 +421,6 @@ test_pmtu_vti6_link_change_mtu() { # Move to another device with different MTU, without passing MTU, check # MTU is adjusted - echo "${ns_a} ip link set vti6_a type vti6 remote ${dummy6_1_addr} local ${dummy6_1_addr}" > /dev/kmsg ${ns_a} ip link set vti6_a type vti6 remote ${dummy6_1_addr} local ${dummy6_1_addr} mtu="$(link_get_mtu "${ns_a}" vti6_a)" if [ ${mtu} -ne $((3000 - 40)) ]; then @@ -430,7 +429,6 @@ test_pmtu_vti6_link_change_mtu() { fi # Move it back, passing MTU, check MTU is not overridden - echo "${ns_a} ip link set vti6_a mtu 1280 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr}" > /dev/kmsg ${ns_a} ip link set vti6_a mtu 1280 type vti6 remote ${dummy6_0_addr} local ${dummy6_0_addr} mtu="$(link_get_mtu "${ns_a}" vti6_a)" if [ ${mtu} -ne 1280 ]; then -- cgit v1.3-14-g43fede From 4b0b37d4cc54b21a6ecad7271cbc850555869c62 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Sat, 17 Mar 2018 08:25:07 -0700 Subject: selftests/x86/ptrace_syscall: Fix for yet more glibc interference glibc keeps getting cleverer, and my version now turns raise() into more than one syscall. Since the test relies on ptrace seeing an exact set of syscalls, this breaks the test. Replace raise(SIGSTOP) with syscall(SYS_tgkill, ...) to force glibc to get out of our way. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Cc: linux-kselftest@vger.kernel.org Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/bc80338b453afa187bc5f895bd8e2c8d6e264da2.1521300271.git.luto@kernel.org Signed-off-by: Ingo Molnar --- tools/testing/selftests/x86/ptrace_syscall.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/x86/ptrace_syscall.c b/tools/testing/selftests/x86/ptrace_syscall.c index 1ae1c5a7392e..6f22238f3217 100644 --- a/tools/testing/selftests/x86/ptrace_syscall.c +++ b/tools/testing/selftests/x86/ptrace_syscall.c @@ -183,8 +183,10 @@ static void test_ptrace_syscall_restart(void) if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) err(1, "PTRACE_TRACEME"); + pid_t pid = getpid(), tid = syscall(SYS_gettid); + printf("\tChild will make one syscall\n"); - raise(SIGSTOP); + syscall(SYS_tgkill, pid, tid, SIGSTOP); syscall(SYS_gettid, 10, 11, 12, 13, 14, 15); _exit(0); @@ -301,9 +303,11 @@ static void test_restart_under_ptrace(void) if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) err(1, "PTRACE_TRACEME"); + pid_t pid = getpid(), tid = syscall(SYS_gettid); + printf("\tChild will take a nap until signaled\n"); setsigign(SIGUSR1, SA_RESTART); - raise(SIGSTOP); + syscall(SYS_tgkill, pid, tid, SIGSTOP); syscall(SYS_pause, 0, 0, 0, 0, 0, 0); _exit(0); -- cgit v1.3-14-g43fede From 82a8616889d506cb690cfc0afb2ccadda120461d Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:57:31 -0700 Subject: bpf: add map tests for BPF_PROG_TYPE_SK_MSG Add map tests to attach BPF_PROG_TYPE_SK_MSG types to a sockmap. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 10 ++++ tools/testing/selftests/bpf/Makefile | 3 +- tools/testing/selftests/bpf/bpf_helpers.h | 2 + tools/testing/selftests/bpf/sockmap_parse_prog.c | 15 +++++- tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c | 33 +++++++++++++ tools/testing/selftests/bpf/sockmap_verdict_prog.c | 7 +++ tools/testing/selftests/bpf/test_maps.c | 55 ++++++++++++++++++++-- 7 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c (limited to 'tools/testing') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 1944d0aee7e8..13d9c59d79ce 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -133,6 +133,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_SOCK_OPS, BPF_PROG_TYPE_SK_SKB, BPF_PROG_TYPE_CGROUP_DEVICE, + BPF_PROG_TYPE_SK_MSG, }; enum bpf_attach_type { @@ -143,6 +144,7 @@ enum bpf_attach_type { BPF_SK_SKB_STREAM_PARSER, BPF_SK_SKB_STREAM_VERDICT, BPF_CGROUP_DEVICE, + BPF_SK_MSG_VERDICT, __MAX_BPF_ATTACH_TYPE }; @@ -941,6 +943,14 @@ enum sk_action { SK_PASS, }; +/* user accessible metadata for SK_MSG packet hook, new fields must + * be added to the end of this structure + */ +struct sk_msg_md { + void *data; + void *data_end; +}; + #define BPF_TAG_SIZE 8 struct bpf_prog_info { diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index b0d29fd5e51c..f35fb02bdf56 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -29,7 +29,8 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ - sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o + sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o \ + sockmap_tcp_msg_prog.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index dde2c11d7771..1558fe8bcf3e 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -123,6 +123,8 @@ static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) = (void *) BPF_FUNC_skb_under_cgroup; static int (*bpf_skb_change_head)(void *, int len, int flags) = (void *) BPF_FUNC_skb_change_head; +static int (*bpf_skb_pull_data)(void *, int len) = + (void *) BPF_FUNC_skb_pull_data; /* Scan the ARCH passed in from ARCH env variable (see Makefile) */ #if defined(__TARGET_ARCH_x86) diff --git a/tools/testing/selftests/bpf/sockmap_parse_prog.c b/tools/testing/selftests/bpf/sockmap_parse_prog.c index a1dec2b6d9c5..0f92858f6226 100644 --- a/tools/testing/selftests/bpf/sockmap_parse_prog.c +++ b/tools/testing/selftests/bpf/sockmap_parse_prog.c @@ -20,14 +20,25 @@ int bpf_prog1(struct __sk_buff *skb) __u32 lport = skb->local_port; __u32 rport = skb->remote_port; __u8 *d = data; + __u32 len = (__u32) data_end - (__u32) data; + int err; - if (data + 10 > data_end) - return skb->len; + if (data + 10 > data_end) { + err = bpf_skb_pull_data(skb, 10); + if (err) + return SK_DROP; + + data_end = (void *)(long)skb->data_end; + data = (void *)(long)skb->data; + if (data + 10 > data_end) + return SK_DROP; + } /* This write/read is a bit pointless but tests the verifier and * strparser handler for read/write pkt data and access into sk * fields. */ + d = data; d[7] = 1; return skb->len; } diff --git a/tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c b/tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c new file mode 100644 index 000000000000..12a7b5c82ed6 --- /dev/null +++ b/tools/testing/selftests/bpf/sockmap_tcp_msg_prog.c @@ -0,0 +1,33 @@ +#include +#include "bpf_helpers.h" +#include "bpf_util.h" +#include "bpf_endian.h" + +int _version SEC("version") = 1; + +#define bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +SEC("sk_msg1") +int bpf_prog1(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + + char *d; + + if (data + 8 > data_end) + return SK_DROP; + + bpf_printk("data length %i\n", (__u64)msg->data_end - (__u64)msg->data); + d = (char *)data; + bpf_printk("hello sendmsg hook %i %i\n", d[0], d[1]); + + return SK_PASS; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/sockmap_verdict_prog.c b/tools/testing/selftests/bpf/sockmap_verdict_prog.c index d7bea972cb21..2ce7634a4012 100644 --- a/tools/testing/selftests/bpf/sockmap_verdict_prog.c +++ b/tools/testing/selftests/bpf/sockmap_verdict_prog.c @@ -26,6 +26,13 @@ struct bpf_map_def SEC("maps") sock_map_tx = { .max_entries = 20, }; +struct bpf_map_def SEC("maps") sock_map_msg = { + .type = BPF_MAP_TYPE_SOCKMAP, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 20, +}; + struct bpf_map_def SEC("maps") sock_map_break = { .type = BPF_MAP_TYPE_ARRAY, .key_size = sizeof(int), diff --git a/tools/testing/selftests/bpf/test_maps.c b/tools/testing/selftests/bpf/test_maps.c index 1238733c5b33..6c253343a6f9 100644 --- a/tools/testing/selftests/bpf/test_maps.c +++ b/tools/testing/selftests/bpf/test_maps.c @@ -464,15 +464,17 @@ static void test_devmap(int task, void *data) #include #define SOCKMAP_PARSE_PROG "./sockmap_parse_prog.o" #define SOCKMAP_VERDICT_PROG "./sockmap_verdict_prog.o" +#define SOCKMAP_TCP_MSG_PROG "./sockmap_tcp_msg_prog.o" static void test_sockmap(int tasks, void *data) { - int one = 1, map_fd_rx = 0, map_fd_tx = 0, map_fd_break, s, sc, rc; - struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_break; + struct bpf_map *bpf_map_rx, *bpf_map_tx, *bpf_map_msg, *bpf_map_break; + int map_fd_msg = 0, map_fd_rx = 0, map_fd_tx = 0, map_fd_break; int ports[] = {50200, 50201, 50202, 50204}; int err, i, fd, udp, sfd[6] = {0xdeadbeef}; u8 buf[20] = {0x0, 0x5, 0x3, 0x2, 0x1, 0x0}; - int parse_prog, verdict_prog; + int parse_prog, verdict_prog, msg_prog; struct sockaddr_in addr; + int one = 1, s, sc, rc; struct bpf_object *obj; struct timeval to; __u32 key, value; @@ -584,6 +586,12 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } + err = bpf_prog_attach(-1, fd, BPF_SK_MSG_VERDICT, 0); + if (!err) { + printf("Failed invalid msg verdict prog attach\n"); + goto out_sockmap; + } + err = bpf_prog_attach(-1, fd, __MAX_BPF_ATTACH_TYPE, 0); if (!err) { printf("Failed unknown prog attach\n"); @@ -602,6 +610,12 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } + err = bpf_prog_detach(fd, BPF_SK_MSG_VERDICT); + if (err) { + printf("Failed empty msg verdict prog detach\n"); + goto out_sockmap; + } + err = bpf_prog_detach(fd, __MAX_BPF_ATTACH_TYPE); if (!err) { printf("Detach invalid prog successful\n"); @@ -616,6 +630,13 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } + err = bpf_prog_load(SOCKMAP_TCP_MSG_PROG, + BPF_PROG_TYPE_SK_MSG, &obj, &msg_prog); + if (err) { + printf("Failed to load SK_SKB msg prog\n"); + goto out_sockmap; + } + err = bpf_prog_load(SOCKMAP_VERDICT_PROG, BPF_PROG_TYPE_SK_SKB, &obj, &verdict_prog); if (err) { @@ -631,7 +652,7 @@ static void test_sockmap(int tasks, void *data) map_fd_rx = bpf_map__fd(bpf_map_rx); if (map_fd_rx < 0) { - printf("Failed to get map fd\n"); + printf("Failed to get map rx fd\n"); goto out_sockmap; } @@ -647,6 +668,18 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } + bpf_map_msg = bpf_object__find_map_by_name(obj, "sock_map_msg"); + if (IS_ERR(bpf_map_msg)) { + printf("Failed to load map msg from msg_verdict prog\n"); + goto out_sockmap; + } + + map_fd_msg = bpf_map__fd(bpf_map_msg); + if (map_fd_msg < 0) { + printf("Failed to get map msg fd\n"); + goto out_sockmap; + } + bpf_map_break = bpf_object__find_map_by_name(obj, "sock_map_break"); if (IS_ERR(bpf_map_break)) { printf("Failed to load map tx from verdict prog\n"); @@ -680,6 +713,12 @@ static void test_sockmap(int tasks, void *data) goto out_sockmap; } + err = bpf_prog_attach(msg_prog, map_fd_msg, BPF_SK_MSG_VERDICT, 0); + if (err) { + printf("Failed msg verdict bpf prog attach\n"); + goto out_sockmap; + } + err = bpf_prog_attach(verdict_prog, map_fd_rx, __MAX_BPF_ATTACH_TYPE, 0); if (!err) { @@ -719,6 +758,14 @@ static void test_sockmap(int tasks, void *data) } } + /* Put sfd[2] (sending fd below) into msg map to test sendmsg bpf */ + i = 0; + err = bpf_map_update_elem(map_fd_msg, &i, &sfd[2], BPF_ANY); + if (err) { + printf("Failed map_fd_msg update sockmap %i\n", err); + goto out_sockmap; + } + /* Test map send/recv */ for (i = 0; i < 2; i++) { buf[0] = i; -- cgit v1.3-14-g43fede From 1acc60b6a41bd4e43c3cb10e5395a5c812e158f5 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:57:36 -0700 Subject: bpf: add verifier tests for BPF_PROG_TYPE_SK_MSG Test read and writes for BPF_PROG_TYPE_SK_MSG. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_verifier.c | 54 +++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 86d7ff491b6f..3e7718b1a9ae 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -1596,6 +1596,60 @@ static struct bpf_test tests[] = { .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SK_SKB, }, + { + "direct packet read for SK_MSG", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, + offsetof(struct sk_msg_md, data)), + BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_1, + offsetof(struct sk_msg_md, data_end)), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), + BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_2, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SK_MSG, + }, + { + "direct packet write for SK_MSG", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, + offsetof(struct sk_msg_md, data)), + BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_1, + offsetof(struct sk_msg_md, data_end)), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), + BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 1), + BPF_STX_MEM(BPF_B, BPF_REG_2, BPF_REG_2, 0), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SK_MSG, + }, + { + "overlapping checks for direct packet access SK_MSG", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_2, BPF_REG_1, + offsetof(struct sk_msg_md, data)), + BPF_LDX_MEM(BPF_DW, BPF_REG_3, BPF_REG_1, + offsetof(struct sk_msg_md, data_end)), + BPF_MOV64_REG(BPF_REG_0, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_0, 8), + BPF_JMP_REG(BPF_JGT, BPF_REG_0, BPF_REG_3, 4), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_2), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 6), + BPF_JMP_REG(BPF_JGT, BPF_REG_1, BPF_REG_3, 1), + BPF_LDX_MEM(BPF_H, BPF_REG_0, BPF_REG_2, 6), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .prog_type = BPF_PROG_TYPE_SK_MSG, + }, { "check skb->mark is not writeable by sockets", .insns = { -- cgit v1.3-14-g43fede From 4c4c3c276c099f265c8b11e0132ce826ee718e2c Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:57:41 -0700 Subject: bpf: sockmap sample, add option to attach SK_MSG program Add sockmap option to use SK_MSG program types. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- samples/bpf/bpf_load.c | 8 +++- samples/sockmap/sockmap_kern.c | 52 ++++++++++++++++++++++++ samples/sockmap/sockmap_user.c | 67 ++++++++++++++++++++++++++++--- tools/include/uapi/linux/bpf.h | 13 +++++- tools/lib/bpf/libbpf.c | 1 + tools/testing/selftests/bpf/bpf_helpers.h | 3 ++ 6 files changed, 135 insertions(+), 9 deletions(-) (limited to 'tools/testing') diff --git a/samples/bpf/bpf_load.c b/samples/bpf/bpf_load.c index 69806d74fa53..b1a310c3ae89 100644 --- a/samples/bpf/bpf_load.c +++ b/samples/bpf/bpf_load.c @@ -67,6 +67,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) bool is_cgroup_sk = strncmp(event, "cgroup/sock", 11) == 0; bool is_sockops = strncmp(event, "sockops", 7) == 0; bool is_sk_skb = strncmp(event, "sk_skb", 6) == 0; + bool is_sk_msg = strncmp(event, "sk_msg", 6) == 0; size_t insns_cnt = size / sizeof(struct bpf_insn); enum bpf_prog_type prog_type; char buf[256]; @@ -96,6 +97,8 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) prog_type = BPF_PROG_TYPE_SOCK_OPS; } else if (is_sk_skb) { prog_type = BPF_PROG_TYPE_SK_SKB; + } else if (is_sk_msg) { + prog_type = BPF_PROG_TYPE_SK_MSG; } else { printf("Unknown event '%s'\n", event); return -1; @@ -113,7 +116,7 @@ static int load_and_attach(const char *event, struct bpf_insn *prog, int size) if (is_xdp || is_perf_event || is_cgroup_skb || is_cgroup_sk) return 0; - if (is_socket || is_sockops || is_sk_skb) { + if (is_socket || is_sockops || is_sk_skb || is_sk_msg) { if (is_socket) event += 6; else @@ -589,7 +592,8 @@ static int do_load_bpf_file(const char *path, fixup_map_cb fixup_map) memcmp(shname, "socket", 6) == 0 || memcmp(shname, "cgroup/", 7) == 0 || memcmp(shname, "sockops", 7) == 0 || - memcmp(shname, "sk_skb", 6) == 0) { + memcmp(shname, "sk_skb", 6) == 0 || + memcmp(shname, "sk_msg", 6) == 0) { ret = load_and_attach(shname, data->d_buf, data->d_size); if (ret != 0) diff --git a/samples/sockmap/sockmap_kern.c b/samples/sockmap/sockmap_kern.c index 52b0053274f4..75edb2f151d4 100644 --- a/samples/sockmap/sockmap_kern.c +++ b/samples/sockmap/sockmap_kern.c @@ -43,6 +43,20 @@ struct bpf_map_def SEC("maps") sock_map = { .max_entries = 20, }; +struct bpf_map_def SEC("maps") sock_map_txmsg = { + .type = BPF_MAP_TYPE_SOCKMAP, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 20, +}; + +struct bpf_map_def SEC("maps") sock_map_redir = { + .type = BPF_MAP_TYPE_SOCKMAP, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 1, +}; + SEC("sk_skb1") int bpf_prog1(struct __sk_buff *skb) { @@ -105,4 +119,42 @@ int bpf_sockmap(struct bpf_sock_ops *skops) return 0; } + +SEC("sk_msg1") +int bpf_prog4(struct sk_msg_md *msg) +{ + return SK_PASS; +} + +SEC("sk_msg2") +int bpf_prog5(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + + bpf_printk("sk_msg2: data length %i\n", (__u32)data_end - (__u32)data); + return SK_PASS; +} + +SEC("sk_msg3") +int bpf_prog6(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + int ret = 0; + + return bpf_msg_redirect_map(msg, &sock_map_redir, ret, 0); +} + +SEC("sk_msg4") +int bpf_prog7(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + int ret = 0; + + bpf_printk("sk_msg3: redirect(%iB)\n", (__u32)data_end - (__u32)data); + return bpf_msg_redirect_map(msg, &sock_map_redir, ret, 0); +} + char _license[] SEC("license") = "GPL"; diff --git a/samples/sockmap/sockmap_user.c b/samples/sockmap/sockmap_user.c index 95a54a89a532..bbfe3a2b9885 100644 --- a/samples/sockmap/sockmap_user.c +++ b/samples/sockmap/sockmap_user.c @@ -54,6 +54,11 @@ void running_handler(int a); /* global sockets */ int s1, s2, c1, c2, p1, p2; +int txmsg_pass; +int txmsg_noisy; +int txmsg_redir; +int txmsg_redir_noisy; + static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, {"cgroup", required_argument, NULL, 'c' }, @@ -62,6 +67,10 @@ static const struct option long_options[] = { {"iov_count", required_argument, NULL, 'i' }, {"length", required_argument, NULL, 'l' }, {"test", required_argument, NULL, 't' }, + {"txmsg", no_argument, &txmsg_pass, 1 }, + {"txmsg_noisy", no_argument, &txmsg_noisy, 1 }, + {"txmsg_redir", no_argument, &txmsg_redir, 1 }, + {"txmsg_redir_noisy", no_argument, &txmsg_redir_noisy, 1}, {0, 0, NULL, 0 } }; @@ -447,13 +456,13 @@ enum { int main(int argc, char **argv) { - int iov_count = 1, length = 1024, rate = 1, verbose = 0; + int iov_count = 1, length = 1024, rate = 1, verbose = 0, tx_prog_fd; struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY}; int opt, longindex, err, cg_fd = 0; int test = PING_PONG; char filename[256]; - while ((opt = getopt_long(argc, argv, "hvc:r:i:l:t:", + while ((opt = getopt_long(argc, argv, ":hvc:r:i:l:t:", long_options, &longindex)) != -1) { switch (opt) { /* Cgroup configuration */ @@ -490,6 +499,8 @@ int main(int argc, char **argv) return -1; } break; + case 0: + break; case 'h': default: usage(argv); @@ -515,16 +526,16 @@ int main(int argc, char **argv) /* catch SIGINT */ signal(SIGINT, running_handler); - /* If base test skip BPF setup */ - if (test == BASE) - goto run; - if (load_bpf_file(filename)) { fprintf(stderr, "load_bpf_file: (%s) %s\n", filename, strerror(errno)); return 1; } + /* If base test skip BPF setup */ + if (test == BASE) + goto run; + /* Attach programs to sockmap */ err = bpf_prog_attach(prog_fd[0], map_fd[0], BPF_SK_SKB_STREAM_PARSER, 0); @@ -557,6 +568,50 @@ run: goto out; } + /* Attach txmsg program to sockmap */ + if (txmsg_pass) + tx_prog_fd = prog_fd[3]; + else if (txmsg_noisy) + tx_prog_fd = prog_fd[4]; + else if (txmsg_redir) + tx_prog_fd = prog_fd[5]; + else if (txmsg_redir_noisy) + tx_prog_fd = prog_fd[6]; + else + tx_prog_fd = 0; + + if (tx_prog_fd) { + int redir_fd, i = 0; + + err = bpf_prog_attach(tx_prog_fd, + map_fd[1], BPF_SK_MSG_VERDICT, 0); + if (err) { + fprintf(stderr, + "ERROR: bpf_prog_attach (txmsg): %d (%s)\n", + err, strerror(errno)); + return err; + } + + err = bpf_map_update_elem(map_fd[1], &i, &c1, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (txmsg): %d (%s\n", + err, strerror(errno)); + return err; + } + if (test == SENDMSG) + redir_fd = c2; + else + redir_fd = c1; + + err = bpf_map_update_elem(map_fd[2], &i, &redir_fd, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (txmsg): %d (%s\n", + err, strerror(errno)); + return err; + } + } if (test == PING_PONG) err = forever_ping_pong(rate, verbose); else if (test == SENDMSG) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 13d9c59d79ce..01b9c97b172e 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -720,6 +720,15 @@ union bpf_attr { * int bpf_override_return(pt_regs, rc) * @pt_regs: pointer to struct pt_regs * @rc: the return value to set + * + * int bpf_msg_redirect_map(map, key, flags) + * Redirect msg to a sock in map using key as a lookup key for the + * sock in map. + * @map: pointer to sockmap + * @key: key to lookup sock in map + * @flags: reserved for future use + * Return: SK_PASS + * */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -781,7 +790,9 @@ union bpf_attr { FN(perf_prog_read_value), \ FN(getsockopt), \ FN(override_return), \ - FN(sock_ops_cb_flags_set), + FN(sock_ops_cb_flags_set), \ + FN(msg_redirect_map), \ + FN(msg_apply_bytes), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 5bbbf285af74..64a8fc384186 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1857,6 +1857,7 @@ static const struct { BPF_PROG_SEC("lwt_xmit", BPF_PROG_TYPE_LWT_XMIT), BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS), BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), + BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), }; #undef BPF_PROG_SEC diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 1558fe8bcf3e..bba7ee6d93ab 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -86,6 +86,9 @@ static int (*bpf_perf_prog_read_value)(void *ctx, void *buf, (void *) BPF_FUNC_perf_prog_read_value; static int (*bpf_override_return)(void *ctx, unsigned long rc) = (void *) BPF_FUNC_override_return; +static int (*bpf_msg_redirect_map)(void *ctx, void *map, int key, int flags) = + (void *) BPF_FUNC_msg_redirect_map; + /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- cgit v1.3-14-g43fede From 1c16c3126ac938562a68ab7041fe74ce0de53166 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:57:56 -0700 Subject: bpf: sockmap, add sample option to test apply_bytes helper This adds an option to test the apply_bytes helper. This option lets the user specify an int on the command line specifying how much data each verdict should apply to. When this is set a map entry is set with the bytes input by the user and then the specified program --txmsg or --txmsg_redir will use the value and set the applied data. If no other option is set then a default --txmsg_apply program is run. This program will drop pkts if an error is detected on the bytes map lookup. Useful to verify the map lookup and apply helper are working and causing a hard error if it is not. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- samples/sockmap/sockmap_kern.c | 54 +++++++++++++++++++++++++++---- samples/sockmap/sockmap_user.c | 19 ++++++++++- tools/testing/selftests/bpf/bpf_helpers.h | 3 +- 3 files changed, 68 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/samples/sockmap/sockmap_kern.c b/samples/sockmap/sockmap_kern.c index 75edb2f151d4..205ec36449d1 100644 --- a/samples/sockmap/sockmap_kern.c +++ b/samples/sockmap/sockmap_kern.c @@ -57,6 +57,13 @@ struct bpf_map_def SEC("maps") sock_map_redir = { .max_entries = 1, }; +struct bpf_map_def SEC("maps") sock_apply_bytes = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 1 +}; + SEC("sk_skb1") int bpf_prog1(struct __sk_buff *skb) { @@ -123,6 +130,11 @@ int bpf_sockmap(struct bpf_sock_ops *skops) SEC("sk_msg1") int bpf_prog4(struct sk_msg_md *msg) { + int *bytes, zero = 0; + + bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); + if (bytes) + bpf_msg_apply_bytes(msg, *bytes); return SK_PASS; } @@ -131,8 +143,13 @@ int bpf_prog5(struct sk_msg_md *msg) { void *data_end = (void *)(long) msg->data_end; void *data = (void *)(long) msg->data; + int *bytes, err = 0, zero = 0; - bpf_printk("sk_msg2: data length %i\n", (__u32)data_end - (__u32)data); + bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); + if (bytes) + err = bpf_msg_apply_bytes(msg, *bytes); + bpf_printk("sk_msg2: data length %i err %i\n", + (__u64)data_end - (__u64)data, err); return SK_PASS; } @@ -141,9 +158,12 @@ int bpf_prog6(struct sk_msg_md *msg) { void *data_end = (void *)(long) msg->data_end; void *data = (void *)(long) msg->data; - int ret = 0; + int *bytes, zero = 0; - return bpf_msg_redirect_map(msg, &sock_map_redir, ret, 0); + bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); + if (bytes) + bpf_msg_apply_bytes(msg, *bytes); + return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); } SEC("sk_msg4") @@ -151,10 +171,32 @@ int bpf_prog7(struct sk_msg_md *msg) { void *data_end = (void *)(long) msg->data_end; void *data = (void *)(long) msg->data; - int ret = 0; + int *bytes, err = 0, zero = 0; + + bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); + if (bytes) + err = bpf_msg_apply_bytes(msg, *bytes); + bpf_printk("sk_msg3: redirect(%iB) err=%i\n", + (__u64)data_end - (__u64)data, err); + return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); +} - bpf_printk("sk_msg3: redirect(%iB)\n", (__u32)data_end - (__u32)data); - return bpf_msg_redirect_map(msg, &sock_map_redir, ret, 0); +SEC("sk_msg5") +int bpf_prog8(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + int ret = 0, *bytes, zero = 0; + + bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); + if (bytes) { + ret = bpf_msg_apply_bytes(msg, *bytes); + if (ret) + return SK_DROP; + } else { + return SK_DROP; + } + return SK_PASS; } char _license[] SEC("license") = "GPL"; diff --git a/samples/sockmap/sockmap_user.c b/samples/sockmap/sockmap_user.c index 8017ad7afea9..41774ec0f0b3 100644 --- a/samples/sockmap/sockmap_user.c +++ b/samples/sockmap/sockmap_user.c @@ -59,6 +59,7 @@ int txmsg_pass; int txmsg_noisy; int txmsg_redir; int txmsg_redir_noisy; +int txmsg_apply; static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, @@ -73,6 +74,7 @@ static const struct option long_options[] = { {"txmsg_noisy", no_argument, &txmsg_noisy, 1 }, {"txmsg_redir", no_argument, &txmsg_redir, 1 }, {"txmsg_redir_noisy", no_argument, &txmsg_redir_noisy, 1}, + {"txmsg_apply", required_argument, NULL, 'a'}, {0, 0, NULL, 0 } }; @@ -546,7 +548,9 @@ int main(int argc, char **argv) while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:", long_options, &longindex)) != -1) { switch (opt) { - /* Cgroup configuration */ + case 'a': + txmsg_apply = atoi(optarg); + break; case 'c': cg_fd = open(optarg, O_DIRECTORY, O_RDONLY); if (cg_fd < 0) { @@ -665,6 +669,8 @@ run: tx_prog_fd = prog_fd[5]; else if (txmsg_redir_noisy) tx_prog_fd = prog_fd[6]; + else if (txmsg_apply) + tx_prog_fd = prog_fd[7]; else tx_prog_fd = 0; @@ -699,6 +705,17 @@ run: err, strerror(errno)); return err; } + + if (txmsg_apply) { + err = bpf_map_update_elem(map_fd[3], + &i, &txmsg_apply, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (apply_bytes): %d (%s\n", + err, strerror(errno)); + return err; + } + } } if (test == PING_PONG) err = forever_ping_pong(rate, &options); diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index bba7ee6d93ab..4713de48cf88 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -88,7 +88,8 @@ static int (*bpf_override_return)(void *ctx, unsigned long rc) = (void *) BPF_FUNC_override_return; static int (*bpf_msg_redirect_map)(void *ctx, void *map, int key, int flags) = (void *) BPF_FUNC_msg_redirect_map; - +static int (*bpf_msg_apply_bytes)(void *ctx, int len) = + (void *) BPF_FUNC_msg_apply_bytes; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- cgit v1.3-14-g43fede From 468b3fdea8826b232a570d95ba45272eb38919cb Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:58:02 -0700 Subject: bpf: sockmap sample support for bpf_msg_cork_bytes() Add sample application support for the bpf_msg_cork_bytes helper. This lets the user specify how many bytes each verdict should apply to. Similar to apply_bytes() tests these can be run as a stand-alone test when used without other options or inline with other tests by using the txmsg_cork option along with any of the basic tests txmsg, txmsg_redir, txmsg_drop. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- samples/sockmap/sockmap_kern.c | 53 ++++++++++++++++++++++++++----- samples/sockmap/sockmap_user.c | 19 +++++++++++ tools/include/uapi/linux/bpf.h | 3 +- tools/testing/selftests/bpf/bpf_helpers.h | 2 ++ 4 files changed, 68 insertions(+), 9 deletions(-) (limited to 'tools/testing') diff --git a/samples/sockmap/sockmap_kern.c b/samples/sockmap/sockmap_kern.c index 205ec36449d1..735226794ce1 100644 --- a/samples/sockmap/sockmap_kern.c +++ b/samples/sockmap/sockmap_kern.c @@ -64,6 +64,13 @@ struct bpf_map_def SEC("maps") sock_apply_bytes = { .max_entries = 1 }; +struct bpf_map_def SEC("maps") sock_cork_bytes = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 1 +}; + SEC("sk_skb1") int bpf_prog1(struct __sk_buff *skb) { @@ -135,6 +142,9 @@ int bpf_prog4(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) bpf_msg_apply_bytes(msg, *bytes); + bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); + if (bytes) + bpf_msg_cork_bytes(msg, *bytes); return SK_PASS; } @@ -143,13 +153,16 @@ int bpf_prog5(struct sk_msg_md *msg) { void *data_end = (void *)(long) msg->data_end; void *data = (void *)(long) msg->data; - int *bytes, err = 0, zero = 0; + int *bytes, err1 = -1, err2 = -1, zero = 0; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) - err = bpf_msg_apply_bytes(msg, *bytes); - bpf_printk("sk_msg2: data length %i err %i\n", - (__u64)data_end - (__u64)data, err); + err1 = bpf_msg_apply_bytes(msg, *bytes); + bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); + if (bytes) + err2 = bpf_msg_cork_bytes(msg, *bytes); + bpf_printk("sk_msg2: data length %i err1 %i err2 %i\n", + (__u64)data_end - (__u64)data, err1, err2); return SK_PASS; } @@ -163,6 +176,9 @@ int bpf_prog6(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) bpf_msg_apply_bytes(msg, *bytes); + bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); + if (bytes) + bpf_msg_cork_bytes(msg, *bytes); return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); } @@ -171,13 +187,17 @@ int bpf_prog7(struct sk_msg_md *msg) { void *data_end = (void *)(long) msg->data_end; void *data = (void *)(long) msg->data; - int *bytes, err = 0, zero = 0; + int *bytes, err1 = 0, err2 = 0, zero = 0; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) - err = bpf_msg_apply_bytes(msg, *bytes); - bpf_printk("sk_msg3: redirect(%iB) err=%i\n", - (__u64)data_end - (__u64)data, err); + err1 = bpf_msg_apply_bytes(msg, *bytes); + bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); + if (bytes) + err2 = bpf_msg_cork_bytes(msg, *bytes); + + bpf_printk("sk_msg3: redirect(%iB) err1=%i err2=%i\n", + (__u64)data_end - (__u64)data, err1, err2); return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); } @@ -198,5 +218,22 @@ int bpf_prog8(struct sk_msg_md *msg) } return SK_PASS; } +SEC("sk_msg6") +int bpf_prog9(struct sk_msg_md *msg) +{ + void *data_end = (void *)(long) msg->data_end; + void *data = (void *)(long) msg->data; + int ret = 0, *bytes, zero = 0; + + bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); + if (bytes) { + if (((__u64)data_end - (__u64)data) >= *bytes) + return SK_PASS; + ret = bpf_msg_cork_bytes(msg, *bytes); + if (ret) + return SK_DROP; + } + return SK_PASS; +} char _license[] SEC("license") = "GPL"; diff --git a/samples/sockmap/sockmap_user.c b/samples/sockmap/sockmap_user.c index 41774ec0f0b3..4e0a3d87881f 100644 --- a/samples/sockmap/sockmap_user.c +++ b/samples/sockmap/sockmap_user.c @@ -60,6 +60,7 @@ int txmsg_noisy; int txmsg_redir; int txmsg_redir_noisy; int txmsg_apply; +int txmsg_cork; static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, @@ -75,6 +76,7 @@ static const struct option long_options[] = { {"txmsg_redir", no_argument, &txmsg_redir, 1 }, {"txmsg_redir_noisy", no_argument, &txmsg_redir_noisy, 1}, {"txmsg_apply", required_argument, NULL, 'a'}, + {"txmsg_cork", required_argument, NULL, 'k'}, {0, 0, NULL, 0 } }; @@ -551,6 +553,9 @@ int main(int argc, char **argv) case 'a': txmsg_apply = atoi(optarg); break; + case 'k': + txmsg_cork = atoi(optarg); + break; case 'c': cg_fd = open(optarg, O_DIRECTORY, O_RDONLY); if (cg_fd < 0) { @@ -671,6 +676,8 @@ run: tx_prog_fd = prog_fd[6]; else if (txmsg_apply) tx_prog_fd = prog_fd[7]; + else if (txmsg_cork) + tx_prog_fd = prog_fd[8]; else tx_prog_fd = 0; @@ -716,6 +723,18 @@ run: return err; } } + + if (txmsg_cork) { + err = bpf_map_update_elem(map_fd[4], + &i, &txmsg_cork, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (cork_bytes): %d (%s\n", + err, strerror(errno)); + return err; + } + } + } if (test == PING_PONG) err = forever_ping_pong(rate, &options); diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 01b9c97b172e..e6924ab20fc3 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -792,7 +792,8 @@ union bpf_attr { FN(override_return), \ FN(sock_ops_cb_flags_set), \ FN(msg_redirect_map), \ - FN(msg_apply_bytes), + FN(msg_apply_bytes), \ + FN(msg_cork_bytes), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 4713de48cf88..b5b45ff705ff 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -90,6 +90,8 @@ static int (*bpf_msg_redirect_map)(void *ctx, void *map, int key, int flags) = (void *) BPF_FUNC_msg_redirect_map; static int (*bpf_msg_apply_bytes)(void *ctx, int len) = (void *) BPF_FUNC_msg_apply_bytes; +static int (*bpf_msg_cork_bytes)(void *ctx, int len) = + (void *) BPF_FUNC_msg_cork_bytes; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- cgit v1.3-14-g43fede From 0dcbbf6785799ba05b44df2ba6bcc1195f4f945c Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sun, 18 Mar 2018 12:58:12 -0700 Subject: bpf: sockmap sample test for bpf_msg_pull_data This adds an option to test the msg_pull_data helper. This uses two options txmsg_start and txmsg_end to let the user specify start and end bytes to pull. The options can be used with txmsg_apply, txmsg_cork options as well as with any of the basic tests, txmsg, txmsg_redir and txmsg_drop (plus noisy variants) to run pull_data inline with those tests. By giving user direct control over the variables we can easily do negative testing as well as positive tests. Signed-off-by: John Fastabend Acked-by: David S. Miller Signed-off-by: Daniel Borkmann --- samples/sockmap/sockmap_kern.c | 79 +++++++++++++++++++++++++------ samples/sockmap/sockmap_user.c | 32 +++++++++++++ tools/include/uapi/linux/bpf.h | 3 +- tools/testing/selftests/bpf/bpf_helpers.h | 2 + 4 files changed, 101 insertions(+), 15 deletions(-) (limited to 'tools/testing') diff --git a/samples/sockmap/sockmap_kern.c b/samples/sockmap/sockmap_kern.c index 8b6c34cd5f46..9ad5ba79c85a 100644 --- a/samples/sockmap/sockmap_kern.c +++ b/samples/sockmap/sockmap_kern.c @@ -71,6 +71,14 @@ struct bpf_map_def SEC("maps") sock_cork_bytes = { .max_entries = 1 }; +struct bpf_map_def SEC("maps") sock_pull_bytes = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(int), + .value_size = sizeof(int), + .max_entries = 2 +}; + + SEC("sk_skb1") int bpf_prog1(struct __sk_buff *skb) { @@ -137,7 +145,8 @@ int bpf_sockmap(struct bpf_sock_ops *skops) SEC("sk_msg1") int bpf_prog4(struct sk_msg_md *msg) { - int *bytes, zero = 0; + int *bytes, zero = 0, one = 1; + int *start, *end; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) @@ -145,15 +154,18 @@ int bpf_prog4(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); if (bytes) bpf_msg_cork_bytes(msg, *bytes); + start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); + end = bpf_map_lookup_elem(&sock_pull_bytes, &one); + if (start && end) + bpf_msg_pull_data(msg, *start, *end, 0); return SK_PASS; } SEC("sk_msg2") int bpf_prog5(struct sk_msg_md *msg) { - void *data_end = (void *)(long) msg->data_end; - void *data = (void *)(long) msg->data; - int *bytes, err1 = -1, err2 = -1, zero = 0; + int err1 = -1, err2 = -1, zero = 0, one = 1; + int *bytes, *start, *end, len1, len2; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) @@ -161,17 +173,32 @@ int bpf_prog5(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); if (bytes) err2 = bpf_msg_cork_bytes(msg, *bytes); + len1 = (__u64)msg->data_end - (__u64)msg->data; + start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); + end = bpf_map_lookup_elem(&sock_pull_bytes, &one); + if (start && end) { + int err; + + bpf_printk("sk_msg2: pull(%i:%i)\n", + start ? *start : 0, end ? *end : 0); + err = bpf_msg_pull_data(msg, *start, *end, 0); + if (err) + bpf_printk("sk_msg2: pull_data err %i\n", + err); + len2 = (__u64)msg->data_end - (__u64)msg->data; + bpf_printk("sk_msg2: length update %i->%i\n", + len1, len2); + } bpf_printk("sk_msg2: data length %i err1 %i err2 %i\n", - (__u64)data_end - (__u64)data, err1, err2); + len1, err1, err2); return SK_PASS; } SEC("sk_msg3") int bpf_prog6(struct sk_msg_md *msg) { - void *data_end = (void *)(long) msg->data_end; - void *data = (void *)(long) msg->data; - int *bytes, zero = 0; + int *bytes, zero = 0, one = 1; + int *start, *end; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) @@ -179,15 +206,18 @@ int bpf_prog6(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); if (bytes) bpf_msg_cork_bytes(msg, *bytes); + start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); + end = bpf_map_lookup_elem(&sock_pull_bytes, &one); + if (start && end) + bpf_msg_pull_data(msg, *start, *end, 0); return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); } SEC("sk_msg4") int bpf_prog7(struct sk_msg_md *msg) { - void *data_end = (void *)(long) msg->data_end; - void *data = (void *)(long) msg->data; - int *bytes, err1 = 0, err2 = 0, zero = 0; + int err1 = 0, err2 = 0, zero = 0, one = 1; + int *bytes, *start, *end, len1, len2; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) @@ -195,9 +225,24 @@ int bpf_prog7(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); if (bytes) err2 = bpf_msg_cork_bytes(msg, *bytes); - + len1 = (__u64)msg->data_end - (__u64)msg->data; + start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); + end = bpf_map_lookup_elem(&sock_pull_bytes, &one); + if (start && end) { + int err; + + bpf_printk("sk_msg2: pull(%i:%i)\n", + start ? *start : 0, end ? *end : 0); + err = bpf_msg_pull_data(msg, *start, *end, 0); + if (err) + bpf_printk("sk_msg2: pull_data err %i\n", + err); + len2 = (__u64)msg->data_end - (__u64)msg->data; + bpf_printk("sk_msg2: length update %i->%i\n", + len1, len2); + } bpf_printk("sk_msg3: redirect(%iB) err1=%i err2=%i\n", - (__u64)data_end - (__u64)data, err1, err2); + len1, err1, err2); return bpf_msg_redirect_map(msg, &sock_map_redir, zero, 0); } @@ -239,7 +284,8 @@ int bpf_prog9(struct sk_msg_md *msg) SEC("sk_msg7") int bpf_prog10(struct sk_msg_md *msg) { - int *bytes, zero = 0; + int *bytes, zero = 0, one = 1; + int *start, *end; bytes = bpf_map_lookup_elem(&sock_apply_bytes, &zero); if (bytes) @@ -247,6 +293,11 @@ int bpf_prog10(struct sk_msg_md *msg) bytes = bpf_map_lookup_elem(&sock_cork_bytes, &zero); if (bytes) bpf_msg_cork_bytes(msg, *bytes); + start = bpf_map_lookup_elem(&sock_pull_bytes, &zero); + end = bpf_map_lookup_elem(&sock_pull_bytes, &one); + if (start && end) + bpf_msg_pull_data(msg, *start, *end, 0); + return SK_DROP; } diff --git a/samples/sockmap/sockmap_user.c b/samples/sockmap/sockmap_user.c index 52c4ed7774d4..07aa237221d1 100644 --- a/samples/sockmap/sockmap_user.c +++ b/samples/sockmap/sockmap_user.c @@ -62,6 +62,8 @@ int txmsg_redir_noisy; int txmsg_drop; int txmsg_apply; int txmsg_cork; +int txmsg_start; +int txmsg_end; static const struct option long_options[] = { {"help", no_argument, NULL, 'h' }, @@ -79,6 +81,8 @@ static const struct option long_options[] = { {"txmsg_drop", no_argument, &txmsg_drop, 1 }, {"txmsg_apply", required_argument, NULL, 'a'}, {"txmsg_cork", required_argument, NULL, 'k'}, + {"txmsg_start", required_argument, NULL, 's'}, + {"txmsg_end", required_argument, NULL, 'e'}, {0, 0, NULL, 0 } }; @@ -572,6 +576,12 @@ int main(int argc, char **argv) while ((opt = getopt_long(argc, argv, ":dhvc:r:i:l:t:", long_options, &longindex)) != -1) { switch (opt) { + case 's': + txmsg_start = atoi(optarg); + break; + case 'e': + txmsg_end = atoi(optarg); + break; case 'a': txmsg_apply = atoi(optarg); break; @@ -761,6 +771,28 @@ run: } } + if (txmsg_start) { + err = bpf_map_update_elem(map_fd[5], + &i, &txmsg_start, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (txmsg_start): %d (%s)\n", + err, strerror(errno)); + return err; + } + } + + if (txmsg_end) { + i = 1; + err = bpf_map_update_elem(map_fd[5], + &i, &txmsg_end, BPF_ANY); + if (err) { + fprintf(stderr, + "ERROR: bpf_map_update_elem (txmsg_end): %d (%s)\n", + err, strerror(errno)); + return err; + } + } } if (txmsg_drop) diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e6924ab20fc3..d245c41213ac 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -793,7 +793,8 @@ union bpf_attr { FN(sock_ops_cb_flags_set), \ FN(msg_redirect_map), \ FN(msg_apply_bytes), \ - FN(msg_cork_bytes), + FN(msg_cork_bytes), \ + FN(msg_pull_data), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index b5b45ff705ff..7cae376d8d0c 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -92,6 +92,8 @@ static int (*bpf_msg_apply_bytes)(void *ctx, int len) = (void *) BPF_FUNC_msg_apply_bytes; static int (*bpf_msg_cork_bytes)(void *ctx, int len) = (void *) BPF_FUNC_msg_cork_bytes; +static int (*bpf_msg_pull_data)(void *ctx, int start, int end, int flags) = + (void *) BPF_FUNC_msg_pull_data; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions -- cgit v1.3-14-g43fede From dd40c5b4c90d84d30cdb452c2d193d6fb42247df Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 6 Mar 2018 23:24:58 +1000 Subject: selftests/powerpc: Add process creation benchmark Signed-off-by: Nicholas Piggin [mpe: Add SPDX, and fixup formatting] Signed-off-by: Michael Ellerman --- .../selftests/powerpc/benchmarks/.gitignore | 2 + .../testing/selftests/powerpc/benchmarks/Makefile | 7 +- .../selftests/powerpc/benchmarks/exec_target.c | 13 + tools/testing/selftests/powerpc/benchmarks/fork.c | 325 +++++++++++++++++++++ 4 files changed, 346 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/powerpc/benchmarks/exec_target.c create mode 100644 tools/testing/selftests/powerpc/benchmarks/fork.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/powerpc/benchmarks/.gitignore b/tools/testing/selftests/powerpc/benchmarks/.gitignore index 04dc1e6ef2ce..9161679b1e1a 100644 --- a/tools/testing/selftests/powerpc/benchmarks/.gitignore +++ b/tools/testing/selftests/powerpc/benchmarks/.gitignore @@ -1,5 +1,7 @@ gettimeofday context_switch +fork +exec_target mmap_bench futex_bench null_syscall diff --git a/tools/testing/selftests/powerpc/benchmarks/Makefile b/tools/testing/selftests/powerpc/benchmarks/Makefile index a35058e3766c..b4d7432a0ecd 100644 --- a/tools/testing/selftests/powerpc/benchmarks/Makefile +++ b/tools/testing/selftests/powerpc/benchmarks/Makefile @@ -1,5 +1,6 @@ # SPDX-License-Identifier: GPL-2.0 -TEST_GEN_PROGS := gettimeofday context_switch mmap_bench futex_bench null_syscall +TEST_GEN_PROGS := gettimeofday context_switch fork mmap_bench futex_bench null_syscall +TEST_GEN_FILES := exec_target CFLAGS += -O2 @@ -10,3 +11,7 @@ $(TEST_GEN_PROGS): ../harness.c $(OUTPUT)/context_switch: ../utils.c $(OUTPUT)/context_switch: CFLAGS += -maltivec -mvsx -mabi=altivec $(OUTPUT)/context_switch: LDLIBS += -lpthread + +$(OUTPUT)/fork: LDLIBS += -lpthread + +$(OUTPUT)/exec_target: CFLAGS += -static -nostartfiles diff --git a/tools/testing/selftests/powerpc/benchmarks/exec_target.c b/tools/testing/selftests/powerpc/benchmarks/exec_target.c new file mode 100644 index 000000000000..3c9c144192be --- /dev/null +++ b/tools/testing/selftests/powerpc/benchmarks/exec_target.c @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Part of fork context switch microbenchmark. + * + * Copyright 2018, Anton Blanchard, IBM Corp. + */ + +void _exit(int); +void _start(void) +{ + _exit(0); +} diff --git a/tools/testing/selftests/powerpc/benchmarks/fork.c b/tools/testing/selftests/powerpc/benchmarks/fork.c new file mode 100644 index 000000000000..d312e638cb37 --- /dev/null +++ b/tools/testing/selftests/powerpc/benchmarks/fork.c @@ -0,0 +1,325 @@ +// SPDX-License-Identifier: GPL-2.0+ + +/* + * Context switch microbenchmark. + * + * Copyright 2018, Anton Blanchard, IBM Corp. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int timeout = 30; + +static void set_cpu(int cpu) +{ + cpu_set_t cpuset; + + if (cpu == -1) + return; + + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + + if (sched_setaffinity(0, sizeof(cpuset), &cpuset)) { + perror("sched_setaffinity"); + exit(1); + } +} + +static void start_process_on(void *(*fn)(void *), void *arg, int cpu) +{ + int pid; + + pid = fork(); + if (pid == -1) { + perror("fork"); + exit(1); + } + + if (pid) + return; + + set_cpu(cpu); + + fn(arg); + + exit(0); +} + +static int cpu; +static int do_fork = 0; +static int do_vfork = 0; +static int do_exec = 0; +static char *exec_file; +static int exec_target = 0; +static unsigned long iterations; +static unsigned long iterations_prev; + +static void run_exec(void) +{ + char *const argv[] = { "./exec_target", NULL }; + + if (execve("./exec_target", argv, NULL) == -1) { + perror("execve"); + exit(1); + } +} + +static void bench_fork(void) +{ + while (1) { + pid_t pid = fork(); + if (pid == -1) { + perror("fork"); + exit(1); + } + if (pid == 0) { + if (do_exec) + run_exec(); + _exit(0); + } + pid = waitpid(pid, NULL, 0); + if (pid == -1) { + perror("waitpid"); + exit(1); + } + iterations++; + } +} + +static void bench_vfork(void) +{ + while (1) { + pid_t pid = vfork(); + if (pid == -1) { + perror("fork"); + exit(1); + } + if (pid == 0) { + if (do_exec) + run_exec(); + _exit(0); + } + pid = waitpid(pid, NULL, 0); + if (pid == -1) { + perror("waitpid"); + exit(1); + } + iterations++; + } +} + +static void *null_fn(void *arg) +{ + pthread_exit(NULL); +} + +static void bench_thread(void) +{ + pthread_t tid; + cpu_set_t cpuset; + pthread_attr_t attr; + int rc; + + rc = pthread_attr_init(&attr); + if (rc) { + errno = rc; + perror("pthread_attr_init"); + exit(1); + } + + if (cpu != -1) { + CPU_ZERO(&cpuset); + CPU_SET(cpu, &cpuset); + + rc = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset); + if (rc) { + errno = rc; + perror("pthread_attr_setaffinity_np"); + exit(1); + } + } + + while (1) { + rc = pthread_create(&tid, &attr, null_fn, NULL); + if (rc) { + errno = rc; + perror("pthread_create"); + exit(1); + } + rc = pthread_join(tid, NULL); + if (rc) { + errno = rc; + perror("pthread_join"); + exit(1); + } + iterations++; + } +} + +static void sigalrm_handler(int junk) +{ + unsigned long i = iterations; + + printf("%ld\n", i - iterations_prev); + iterations_prev = i; + + if (--timeout == 0) + kill(0, SIGUSR1); + + alarm(1); +} + +static void sigusr1_handler(int junk) +{ + exit(0); +} + +static void *bench_proc(void *arg) +{ + signal(SIGALRM, sigalrm_handler); + alarm(1); + + if (do_fork) + bench_fork(); + else if (do_vfork) + bench_vfork(); + else + bench_thread(); + + return NULL; +} + +static struct option options[] = { + { "fork", no_argument, &do_fork, 1 }, + { "vfork", no_argument, &do_vfork, 1 }, + { "exec", no_argument, &do_exec, 1 }, + { "timeout", required_argument, 0, 's' }, + { "exec-target", no_argument, &exec_target, 1 }, + { NULL }, +}; + +static void usage(void) +{ + fprintf(stderr, "Usage: fork CPU\n\n"); + fprintf(stderr, "\t\t--fork\tUse fork() (default threads)\n"); + fprintf(stderr, "\t\t--vfork\tUse vfork() (default threads)\n"); + fprintf(stderr, "\t\t--exec\tAlso exec() (default no exec)\n"); + fprintf(stderr, "\t\t--timeout=X\tDuration in seconds to run (default 30)\n"); + fprintf(stderr, "\t\t--exec-target\tInternal option for exec workload\n"); +} + +int main(int argc, char *argv[]) +{ + signed char c; + + while (1) { + int option_index = 0; + + c = getopt_long(argc, argv, "", options, &option_index); + + if (c == -1) + break; + + switch (c) { + case 0: + if (options[option_index].flag != 0) + break; + + usage(); + exit(1); + break; + + case 's': + timeout = atoi(optarg); + break; + + default: + usage(); + exit(1); + } + } + + if (do_fork && do_vfork) { + usage(); + exit(1); + } + if (do_exec && !do_fork && !do_vfork) { + usage(); + exit(1); + } + + if (do_exec) { + char *dirname = strdup(argv[0]); + int i; + i = strlen(dirname) - 1; + while (i) { + if (dirname[i] == '/') { + dirname[i] = '\0'; + if (chdir(dirname) == -1) { + perror("chdir"); + exit(1); + } + break; + } + i--; + } + } + + if (exec_target) { + exit(0); + } + + if (((argc - optind) != 1)) { + cpu = -1; + } else { + cpu = atoi(argv[optind++]); + } + + if (do_exec) + exec_file = argv[0]; + + set_cpu(cpu); + + printf("Using "); + if (do_fork) + printf("fork"); + else if (do_vfork) + printf("vfork"); + else + printf("clone"); + + if (do_exec) + printf(" + exec"); + + printf(" on cpu %d\n", cpu); + + /* Create a new process group so we can signal everyone for exit */ + setpgid(getpid(), getpid()); + + signal(SIGUSR1, sigusr1_handler); + + start_process_on(bench_proc, NULL, cpu); + + while (1) + sleep(3600); + + return 0; +} -- cgit v1.3-14-g43fede From f5a614519e67b429faf01ca36db90030976449cc Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 10 Mar 2018 06:14:53 -0800 Subject: test_firmware: expand on library with shared helpers This expands our library with as many things we could find which both scripts we use share. Signed-off-by: Luis R. Rodriguez Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/firmware/fw_fallback.sh | 31 +++----------- tools/testing/selftests/firmware/fw_filesystem.sh | 41 +++--------------- tools/testing/selftests/firmware/fw_lib.sh | 52 +++++++++++++++++++++++ 3 files changed, 63 insertions(+), 61 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/firmware/fw_fallback.sh b/tools/testing/selftests/firmware/fw_fallback.sh index 323c921a2469..9337a0328627 100755 --- a/tools/testing/selftests/firmware/fw_fallback.sh +++ b/tools/testing/selftests/firmware/fw_fallback.sh @@ -6,30 +6,17 @@ # won't find so that we can do the load ourself manually. set -e +TEST_REQS_FW_SYSFS_FALLBACK="yes" +TEST_REQS_FW_SET_CUSTOM_PATH="no" TEST_DIR=$(dirname $0) source $TEST_DIR/fw_lib.sh check_mods +check_setup +verify_reqs +setup_tmp_file -HAS_FW_LOADER_USER_HELPER=$(kconfig_has CONFIG_FW_LOADER_USER_HELPER=y) -HAS_FW_LOADER_USER_HELPER_FALLBACK=$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y) - -if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then - OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) -else - echo "usermode helper disabled so ignoring test" - exit 0 -fi - -FWPATH=$(mktemp -d) -FW="$FWPATH/test-firmware.bin" - -test_finish() -{ - echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout - rm -f "$FW" - rmdir "$FWPATH" -} +trap "test_finish" EXIT load_fw() { @@ -168,12 +155,6 @@ load_fw_fallback_with_child() return $RET } -trap "test_finish" EXIT - -# This is an unlikely real-world firmware content. :) -echo "ABCD0123" >"$FW" -NAME=$(basename "$FW") - test_syfs_timeout() { DEVPATH="$DIR"/"nope-$NAME"/loading diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh index 748f2f5737e9..7f47877fa7fa 100755 --- a/tools/testing/selftests/firmware/fw_filesystem.sh +++ b/tools/testing/selftests/firmware/fw_filesystem.sh @@ -6,38 +6,15 @@ # know so we can be sure we're not accidentally testing the user helper. set -e +TEST_REQS_FW_SYSFS_FALLBACK="no" +TEST_REQS_FW_SET_CUSTOM_PATH="yes" TEST_DIR=$(dirname $0) source $TEST_DIR/fw_lib.sh check_mods - -# CONFIG_FW_LOADER_USER_HELPER has a sysfs class under /sys/class/firmware/ -# These days most distros enable CONFIG_FW_LOADER_USER_HELPER but disable -# CONFIG_FW_LOADER_USER_HELPER_FALLBACK. We use /sys/class/firmware/ as an -# indicator for CONFIG_FW_LOADER_USER_HELPER. -HAS_FW_LOADER_USER_HELPER=$(if [ -d /sys/class/firmware/ ]; then echo yes; else echo no; fi) - -if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then - OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) -fi - -OLD_FWPATH=$(cat /sys/module/firmware_class/parameters/path) - -FWPATH=$(mktemp -d) -FW="$FWPATH/test-firmware.bin" - -test_finish() -{ - if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then - echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout - fi - if [ "$OLD_FWPATH" = "" ]; then - OLD_FWPATH=" " - fi - echo -n "$OLD_FWPATH" >/sys/module/firmware_class/parameters/path - rm -f "$FW" - rmdir "$FWPATH" -} +check_setup +verify_reqs +setup_tmp_file trap "test_finish" EXIT @@ -46,14 +23,6 @@ if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then echo 1 >/sys/class/firmware/timeout fi -# Set the kernel search path. -echo -n "$FWPATH" >/sys/module/firmware_class/parameters/path - -# This is an unlikely real-world firmware content. :) -echo "ABCD0123" >"$FW" - -NAME=$(basename "$FW") - if printf '\000' >"$DIR"/trigger_request 2> /dev/null; then echo "$0: empty filename should not succeed" >&2 exit 1 diff --git a/tools/testing/selftests/firmware/fw_lib.sh b/tools/testing/selftests/firmware/fw_lib.sh index 467567c758b9..e3cc4483fdba 100755 --- a/tools/testing/selftests/firmware/fw_lib.sh +++ b/tools/testing/selftests/firmware/fw_lib.sh @@ -43,6 +43,58 @@ check_mods() fi } +check_setup() +{ + HAS_FW_LOADER_USER_HELPER="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER=y)" + HAS_FW_LOADER_USER_HELPER_FALLBACK="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y)" + + if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then + OLD_TIMEOUT="$(cat /sys/class/firmware/timeout)" + fi + + OLD_FWPATH="$(cat /sys/module/firmware_class/parameters/path)" +} + +verify_reqs() +{ + if [ "$TEST_REQS_FW_SYSFS_FALLBACK" = "yes" ]; then + if [ ! "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then + echo "usermode helper disabled so ignoring test" + exit 0 + fi + fi +} + +setup_tmp_file() +{ + FWPATH=$(mktemp -d) + FW="$FWPATH/test-firmware.bin" + echo "ABCD0123" >"$FW" + NAME=$(basename "$FW") + if [ "$TEST_REQS_FW_SET_CUSTOM_PATH" = "yes" ]; then + echo -n "$FWPATH" >/sys/module/firmware_class/parameters/path + fi +} + +test_finish() +{ + if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then + echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout + fi + if [ "$OLD_FWPATH" = "" ]; then + OLD_FWPATH=" " + fi + if [ "$TEST_REQS_FW_SET_CUSTOM_PATH" = "yes" ]; then + echo -n "$OLD_FWPATH" >/sys/module/firmware_class/parameters/path + fi + if [ -f $FW ]; then + rm -f "$FW" + fi + if [ -d $FWPATH ]; then + rm -rf "$FWPATH" + fi +} + kconfig_has() { if [ -f $PROC_CONFIG ]; then -- cgit v1.3-14-g43fede From b3cf21fae1fe0b3a3e8ada0a60d3fb6217ebce5b Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 10 Mar 2018 06:14:54 -0800 Subject: test_firmware: test three firmware kernel configs using a proc knob Since we now have knobs to twiddle what used to be set on kernel configurations we can build one base kernel configuration and modify behaviour to mimic such kernel configurations to test them. Provided you build a kernel with: CONFIG_TEST_FIRMWARE=y CONFIG_FW_LOADER=y CONFIG_FW_LOADER_USER_HELPER=y CONFIG_IKCONFIG=y CONFIG_IKCONFIG_PROC=y We should now be able test all possible kernel configurations when FW_LOADER=y. Note that when FW_LOADER=m we just don't provide the built-in functionality of the built-in firmware. If you're on an old kernel and either don't have /proc/config.gz (CONFIG_IKCONFIG_PROC) or haven't enabled CONFIG_FW_LOADER_USER_HELPER we cannot run these dynamic tests, so just run both scripts just as we used to before making blunt assumptions about your setup and requirements exactly as we did before. Acked-by: Kees Cook Signed-off-by: Luis R. Rodriguez Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/firmware/Makefile | 2 +- tools/testing/selftests/firmware/fw_lib.sh | 51 +++++++++++++++++ tools/testing/selftests/firmware/fw_run_tests.sh | 70 ++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100755 tools/testing/selftests/firmware/fw_run_tests.sh (limited to 'tools/testing') diff --git a/tools/testing/selftests/firmware/Makefile b/tools/testing/selftests/firmware/Makefile index 1894d625af2d..826f38d5dd19 100644 --- a/tools/testing/selftests/firmware/Makefile +++ b/tools/testing/selftests/firmware/Makefile @@ -3,7 +3,7 @@ # No binaries, but make sure arg-less "make" doesn't trigger "run_tests" all: -TEST_PROGS := fw_filesystem.sh fw_fallback.sh +TEST_PROGS := fw_run_tests.sh include ../lib.mk diff --git a/tools/testing/selftests/firmware/fw_lib.sh b/tools/testing/selftests/firmware/fw_lib.sh index e3cc4483fdba..98dceb847ba0 100755 --- a/tools/testing/selftests/firmware/fw_lib.sh +++ b/tools/testing/selftests/firmware/fw_lib.sh @@ -47,6 +47,34 @@ check_setup() { HAS_FW_LOADER_USER_HELPER="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER=y)" HAS_FW_LOADER_USER_HELPER_FALLBACK="$(kconfig_has CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y)" + PROC_FW_IGNORE_SYSFS_FALLBACK="0" + PROC_FW_FORCE_SYSFS_FALLBACK="0" + + if [ -z $PROC_SYS_DIR ]; then + PROC_SYS_DIR="/proc/sys/kernel" + fi + + FW_PROC="${PROC_SYS_DIR}/firmware_config" + FW_FORCE_SYSFS_FALLBACK="$FW_PROC/force_sysfs_fallback" + FW_IGNORE_SYSFS_FALLBACK="$FW_PROC/ignore_sysfs_fallback" + + if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then + PROC_FW_FORCE_SYSFS_FALLBACK="$(cat $FW_FORCE_SYSFS_FALLBACK)" + fi + + if [ -f $FW_IGNORE_SYSFS_FALLBACK ]; then + PROC_FW_IGNORE_SYSFS_FALLBACK="$(cat $FW_IGNORE_SYSFS_FALLBACK)" + fi + + if [ "$PROC_FW_FORCE_SYSFS_FALLBACK" = "1" ]; then + HAS_FW_LOADER_USER_HELPER="yes" + HAS_FW_LOADER_USER_HELPER_FALLBACK="yes" + fi + + if [ "$PROC_FW_IGNORE_SYSFS_FALLBACK" = "1" ]; then + HAS_FW_LOADER_USER_HELPER_FALLBACK="no" + HAS_FW_LOADER_USER_HELPER="no" + fi if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then OLD_TIMEOUT="$(cat /sys/class/firmware/timeout)" @@ -76,6 +104,28 @@ setup_tmp_file() fi } +proc_set_force_sysfs_fallback() +{ + if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then + echo -n $1 > $FW_FORCE_SYSFS_FALLBACK + check_setup + fi +} + +proc_set_ignore_sysfs_fallback() +{ + if [ -f $FW_IGNORE_SYSFS_FALLBACK ]; then + echo -n $1 > $FW_IGNORE_SYSFS_FALLBACK + check_setup + fi +} + +proc_restore_defaults() +{ + proc_set_force_sysfs_fallback 0 + proc_set_ignore_sysfs_fallback 0 +} + test_finish() { if [ "$HAS_FW_LOADER_USER_HELPER" = "yes" ]; then @@ -93,6 +143,7 @@ test_finish() if [ -d $FWPATH ]; then rm -rf "$FWPATH" fi + proc_restore_defaults } kconfig_has() diff --git a/tools/testing/selftests/firmware/fw_run_tests.sh b/tools/testing/selftests/firmware/fw_run_tests.sh new file mode 100755 index 000000000000..06d638e9dc62 --- /dev/null +++ b/tools/testing/selftests/firmware/fw_run_tests.sh @@ -0,0 +1,70 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +# This runs all known tests across all known possible configurations we could +# emulate in one run. + +set -e + +TEST_DIR=$(dirname $0) +source $TEST_DIR/fw_lib.sh + +export HAS_FW_LOADER_USER_HELPER="" +export HAS_FW_LOADER_USER_HELPER_FALLBACK="" + +run_tests() +{ + proc_set_force_sysfs_fallback $1 + proc_set_ignore_sysfs_fallback $2 + $TEST_DIR/fw_filesystem.sh + + proc_set_force_sysfs_fallback $1 + proc_set_ignore_sysfs_fallback $2 + $TEST_DIR/fw_fallback.sh +} + +run_test_config_0001() +{ + echo "-----------------------------------------------------" + echo "Running kernel configuration test 1 -- rare" + echo "Emulates:" + echo "CONFIG_FW_LOADER=y" + echo "CONFIG_FW_LOADER_USER_HELPER=n" + echo "CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n" + run_tests 0 1 +} + +run_test_config_0002() +{ + echo "-----------------------------------------------------" + echo "Running kernel configuration test 2 -- distro" + echo "Emulates:" + echo "CONFIG_FW_LOADER=y" + echo "CONFIG_FW_LOADER_USER_HELPER=y" + echo "CONFIG_FW_LOADER_USER_HELPER_FALLBACK=n" + proc_set_ignore_sysfs_fallback 0 + run_tests 0 0 +} + +run_test_config_0003() +{ + echo "-----------------------------------------------------" + echo "Running kernel configuration test 3 -- android" + echo "Emulates:" + echo "CONFIG_FW_LOADER=y" + echo "CONFIG_FW_LOADER_USER_HELPER=y" + echo "CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y" + run_tests 1 0 +} + +check_mods +check_setup + +if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then + run_test_config_0001 + run_test_config_0002 + run_test_config_0003 +else + echo "Running basic kernel configuration, working with your config" + run_test +fi -- cgit v1.3-14-g43fede From 9952db75e0659d9db62d76d9a351fdae06898642 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Sat, 10 Mar 2018 06:14:58 -0800 Subject: test_firmware: modify custom fallback tests to use unique files Users of the custom firmware fallback interface is are not supposed to use the firmware cache interface, this can happen if for instance the one of the APIs which use the firmware cache is used first with one firmware file and then the request_firmware_nowait(uevent=false) API is used with the same file. We'll soon become strict about this on the firmware interface to reject such calls later, so correct the test scripts to avoid such uses as well. We address this on the tests scripts by simply using unique names when testing the custom fallback interface. Signed-off-by: Luis R. Rodriguez Signed-off-by: Greg Kroah-Hartman --- tools/testing/selftests/firmware/fw_fallback.sh | 20 ++++++++++++++------ tools/testing/selftests/firmware/fw_filesystem.sh | 11 +++++++++-- tools/testing/selftests/firmware/fw_lib.sh | 23 +++++++++++++++++++++++ 3 files changed, 46 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/firmware/fw_fallback.sh b/tools/testing/selftests/firmware/fw_fallback.sh index 9337a0328627..8e2e34a2ca69 100755 --- a/tools/testing/selftests/firmware/fw_fallback.sh +++ b/tools/testing/selftests/firmware/fw_fallback.sh @@ -238,8 +238,10 @@ run_sysfs_main_tests() run_sysfs_custom_load_tests() { - if load_fw_custom "$NAME" "$FW" ; then - if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then + RANDOM_FILE_PATH=$(setup_random_file) + RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" + if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then + if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then echo "$0: firmware was not loaded" >&2 exit 1 else @@ -247,8 +249,10 @@ run_sysfs_custom_load_tests() fi fi - if load_fw_custom "$NAME" "$FW" ; then - if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then + RANDOM_FILE_PATH=$(setup_random_file) + RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" + if load_fw_custom "$RANDOM_FILE" "$RANDOM_FILE_PATH" ; then + if ! diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then echo "$0: firmware was not loaded" >&2 exit 1 else @@ -256,8 +260,12 @@ run_sysfs_custom_load_tests() fi fi - if load_fw_custom_cancel "nope-$NAME" "$FW" ; then - if diff -q "$FW" /dev/test_firmware >/dev/null ; then + RANDOM_FILE_REAL="$RANDOM_FILE_PATH" + FAKE_RANDOM_FILE_PATH=$(setup_random_file_fake) + FAKE_RANDOM_FILE="$(basename $FAKE_RANDOM_FILE_PATH)" + + if load_fw_custom_cancel "$FAKE_RANDOM_FILE" "$RANDOM_FILE_REAL" ; then + if diff -q "$RANDOM_FILE_PATH" /dev/test_firmware >/dev/null ; then echo "$0: firmware was expected to be cancelled" >&2 exit 1 else diff --git a/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh index 7f47877fa7fa..6452d2129cd9 100755 --- a/tools/testing/selftests/firmware/fw_filesystem.sh +++ b/tools/testing/selftests/firmware/fw_filesystem.sh @@ -230,10 +230,13 @@ test_wait_and_cancel_custom_load() test_request_firmware_nowait_custom_nofile() { echo -n "Batched request_firmware_nowait(uevent=false) nofile try #$1: " + config_reset config_unset_uevent - config_set_name nope-test-firmware.bin + RANDOM_FILE_PATH=$(setup_random_file_fake) + RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" + config_set_name $RANDOM_FILE config_trigger_async & - test_wait_and_cancel_custom_load nope-test-firmware.bin + test_wait_and_cancel_custom_load $RANDOM_FILE wait release_all_firmware echo "OK" @@ -271,7 +274,11 @@ test_request_firmware_nowait_uevent() test_request_firmware_nowait_custom() { echo -n "Batched request_firmware_nowait(uevent=false) try #$1: " + config_reset config_unset_uevent + RANDOM_FILE_PATH=$(setup_random_file) + RANDOM_FILE="$(basename $RANDOM_FILE_PATH)" + config_set_name $RANDOM_FILE config_trigger_async release_all_firmware echo "OK" diff --git a/tools/testing/selftests/firmware/fw_lib.sh b/tools/testing/selftests/firmware/fw_lib.sh index 98dceb847ba0..9ea31b57d71a 100755 --- a/tools/testing/selftests/firmware/fw_lib.sh +++ b/tools/testing/selftests/firmware/fw_lib.sh @@ -104,6 +104,29 @@ setup_tmp_file() fi } +__setup_random_file() +{ + RANDOM_FILE_PATH="$(mktemp -p $FWPATH)" + # mktemp says dry-run -n is unsafe, so... + if [[ "$1" = "fake" ]]; then + rm -rf $RANDOM_FILE_PATH + sync + else + echo "ABCD0123" >"$RANDOM_FILE_PATH" + fi + echo $RANDOM_FILE_PATH +} + +setup_random_file() +{ + echo $(__setup_random_file) +} + +setup_random_file_fake() +{ + echo $(__setup_random_file fake) +} + proc_set_force_sysfs_fallback() { if [ -f $FW_FORCE_SYSFS_FALLBACK ]; then -- cgit v1.3-14-g43fede From 9f23b129eb35c1465aa1733884acad3d95c8fde7 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 21 Mar 2018 10:24:20 -0400 Subject: ktest: Wait for console process to exit To clean up the console processes that are forked to monitor the console, there needs to be a waitpid(). Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 0c8b61f8398e..4eece2a9772c 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1515,6 +1515,9 @@ sub close_console { doprint "kill child process $pid\n"; kill $close_console_signal, $pid; + doprint "wait for child process $pid to exit\n"; + waitpid($pid, 0); + print "closing!\n"; close($fp); -- cgit v1.3-14-g43fede From 3e1d3678844b2b1f4c41818bc9a2885cbf5ccef6 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 21 Mar 2018 10:36:08 -0400 Subject: ktest: Add CONNECT_TIMEOUT to change the connection timeout time Before ktest issues a reboot, it will try to connect to the target machine to make sure that it is still alive. If the target does not respond within 5 seconds, it will power cycle the box instead of issuing a reboot. Five seconds may be too short, and ktest may unnecessarially power cycle the box. I have found 25 seconds seems to be a better timeout for this purpose. But even 25 may be too arbitrary. Add a CONNECT_TIMEOUT option to let the user determine the timeout time before rebooting. By default, it has been raised to 25 seconds. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 7 +++++-- tools/testing/ktest/sample.conf | 7 +++++++ 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 4eece2a9772c..a959b6f79ce5 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -59,6 +59,7 @@ my %default = ( "GRUB_REBOOT" => "grub2-reboot", "SYSLINUX" => "extlinux", "SYSLINUX_PATH" => "/boot/extlinux", + "CONNECT_TIMEOUT" => 25, # required, and we will ask users if they don't have them but we keep the default # value something that is common. @@ -163,6 +164,7 @@ my $store_failures; my $store_successes; my $test_name; my $timeout; +my $connect_timeout; my $booted_timeout; my $detect_triplefault; my $console; @@ -296,6 +298,7 @@ my %option_map = ( "STORE_SUCCESSES" => \$store_successes, "TEST_NAME" => \$test_name, "TIMEOUT" => \$timeout, + "CONNECT_TIMEOUT" => \$connect_timeout, "BOOTED_TIMEOUT" => \$booted_timeout, "CONSOLE" => \$console, "CLOSE_CONSOLE_SIGNAL" => \$close_console_signal, @@ -1328,8 +1331,8 @@ sub reboot { my ($time) = @_; my $powercycle = 0; - # test if the machine can be connected to within 5 seconds - my $stat = run_ssh("echo check machine status", 5); + # test if the machine can be connected to within a few seconds + my $stat = run_ssh("echo check machine status", $connect_timeout); if (!$stat) { doprint("power cycle\n"); $powercycle = 1; diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 6c58cd8bbbae..8df62c837dd1 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -725,6 +725,13 @@ # (default 120) #TIMEOUT = 120 +# The timeout in seconds when to test if the box can be rebooted +# or not. Before issuing the reboot command, a ssh connection +# is attempted to see if the target machine is still active. +# If the target does not connect within this timeout, a power cycle +# is issued instead of a reboot. +# CONNECT_TIMEOUT = 25 + # In between tests, a reboot of the box may occur, and this # is the time to wait for the console after it stops producing # output. Some machines may not produce a large lag on reboot -- cgit v1.3-14-g43fede From edbd0ede0078bde5eb539e175cd7e0e89cd82df0 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Sun, 16 Jul 2017 19:16:23 -0500 Subject: ktest: Clarify config file usage Simply telling a new user to edit "the config file" without giving any hints on where that file should go, what it should be named, or where a template can be found, is not particularly helpful. Link: http://lkml.kernel.org/r/20170717001630.10518-1-swood@redhat.com Signed-off-by: Scott Wood Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 3 ++- tools/testing/ktest/sample.conf | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index a959b6f79ce5..c85a9f9342f4 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1143,7 +1143,8 @@ sub __read_config { sub get_test_case { print "What test case would you like to run?\n"; print " (build, install or boot)\n"; - print " Other tests are available but require editing the config file\n"; + print " Other tests are available but require editing ktest.conf\n"; + print " (see tools/testing/ktest/sample.conf)\n"; my $ans = ; chomp $ans; $default{"TEST_TYPE"} = $ans; diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 8df62c837dd1..e628e7c8d875 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -1,6 +1,9 @@ # # Config file for ktest.pl # +# Place your customized version of this, named ktest.conf, in the +# working directory that ktest.pl is run from. +# # Note, all paths must be absolute # -- cgit v1.3-14-g43fede From 6dd3791dcf3051f47898a59553aaf21cd2cf8d1d Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 21 Mar 2018 12:08:02 -0400 Subject: ktest: Comment about other names than just ktest.conf ktest.pl will read any file as long as its name is specified as the first argument on the command line. Comment this fact in sample.conf. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/sample.conf | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index e628e7c8d875..695983a72465 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -1,8 +1,10 @@ # # Config file for ktest.pl # -# Place your customized version of this, named ktest.conf, in the -# working directory that ktest.pl is run from. +# Place your customized version of this, in the working directory that +# ktest.pl is run from. By default, ktest.pl will look for a file +# called "ktest.conf", but you can name it anything you like and specify +# the name of your config file as the first argument of ktest.pl. # # Note, all paths must be absolute # -- cgit v1.3-14-g43fede From 25bc70fa0968dacb40eec37d4340163df48b06cf Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Sun, 16 Jul 2017 19:16:24 -0500 Subject: ktest: Set buildonly=1 for CONFIG_BISECT_TYPE=build Rather than adding a third copy of the same logic, rework it to cover all three buildonly cases at once. In the future, please consider using the same variable to perform the same function regardless of context... Link: http://lkml.kernel.org/r/20170717001630.10518-2-swood@redhat.com Signed-off-by: Scott Wood Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index c85a9f9342f4..80091dfbce4b 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -721,21 +721,13 @@ sub set_value { my $prvalue = process_variables($rvalue); - if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") { + if ($lvalue =~ /^(TEST|BISECT|CONFIG_BISECT)_TYPE(\[.*\])?$/ && + $prvalue !~ /^(config_|)bisect$/ && + $prvalue !~ /^build$/ && + $buildonly) { + # Note if a test is something other than build, then we # will need other mandatory options. - if ($prvalue ne "install") { - # for bisect, we need to check BISECT_TYPE - if ($prvalue ne "bisect") { - $buildonly = 0; - } - } else { - # install still limits some mandatory options. - $buildonly = 2; - } - } - - if ($buildonly && $lvalue =~ /^BISECT_TYPE(\[.*\])?$/ && $prvalue ne "build") { if ($prvalue ne "install") { $buildonly = 0; } else { -- cgit v1.3-14-g43fede From 649c0f12defbefc303d0cb7157b090c9cfd92944 Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Sun, 16 Jul 2017 19:16:25 -0500 Subject: ktest: Set do_not_reboot=y for CONFIG_BISECT_TYPE=build Currently setting do_not_reboot is triggered by simple builds and bisect builds, but not config bisect builds. Link: http://lkml.kernel.org/r/20170717001630.10518-3-swood@redhat.com Signed-off-by: Scott Wood Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 80091dfbce4b..f597f9b4e8d5 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1400,7 +1400,8 @@ sub do_not_reboot { return $test_type eq "build" || $no_reboot || ($test_type eq "patchcheck" && $opt{"PATCHCHECK_TYPE[$i]"} eq "build") || - ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build"); + ($test_type eq "bisect" && $opt{"BISECT_TYPE[$i]"} eq "build") || + ($test_type eq "config_bisect" && $opt{"CONFIG_BISECT_TYPE[$i]"} eq "build"); } sub dodie { -- cgit v1.3-14-g43fede From 55c1b5f4af398f5776add417ddf8ae9cc574f0b7 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Thu, 8 Mar 2018 15:37:41 +0100 Subject: selftests/android/ion: Makefile: fix build error Fails to build iomap_test.c due to missing include gcc -I. -I../../../../../drivers/staging/android/uapi/ -Wall -O2 -g ionmap_test.c ipcsocket.c ionutils.c -o ionmap_test ionmap_test.c:12:27: fatal error: linux/dma-buf.h: No such file or directory #include ^ compilation terminated. : recipe for target 'ionmap_test' failed make[2]: *** [ionmap_test] Error 1 In the current code, we add a new -I ../../../../../usr/include/ to the INCLUDEDIR variable. Also add ionmap_test to the .gitignore file. Fixes: ac93f7046a53 ("selftests: ion: Add simple test with the vgem driver") Signed-off-by: Anders Roxell Acked-by: Laura Abbott Signed-off-by: Shuah Khan --- tools/testing/selftests/android/ion/.gitignore | 1 + tools/testing/selftests/android/ion/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/android/ion/.gitignore b/tools/testing/selftests/android/ion/.gitignore index 67e6f391b2a9..95e8f4561474 100644 --- a/tools/testing/selftests/android/ion/.gitignore +++ b/tools/testing/selftests/android/ion/.gitignore @@ -1,2 +1,3 @@ ionapp_export ionapp_import +ionmap_test diff --git a/tools/testing/selftests/android/ion/Makefile b/tools/testing/selftests/android/ion/Makefile index d23b6d537d8b..e03695287f76 100644 --- a/tools/testing/selftests/android/ion/Makefile +++ b/tools/testing/selftests/android/ion/Makefile @@ -1,5 +1,5 @@ -INCLUDEDIR := -I. -I../../../../../drivers/staging/android/uapi/ +INCLUDEDIR := -I. -I../../../../../drivers/staging/android/uapi/ -I../../../../../usr/include/ CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g TEST_GEN_FILES := ionapp_export ionapp_import ionmap_test -- cgit v1.3-14-g43fede From 6c3b6d50839151c5d8a077610b5d8c3dc1e7e7b3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 15 Mar 2018 09:59:16 -0700 Subject: selftests/seccomp: Allow get_metadata to XFAIL Since seccomp_get_metadata() depends on CHECKPOINT_RESTORE, XFAIL the test if the ptrace reports it as missing. Signed-off-by: Kees Cook Acked-by: Tycho Andersen Signed-off-by: Shuah Khan --- tools/testing/selftests/kselftest_harness.h | 26 +++++++++++++++++++++++++- tools/testing/selftests/seccomp/seccomp_bpf.c | 15 +++++++++++++-- 2 files changed, 38 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/kselftest_harness.h b/tools/testing/selftests/kselftest_harness.h index e81bd28bdd89..6ae3730c4ee3 100644 --- a/tools/testing/selftests/kselftest_harness.h +++ b/tools/testing/selftests/kselftest_harness.h @@ -106,6 +106,27 @@ fprintf(TH_LOG_STREAM, "%s:%d:%s:" fmt "\n", \ __FILE__, __LINE__, _metadata->name, ##__VA_ARGS__) +/** + * XFAIL(statement, fmt, ...) + * + * @statement: statement to run after reporting XFAIL + * @fmt: format string + * @...: optional arguments + * + * This forces a "pass" after reporting a failure with an XFAIL prefix, + * and runs "statement", which is usually "return" or "goto skip". + */ +#define XFAIL(statement, fmt, ...) do { \ + if (TH_LOG_ENABLED) { \ + fprintf(TH_LOG_STREAM, "[ XFAIL! ] " fmt "\n", \ + ##__VA_ARGS__); \ + } \ + /* TODO: find a way to pass xfail to test runner process. */ \ + _metadata->passed = 1; \ + _metadata->trigger = 0; \ + statement; \ +} while (0) + /** * TEST(test_name) - Defines the test function and creates the registration * stub @@ -198,7 +219,7 @@ /** * FIXTURE_SETUP(fixture_name) - Prepares the setup function for the fixture. - * *_metadata* is included so that ASSERT_* work as a convenience + * *_metadata* is included so that EXPECT_* and ASSERT_* work correctly. * * @fixture_name: fixture name * @@ -221,6 +242,7 @@ FIXTURE_DATA(fixture_name) __attribute__((unused)) *self) /** * FIXTURE_TEARDOWN(fixture_name) + * *_metadata* is included so that EXPECT_* and ASSERT_* work correctly. * * @fixture_name: fixture name * @@ -253,6 +275,8 @@ * Defines a test that depends on a fixture (e.g., is part of a test case). * Very similar to TEST() except that *self* is the setup instance of fixture's * datatype exposed for use by the implementation. + * + * Warning: use of ASSERT_* here will skip TEARDOWN. */ /* TODO(wad) register fixtures on dedicated test lists. */ #define TEST_F(fixture_name, test_name) \ diff --git a/tools/testing/selftests/seccomp/seccomp_bpf.c b/tools/testing/selftests/seccomp/seccomp_bpf.c index 5df609950a66..168c66d74fc5 100644 --- a/tools/testing/selftests/seccomp/seccomp_bpf.c +++ b/tools/testing/selftests/seccomp/seccomp_bpf.c @@ -2860,6 +2860,7 @@ TEST(get_metadata) int pipefd[2]; char buf; struct seccomp_metadata md; + long ret; ASSERT_EQ(0, pipe(pipefd)); @@ -2893,16 +2894,26 @@ TEST(get_metadata) ASSERT_EQ(0, ptrace(PTRACE_ATTACH, pid)); ASSERT_EQ(pid, waitpid(pid, NULL, 0)); + /* Past here must not use ASSERT or child process is never killed. */ + md.filter_off = 0; - ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md)); + errno = 0; + ret = ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md); + EXPECT_EQ(sizeof(md), ret) { + if (errno == EINVAL) + XFAIL(goto skip, "Kernel does not support PTRACE_SECCOMP_GET_METADATA (missing CONFIG_CHECKPOINT_RESTORE?)"); + } + EXPECT_EQ(md.flags, SECCOMP_FILTER_FLAG_LOG); EXPECT_EQ(md.filter_off, 0); md.filter_off = 1; - ASSERT_EQ(sizeof(md), ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md)); + ret = ptrace(PTRACE_SECCOMP_GET_METADATA, pid, sizeof(md), &md); + EXPECT_EQ(sizeof(md), ret); EXPECT_EQ(md.flags, 0); EXPECT_EQ(md.filter_off, 1); +skip: ASSERT_EQ(0, kill(pid, SIGKILL)); } -- cgit v1.3-14-g43fede From 8ae797aaa845317bddfbf14f4b37514b017045a6 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 20 Mar 2018 10:04:30 -0700 Subject: selftests: Add multipath tests for onlink flag Add multipath tests for onlink flag: one test with onlink added to both nexthops, then tests with onlink added to only 1 nexthop. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib-onlink-tests.sh | 98 ++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/net/fib-onlink-tests.sh b/tools/testing/selftests/net/fib-onlink-tests.sh index 06b1d7cc12cc..3991ad1a368d 100755 --- a/tools/testing/selftests/net/fib-onlink-tests.sh +++ b/tools/testing/selftests/net/fib-onlink-tests.sh @@ -56,7 +56,8 @@ TEST_NET6[2]=2001:db8:102 # connected gateway CONGW[1]=169.254.1.254 -CONGW[2]=169.254.5.254 +CONGW[2]=169.254.3.254 +CONGW[3]=169.254.5.254 # recursive gateway RECGW4[1]=169.254.11.254 @@ -232,6 +233,23 @@ run_ip() log_test $? ${exp_rc} "${desc}" } +run_ip_mpath() +{ + local table="$1" + local prefix="$2" + local nh1="$3" + local nh2="$4" + local exp_rc="$5" + local desc="$6" + + # dev arg may be empty + [ -n "${dev}" ] && dev="dev ${dev}" + + run_cmd ip ro add table "${table}" "${prefix}"/32 \ + nexthop via ${nh1} nexthop via ${nh2} + log_test $? ${exp_rc} "${desc}" +} + valid_onlink_ipv4() { # - unicast connected, unicast recursive @@ -243,13 +261,37 @@ valid_onlink_ipv4() log_subsection "VRF ${VRF}" - run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[2]} ${NETIFS[p5]} 0 "unicast connected" + run_ip ${VRF_TABLE} ${TEST_NET4[2]}.1 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected" run_ip ${VRF_TABLE} ${TEST_NET4[2]}.2 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" log_subsection "VRF device, PBR table" - run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[2]} ${NETIFS[p5]} 0 "unicast connected" + run_ip ${PBR_TABLE} ${TEST_NET4[2]}.3 ${CONGW[3]} ${NETIFS[p5]} 0 "unicast connected" run_ip ${PBR_TABLE} ${TEST_NET4[2]}.4 ${RECGW4[2]} ${NETIFS[p5]} 0 "unicast recursive" + + # multipath version + # + log_subsection "default VRF - main table - multipath" + + run_ip_mpath 254 ${TEST_NET4[1]}.5 \ + "${CONGW[1]} dev ${NETIFS[p1]} onlink" \ + "${CONGW[2]} dev ${NETIFS[p3]} onlink" \ + 0 "unicast connected - multipath" + + run_ip_mpath 254 ${TEST_NET4[1]}.6 \ + "${RECGW4[1]} dev ${NETIFS[p1]} onlink" \ + "${RECGW4[2]} dev ${NETIFS[p3]} onlink" \ + 0 "unicast recursive - multipath" + + run_ip_mpath 254 ${TEST_NET4[1]}.7 \ + "${CONGW[1]} dev ${NETIFS[p1]}" \ + "${CONGW[2]} dev ${NETIFS[p3]} onlink" \ + 0 "unicast connected - multipath onlink first only" + + run_ip_mpath 254 ${TEST_NET4[1]}.8 \ + "${CONGW[1]} dev ${NETIFS[p1]} onlink" \ + "${CONGW[2]} dev ${NETIFS[p3]}" \ + 0 "unicast connected - multipath onlink second only" } invalid_onlink_ipv4() @@ -289,6 +331,21 @@ run_ip6() log_test $? ${exp_rc} "${desc}" } +run_ip6_mpath() +{ + local table="$1" + local prefix="$2" + local opts="$3" + local nh1="$4" + local nh2="$5" + local exp_rc="$6" + local desc="$7" + + run_cmd ip -6 ro add table "${table}" "${prefix}"/128 "${opts}" \ + nexthop via ${nh1} nexthop via ${nh2} + log_test $? ${exp_rc} "${desc}" +} + valid_onlink_ipv6() { # - unicast connected, unicast recursive, v4-mapped @@ -310,6 +367,40 @@ valid_onlink_ipv6() run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::4 ${V6ADDRS[p5]/::*}::64 ${NETIFS[p5]} 0 "unicast connected" run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::5 ${RECGW6[2]} ${NETIFS[p5]} 0 "unicast recursive" run_ip6 ${PBR_TABLE} ${TEST_NET6[2]}::6 ::ffff:${TEST_NET4IN6[2]} ${NETIFS[p5]} 0 "v4-mapped" + + # multipath version + # + log_subsection "default VRF - main table - multipath" + + run_ip6_mpath 254 ${TEST_NET6[1]}::4 "onlink" \ + "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \ + "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \ + 0 "unicast connected - multipath onlink" + + run_ip6_mpath 254 ${TEST_NET6[1]}::5 "onlink" \ + "${RECGW6[1]} dev ${NETIFS[p1]}" \ + "${RECGW6[2]} dev ${NETIFS[p3]}" \ + 0 "unicast recursive - multipath onlink" + + run_ip6_mpath 254 ${TEST_NET6[1]}::6 "onlink" \ + "::ffff:${TEST_NET4IN6[1]} dev ${NETIFS[p1]}" \ + "::ffff:${TEST_NET4IN6[2]} dev ${NETIFS[p3]}" \ + 0 "v4-mapped - multipath onlink" + + run_ip6_mpath 254 ${TEST_NET6[1]}::7 "" \ + "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \ + "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \ + 0 "unicast connected - multipath onlink both nexthops" + + run_ip6_mpath 254 ${TEST_NET6[1]}::8 "" \ + "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]} onlink" \ + "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]}" \ + 0 "unicast connected - multipath onlink first only" + + run_ip6_mpath 254 ${TEST_NET6[1]}::9 "" \ + "${V6ADDRS[p1]/::*}::64 dev ${NETIFS[p1]}" \ + "${V6ADDRS[p3]/::*}::64 dev ${NETIFS[p3]} onlink" \ + 0 "unicast connected - multipath onlink second only" } invalid_onlink_ipv6() @@ -355,6 +446,7 @@ run_onlink_tests() log_section "IPv6 onlink" log_subsection "Valid onlink commands" valid_onlink_ipv6 + log_subsection "Invalid onlink commands" invalid_onlink_ipv6 } -- cgit v1.3-14-g43fede From 871bef2000968c312a4000b2f56d370dcedbc93c Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 17 Mar 2018 21:38:56 +0900 Subject: selftests: ftrace: Add probe event argument syntax testcase Add a testcase for probe event argument syntax which ensures the kprobe_events interface correctly parses given event arguments. Link: http://lkml.kernel.org/r/152129033679.31874.12705519603869152799.stgit@devbox Signed-off-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) --- .../ftrace/test.d/kprobe/kprobe_args_syntax.tc | 97 ++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc (limited to 'tools/testing') diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc new file mode 100644 index 000000000000..231bcd2c4eb5 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc @@ -0,0 +1,97 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe event argument syntax + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +grep "x8/16/32/64" README > /dev/null || exit_unsupported # version issue + +echo 0 > events/enable +echo > kprobe_events + +PROBEFUNC="vfs_read" +GOODREG= +BADREG= +GOODSYM="_sdata" +if ! grep -qw ${GOODSYM} /proc/kallsyms ; then + GOODSYM=$PROBEFUNC +fi +BADSYM="deaqswdefr" +SYMADDR=0x`grep -w ${GOODSYM} /proc/kallsyms | cut -f 1 -d " "` +GOODTYPE="x16" +BADTYPE="y16" + +case `uname -m` in +x86_64|i[3456]86) + GOODREG=%ax + BADREG=%ex +;; +aarch64) + GOODREG=%x0 + BADREG=%ax +;; +arm*) + GOODREG=%r0 + BADREG=%ax +;; +esac + +test_goodarg() # Good-args +{ + while [ "$1" ]; do + echo "p ${PROBEFUNC} $1" > kprobe_events + shift 1 + done; +} + +test_badarg() # Bad-args +{ + while [ "$1" ]; do + ! echo "p ${PROBEFUNC} $1" > kprobe_events + shift 1 + done; +} + +echo > kprobe_events + +: "Register access" +test_goodarg ${GOODREG} +test_badarg ${BADREG} + +: "Symbol access" +test_goodarg "@${GOODSYM}" "@${SYMADDR}" "@${GOODSYM}+10" "@${GOODSYM}-10" +test_badarg "@" "@${BADSYM}" "@${GOODSYM}*10" "@${GOODSYM}/10" \ + "@${GOODSYM}%10" "@${GOODSYM}&10" "@${GOODSYM}|10" + +: "Stack access" +test_goodarg "\$stack" "\$stack0" "\$stack1" +test_badarg "\$stackp" "\$stack0+10" "\$stack1-10" + +: "Retval access" +echo "r ${PROBEFUNC} \$retval" > kprobe_events +! echo "p ${PROBEFUNC} \$retval" > kprobe_events + +: "Comm access" +test_goodarg "\$comm" + +: "Indirect memory access" +test_goodarg "+0(${GOODREG})" "-0(${GOODREG})" "+10(\$stack)" \ + "+0(\$stack1)" "+10(@${GOODSYM}-10)" "+0(+10(+20(\$stack)))" +test_badarg "+(${GOODREG})" "(${GOODREG}+10)" "-(${GOODREG})" "(${GOODREG})" \ + "+10(\$comm)" "+0(${GOODREG})+10" + +: "Name assignment" +test_goodarg "varname=${GOODREG}" +test_badarg "varname=varname2=${GOODREG}" + +: "Type syntax" +test_goodarg "${GOODREG}:${GOODTYPE}" +test_badarg "${GOODREG}::${GOODTYPE}" "${GOODREG}:${BADTYPE}" \ + "${GOODTYPE}:${GOODREG}" + +: "Combination check" + +test_goodarg "\$comm:string" "+0(\$stack):string" +test_badarg "\$comm:x64" "\$stack:string" "${GOODREG}:string" + +echo > kprobe_events -- cgit v1.3-14-g43fede From 5fbdbed797b6d12d043a5121fdbc8d8b49d10e80 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 17 Mar 2018 21:39:44 +0900 Subject: selftests: ftrace: Add a testcase for string type with kprobe_event Add a testcase for string type with kprobe event. This tests good/bad syntax combinations and also the traced data is correct in several way. Link: http://lkml.kernel.org/r/152129038381.31874.9201387794548737554.stgit@devbox Signed-off-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) --- .../ftrace/test.d/kprobe/kprobe_args_string.tc | 46 ++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc (limited to 'tools/testing') diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc new file mode 100644 index 000000000000..5ba73035e1d9 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc @@ -0,0 +1,46 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe event string type argument + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +echo 0 > events/enable +echo > kprobe_events + +case `uname -m` in +x86_64) + ARG2=%si + OFFS=8 +;; +i[3456]86) + ARG2=%cx + OFFS=4 +;; +aarch64) + ARG2=%x1 + OFFS=8 +;; +arm*) + ARG2=%r1 + OFFS=4 +;; +*) + echo "Please implement other architecture here" + exit_untested +esac + +: "Test get argument (1)" +echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string" > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo test >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1=\"test\"" + +echo 0 > events/kprobes/testprobe/enable +: "Test get argument (2)" +echo "p:testprobe create_trace_kprobe arg1=+0(+0(${ARG2})):string arg2=+0(+${OFFS}(${ARG2})):string" > kprobe_events +echo 1 > events/kprobes/testprobe/enable +! echo test1 test2 >> kprobe_events +tail -n 1 trace | grep -qe "testprobe.* arg1=\"test1\" arg2=\"test2\"" + +echo 0 > events/enable +echo > kprobe_events -- cgit v1.3-14-g43fede From dfa453bc90eca0febff33c8d292a656e53702158 Mon Sep 17 00:00:00 2001 From: Masami Hiramatsu Date: Sat, 17 Mar 2018 21:40:31 +0900 Subject: selftests: ftrace: Add a testcase for probepoint Add a testcase for probe point definition. This tests symbol, address and symbol+offset syntax. The offset must be positive and smaller than UINT_MAX. Link: http://lkml.kernel.org/r/152129043097.31874.14273580606301767394.stgit@devbox Signed-off-by: Masami Hiramatsu Signed-off-by: Steven Rostedt (VMware) --- .../selftests/ftrace/test.d/kprobe/probepoint.tc | 43 ++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc (limited to 'tools/testing') diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc new file mode 100644 index 000000000000..4fda01a08da4 --- /dev/null +++ b/tools/testing/selftests/ftrace/test.d/kprobe/probepoint.tc @@ -0,0 +1,43 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 +# description: Kprobe events - probe points + +[ -f kprobe_events ] || exit_unsupported # this is configurable + +TARGET_FUNC=create_trace_kprobe + +dec_addr() { # hexaddr + printf "%d" "0x"`echo $1 | tail -c 8` +} + +set_offs() { # prev target next + A1=`dec_addr $1` + A2=`dec_addr $2` + A3=`dec_addr $3` + TARGET="0x$2" # an address + PREV=`expr $A1 - $A2` # offset to previous symbol + NEXT=+`expr $A3 - $A2` # offset to next symbol + OVERFLOW=+`printf "0x%x" ${PREV}` # overflow offset to previous symbol +} + +# We have to decode symbol addresses to get correct offsets. +# If the offset is not an instruction boundary, it cause -EILSEQ. +set_offs `grep -A1 -B1 ${TARGET_FUNC} /proc/kallsyms | cut -f 1 -d " " | xargs` + +UINT_TEST=no +# printf "%x" -1 returns (unsigned long)-1. +if [ `printf "%x" -1 | wc -c` != 9 ]; then + UINT_TEST=yes +fi + +echo 0 > events/enable +echo > kprobe_events +echo "p:testprobe ${TARGET_FUNC}" > kprobe_events +echo "p:testprobe ${TARGET}" > kprobe_events +echo "p:testprobe ${TARGET_FUNC}${NEXT}" > kprobe_events +! echo "p:testprobe ${TARGET_FUNC}${PREV}" > kprobe_events +if [ "${UINT_TEST}" = yes ]; then +! echo "p:testprobe ${TARGET_FUNC}${OVERFLOW}" > kprobe_events +fi +echo > kprobe_events +clear_trace -- cgit v1.3-14-g43fede From 440ea4ae182820cfced77cee2b7f3e6eaa8ac5d3 Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Thu, 22 Mar 2018 19:12:19 +0100 Subject: tc-testing: add selftests for 'bpf' action Test d959: Add cBPF action with valid bytecode Test f84a: Add cBPF action with invalid bytecode Test e939: Add eBPF action with valid object-file Test 282d: Add eBPF action with invalid object-file Test d819: Replace cBPF bytecode and action control Test 6ae3: Delete cBPF action Test 3e0d: List cBPF actions Test 55ce: Flush BPF actions Test ccc3: Add cBPF action with duplicate index Test 89c7: Add cBPF action with invalid index Test 7ab9: Add cBPF action with cookie Changes since v1: - use index=2^32-1 in test ccc3, add tests 7a89, 89c7 (thanks Roman Mashak) - added test 282d Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- .../selftests/tc-testing/tc-tests/actions/bpf.json | 289 +++++++++++++++++++++ 1 file changed, 289 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json new file mode 100644 index 000000000000..5b012f4981d4 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/bpf.json @@ -0,0 +1,289 @@ +[ + { + "id": "d959", + "name": "Add cBPF action with valid bytecode", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC action flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' index 100", + "expExitCode": "0", + "verifyCmd": "$TC action get action bpf index 100", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' default-action pipe.*index 100 ref", + "matchCount": "1", + "teardown": [ + "$TC action flush action bpf" + ] + }, + { + "id": "f84a", + "name": "Add cBPF action with invalid bytecode", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf bytecode '4,40 0 0 12,31 0 1 2048,6 0 0 262144,6 0 0 0' index 100", + "expExitCode": "255", + "verifyCmd": "$TC action get action bpf index 100", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,31 0 1 2048,6 0 0 262144,6 0 0 0' default-action pipe.*index 100 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action bpf" + ] + }, + { + "id": "e939", + "name": "Add eBPF action with valid object-file", + "category": [ + "actions", + "bpf" + ], + "setup": [ + "printf '#include \nchar l[] __attribute__((section(\"license\"),used))=\"GPL\"; __attribute__((section(\"action\"),used)) int m(struct __sk_buff *s) { return 2; }' | clang -O2 -x c -c - -target bpf -o _b.o", + [ + "$TC action flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf object-file _b.o index 667", + "expExitCode": "0", + "verifyCmd": "$TC action get action bpf index 667", + "matchPattern": "action order [0-9]*: bpf _b.o:\\[action\\] id [0-9]* tag 3b185187f1855c4c default-action pipe.*index 667 ref", + "matchCount": "1", + "teardown": [ + "$TC action flush action bpf", + "rm -f _b.o" + ] + }, + { + "id": "282d", + "name": "Add eBPF action with invalid object-file", + "category": [ + "actions", + "bpf" + ], + "setup": [ + "printf '#include \nchar l[] __attribute__((section(\"license\"),used))=\"GPL\"; __attribute__((section(\"action\"),used)) int m(struct __sk_buff *s) { s->data = 0x0; return 2; }' | clang -O2 -x c -c - -target bpf -o _c.o", + [ + "$TC action flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf object-file _c.o index 667", + "expExitCode": "255", + "verifyCmd": "$TC action get action bpf index 667", + "matchPattern": "action order [0-9]*: bpf _b.o:\\[action\\] id [0-9].*index 667 ref", + "matchCount": "0", + "teardown": [ + "$TC action flush action bpf", + "rm -f _c.o" + ] + }, + { + "id": "d819", + "name": "Replace cBPF bytecode and action control", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ], + [ + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' index 555", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action replace action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' drop index 555", + "expExitCode": "0", + "verifyCmd": "$TC action get action bpf index 555", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' default-action drop.*index 555 ref", + "matchCount": "1", + "teardown": [ + "$TC action flush action bpf" + ] + }, + { + "id": "6ae3", + "name": "Delete cBPF action ", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ], + [ + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' index 444", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action delete action bpf index 444", + "expExitCode": "0", + "verifyCmd": "$TC action get action bpf index 444", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' default-action pipe.*index 444 ref", + "matchCount": "0", + "teardown": [ + "$TC action flush action bpf" + ] + }, + { + "id": "3e0d", + "name": "List cBPF actions", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC action flush action bpf", + 0, + 1, + 255 + ], + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' ok index 101", + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' drop index 102", + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 33024,6 0 0 262144,6 0 0 0' continue index 103" + ], + "cmdUnderTest": "$TC action list action bpf", + "expExitCode": "0", + "verifyCmd": "$TC action list action bpf", + "matchPattern": "action order [0-9]*: bpf bytecode", + "matchCount": "3", + "teardown": [ + "$TC actions flush action bpf" + ] + }, + { + "id": "55ce", + "name": "Flush BPF actions", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ], + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' ok index 101", + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' drop index 102", + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 33024,6 0 0 262144,6 0 0 0' continue index 103" + ], + "cmdUnderTest": "$TC action flush action bpf", + "expExitCode": "0", + "verifyCmd": "$TC action list action bpf", + "matchPattern": "action order [0-9]*: bpf bytecode", + "matchCount": "0", + "teardown": [ + "$TC actions flush action bpf" + ] + }, + { + "id": "ccc3", + "name": "Add cBPF action with duplicate index", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ], + "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' index 4294967295" + ], + "cmdUnderTest": "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' index 4294967295", + "expExitCode": "255", + "verifyCmd": "$TC action get action bpf index 4294967295", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' default-action pipe.*index 4294967295", + "matchCount": "1", + "teardown": [ + "$TC action flush action bpf" + ] + }, + { + "id": "89c7", + "name": "Add cBPF action with invalid index", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' index 4294967296 cookie 12345", + "expExitCode": "255", + "verifyCmd": "$TC action ls action bpf", + "matchPattern": "action order [0-9]*: bpf bytecode '4,40 0 0 12,21 0 1 2048,6 0 0 262144,6 0 0 0' default-action pipe.*cookie 12345", + "matchCount": "0", + "teardown": [ + "$TC action flush action bpf" + ] + }, + { + "id": "7ab9", + "name": "Add cBPF action with cookie", + "category": [ + "actions", + "bpf" + ], + "setup": [ + [ + "$TC actions flush action bpf", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC action add action bpf bytecode '4,40 0 0 12,21 0 1 2054,6 0 0 262144,6 0 0 0' cookie d0d0d0d0d0d0d0d0", + "expExitCode": "0", + "verifyCmd": "$TC action list action bpf", + "matchPattern": "action order [0-9]*: bpf.*cookie d0d0d0d0d0d0d0", + "matchCount": "1", + "teardown": [ + "$TC action flush action bpf" + ] + } +] -- cgit v1.3-14-g43fede From 808679e7fa8018321ccfb227628175b84d2a5ff9 Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Sun, 25 Mar 2018 17:20:06 -0400 Subject: tc-testing: updated police, mirred, skbedit and skbmod with more tests Added extra test cases for control actions (reclassify, pipe etc.), cookies, max index value and police args sanity check. Signed-off-by: Roman Mashak Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/mirred.json | 192 +++++++++++++++++++++ .../tc-testing/tc-tests/actions/police.json | 144 ++++++++++++++++ .../tc-testing/tc-tests/actions/skbedit.json | 168 ++++++++++++++++++ .../tc-testing/tc-tests/actions/skbmod.json | 24 +++ 4 files changed, 528 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json index 0fcccf18399b..443c9b3c8664 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/mirred.json @@ -170,6 +170,198 @@ "$TC actions flush action mirred" ] }, + { + "id": "8917", + "name": "Add mirred mirror action with control pass", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo pass index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 1", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) pass.*index 1 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "1054", + "name": "Add mirred mirror action with control pipe", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo pipe index 15", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 15", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) pipe.*index 15 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "9887", + "name": "Add mirred mirror action with control continue", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo continue index 15", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 15", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) continue.*index 15 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "e4aa", + "name": "Add mirred mirror action with control reclassify", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo reclassify index 150", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 150", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) reclassify.*index 150 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "ece9", + "name": "Add mirred mirror action with control drop", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo drop index 99", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 99", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) drop.*index 99 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "0031", + "name": "Add mirred mirror action with control jump", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo jump 10 index 99", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 99", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) jump 10.*index 99 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "407c", + "name": "Add mirred mirror action with cookie", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo reclassify cookie aa11bb22cc33dd44ee55", + "expExitCode": "0", + "verifyCmd": "$TC actions ls action mirred", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) reclassify.*cookie aa11bb22cc33dd44ee55", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, + { + "id": "8b69", + "name": "Add mirred mirror action with maximum index", + "category": [ + "actions", + "mirred" + ], + "setup": [ + [ + "$TC actions flush action mirred", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action mirred ingress mirror dev lo pipe index 4294967295", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 4294967295", + "matchPattern": "action order [0-9]*: mirred \\(Ingress Mirror to device lo\\) pipe.*index 4294967295", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, { "id": "a70e", "name": "Delete mirred mirror action", diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/police.json b/tools/testing/selftests/tc-testing/tc-tests/actions/police.json index 0e602a3f9393..38d85a1d7492 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/police.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/police.json @@ -264,6 +264,150 @@ "$TC actions flush action police" ] }, + { + "id": "ddd6", + "name": "Add police action with invalid rate value", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 3tb burst 250k conform-exceed pass/pipe index 5", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action police", + "matchPattern": "action order [0-9]*: police 0x5 rate 3Tb burst 250Kb mtu 2Kb action pass/pipe", + "matchCount": "0", + "teardown": [ + "$TC actions flush action police" + ] + }, + { + "id": "f61c", + "name": "Add police action with invalid burst value", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 3kbit burst 250P conform-exceed pass/pipe index 5", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action police", + "matchPattern": "action order [0-9]*: police 0x5 rate 3Kbit burst 250Pb mtu 2Kb action pass/pipe", + "matchCount": "0", + "teardown": [ + "$TC actions flush action police" + ] + }, + { + "id": "c26f", + "name": "Add police action with invalid peakrate value", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 90kbit burst 10k mtu 2kb peakrate 100T index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action police", + "matchPattern": "action order [0-9]*: police 0x1 rate 90Kbit burst 10Kb mtu 2Kb peakrate 100Tbit", + "matchCount": "0", + "teardown": [ + "$TC actions flush action police" + ] + }, + { + "id": "db04", + "name": "Add police action with invalid mtu value", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 10kbit burst 10k mtu 2Pbit index 1", + "expExitCode": "255", + "verifyCmd": "$TC actions ls action police", + "matchPattern": "action order [0-9]*: police 0x1 rate 10Kbit burst 1Kb mtu 2Pb", + "matchCount": "0", + "teardown": [ + "$TC actions flush action police" + ] + }, + { + "id": "f3c9", + "name": "Add police action with cookie", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 10mbit burst 10k index 1 cookie a1b1c1d1e1f12233bb", + "expExitCode": "0", + "verifyCmd": "$TC actions get action police index 1", + "matchPattern": "action order [0-9]*: police 0x1 rate 10Mbit burst 10Kb mtu 2Kb.*cookie a1b1c1d1e1f12233bb", + "matchCount": "1", + "teardown": [ + "$TC actions flush action police" + ] + }, + { + "id": "d190", + "name": "Add police action with maximum index", + "category": [ + "actions", + "police" + ], + "setup": [ + [ + "$TC actions flush action police", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action police rate 10mbit burst 10k index 4294967295", + "expExitCode": "0", + "verifyCmd": "$TC actions get action mirred index 4294967295", + "matchPattern": "action order [0-9]*: police 0xffffffff rate 10Mbit burst 10Kb mtu 2Kb", + "matchCount": "1", + "teardown": [ + "$TC actions flush action mirred" + ] + }, { "id": "336e", "name": "Delete police action", diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json index 99635ea4722e..37ecc2716fee 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbedit.json @@ -215,6 +215,174 @@ "$TC actions flush action skbedit" ] }, + { + "id": "464a", + "name": "Add skbedit action with control pipe", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit ptype host pipe index 11", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 11", + "matchPattern": "action order [0-9]*: skbedit ptype host pipe.*index 11 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "212f", + "name": "Add skbedit action with control reclassify", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit mark 56789 reclassify index 90", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 90", + "matchPattern": "action order [0-9]*: skbedit mark 56789 reclassify.*index 90 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "0651", + "name": "Add skbedit action with control pass", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 pass index 271", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 271", + "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 pass.*index 271 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "cc53", + "name": "Add skbedit action with control drop", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit queue_mapping 3 drop index 271", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 271", + "matchPattern": "action order [0-9]*: skbedit queue_mapping 3 drop.*index 271 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "ec16", + "name": "Add skbedit action with control jump", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit priority 8 jump 9 index 2", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 2", + "matchPattern": "action order [0-9]*: skbedit priority :8 jump 9.*index 2 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "db54", + "name": "Add skbedit action with control continue", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 32", + "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, + { + "id": "1055", + "name": "Add skbedit action with cookie", + "category": [ + "actions", + "skbedit" + ], + "setup": [ + [ + "$TC actions flush action skbedit", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbedit priority 16 continue index 32 cookie deadbeef", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbedit index 32", + "matchPattern": "action order [0-9]*: skbedit priority :16 continue.*index 32 ref.*cookie deadbeef", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbedit" + ] + }, { "id": "5172", "name": "List skbedit actions", diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json index 90bba48c3f07..fe3326e939c1 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/skbmod.json @@ -263,6 +263,30 @@ "$TC actions flush action skbmod" ] }, + { + "id": "6046", + "name": "Add skbmod action with control reclassify and cookie", + "category": [ + "actions", + "skbmod" + ], + "setup": [ + [ + "$TC actions flush action skbmod", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action skbmod set smac 00:01:02:03:04:01 reclassify index 1 cookie ddeeffaabb11cc22", + "expExitCode": "0", + "verifyCmd": "$TC actions get action skbmod index 1", + "matchPattern": "action order [0-9]*: skbmod reclassify set smac 00:01:02:03:04:01.*index 1 ref.*cookie ddeeffaabb11cc22", + "matchCount": "1", + "teardown": [ + "$TC actions flush action skbmod" + ] + }, { "id": "58cb", "name": "List skbmod actions", -- cgit v1.3-14-g43fede From 4aaacfc669941d4faed3c105f38368b463d0f59d Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 9 Mar 2018 16:29:02 +0100 Subject: ktest: remove obsolete architectures A number of architectures are being removed from the kernel, so we no longer need to test them. Acked-by: Steven Rostedt (VMware) Signed-off-by: Arnd Bergmann --- tools/testing/ktest/examples/crosstests.conf | 31 +--------------------------- 1 file changed, 1 insertion(+), 30 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/examples/crosstests.conf b/tools/testing/ktest/examples/crosstests.conf index a1203148dfa1..6907f32590b2 100644 --- a/tools/testing/ktest/examples/crosstests.conf +++ b/tools/testing/ktest/examples/crosstests.conf @@ -59,7 +59,7 @@ DO_DEFAULT := 1 # By setting both DO_FAILED and DO_DEFAULT to zero, you can pick a single # arch that you want to test. (uncomment RUN and chose your arch) -#RUN := m32r +#RUN := arm # At the bottom of the config file exists a bisect test. You can update that # test and set DO_FAILED and DO_DEFAULT to zero, and uncomment this variable @@ -106,33 +106,11 @@ TEST_START IF ${RUN} == arm || ${DO_DEFAULT} CROSS = arm-unknown-linux-gnueabi ARCH = arm -# black fin -TEST_START IF ${RUN} == bfin || ${DO_DEFAULT} -CROSS = bfin-uclinux -ARCH = blackfin -BUILD_OPTIONS = -j8 vmlinux - -# cris - FAILS? -TEST_START IF ${RUN} == cris || ${RUN} == cris64 || ${DO_FAILED} -CROSS = cris-linux -ARCH = cris - -# cris32 - not right arch? -TEST_START IF ${RUN} == cris || ${RUN} == cris32 || ${DO_FAILED} -CROSS = crisv32-linux -ARCH = cris - # ia64 TEST_START IF ${RUN} == ia64 || ${DO_DEFAULT} CROSS = ia64-linux ARCH = ia64 -# frv -TEST_START IF ${RUN} == frv || ${DO_FAILED} -CROSS = frv-linux -ARCH = frv -GCC_VER = 4.5.1 - # m68k fails with error? TEST_START IF ${RUN} == m68k || ${DO_DEFAULT} CROSS = m68k-linux @@ -148,13 +126,6 @@ TEST_START IF ${RUN} == mips || ${RUN} == mips32 || ${DO_DEFAULT} CROSS = mips-linux ARCH = mips -# m32r -TEST_START IF ${RUN} == m32r || ${DO_FAILED} -CROSS = m32r-linux -ARCH = m32r -GCC_VER = 4.5.1 -BUILD_OPTIONS = -j8 vmlinux - # parisc64 failed? TEST_START IF ${RUN} == hppa || ${RUN} == hppa64 || ${DO_FAILED} CROSS = hppa64-linux -- cgit v1.3-14-g43fede From 88893cf787d3062c631cc20b875068eb11756e03 Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 23 Mar 2018 20:44:27 +1100 Subject: selftests: Print the test we're running to /dev/kmsg Some tests cause the kernel to print things to the kernel log buffer (ie. printk), in particular oops and warnings etc. However when running all the tests in succession it's not always obvious which test(s) caused the kernel to print something. We can narrow it down by printing which test directory we're running in to /dev/kmsg, if it's writable. Example output: [ 170.149149] kselftest: Running tests in powerpc [ 305.300132] kworker/dying (71) used greatest stack depth: 7776 bytes left [ 808.915456] kselftest: Running tests in pstore Signed-off-by: Michael Ellerman Signed-off-by: Shuah Khan --- tools/testing/selftests/Makefile | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index a41b4be28b9f..f4dfee6ea8a4 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -138,6 +138,7 @@ ifdef INSTALL_PATH echo "echo ; echo TAP version 13" >> $(ALL_SCRIPT); \ echo "echo Running tests in $$TARGET" >> $(ALL_SCRIPT); \ echo "echo ========================================" >> $(ALL_SCRIPT); \ + echo "[ -w /dev/kmsg ] && echo \"kselftest: Running tests in $$TARGET\" >> /dev/kmsg" >> $(ALL_SCRIPT); \ echo "cd $$TARGET" >> $(ALL_SCRIPT); \ make -s --no-print-directory OUTPUT=$$BUILD_TARGET -C $$TARGET emit_tests >> $(ALL_SCRIPT); \ echo "cd \$$ROOT" >> $(ALL_SCRIPT); \ -- cgit v1.3-14-g43fede From cd464197f2378499db134d6c44af3b4e3c0c14b5 Mon Sep 17 00:00:00 2001 From: Lucas Bates Date: Mon, 26 Mar 2018 10:46:14 -0400 Subject: tc-testing: Correct compound statements for namespace execution If tdc is executing test cases inside a namespace, only the first command in a compound statement will be executed inside the namespace by tdc. As a result, the subsequent commands are not executed inside the namespace and the test will fail. Example: for i in {x..y}; do args="foo"; done && tc actions add $args The namespace execution feature will prepend 'ip netns exec' to the command: ip netns exec tcut for i in {x..y}; do args="foo"; done && \ tc actions add $args So the actual tc command is not parsed by the shell as being part of the namespace execution. Enclosing these compound statements inside a bash invocation with proper escape characters resolves the problem by creating a subshell inside the namespace. Signed-off-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tc-tests/actions/gact.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json index ae96d0350d7e..68c91023cdb9 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/gact.json @@ -481,7 +481,7 @@ 255 ] ], - "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action pass index $i \"; args=\"$args$cmd\"; done && $TC actions add $args", + "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action pass index \\$i \\\"; args=\"\\$args\\$cmd\"; done && $TC actions add \\$args\"", "expExitCode": "0", "verifyCmd": "$TC actions list action gact", "matchPattern": "^[ \t]+index [0-9]+ ref", @@ -505,7 +505,7 @@ 255 ] ], - "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action continue index $i cookie aabbccddeeff112233445566778800a1 \"; args=\"$args$cmd\"; done && $TC actions add $args", + "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action continue index \\$i cookie aabbccddeeff112233445566778800a1 \\\"; args=\"\\$args\\$cmd\"; done && $TC actions add \\$args\"", "expExitCode": "0", "verifyCmd": "$TC actions list action gact", "matchPattern": "^[ \t]+index [0-9]+ ref", @@ -528,13 +528,13 @@ 1, 255 ], - "for i in `seq 1 32`; do cmd=\"action continue index $i \"; args=\"$args$cmd\"; done && $TC actions add $args" + "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action continue index \\$i \\\"; args=\\\"\\$args\\$cmd\\\"; done && $TC actions add \\$args\"" ], - "cmdUnderTest": "for i in `seq 1 32`; do cmd=\"action gact index $i \"; args=\"$args$cmd\"; done && $TC actions del $args", + "cmdUnderTest": "bash -c \"for i in \\`seq 1 32\\`; do cmd=\\\"action gact index \\$i \\\"; args=\"\\$args\\$cmd\"; done && $TC actions del \\$args\"", "expExitCode": "0", "verifyCmd": "$TC actions list action gact", "matchPattern": "^[ \t]+index [0-9]+ ref", "matchCount": "0", "teardown": [] } -] \ No newline at end of file +] -- cgit v1.3-14-g43fede From 3bbe0869884ceebffd59d5519c1d560207c6e116 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 28 Mar 2018 12:05:40 -0700 Subject: selftests/bpf: test for bpf_get_stackid() from raw tracepoints similar to traditional traceopint test add bpf_get_stackid() test from raw tracepoints and reduce verbosity of existing stackmap test Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_progs.c | 91 ++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 21 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/bpf/test_progs.c b/tools/testing/selftests/bpf/test_progs.c index e9df48b306df..faadbe233966 100644 --- a/tools/testing/selftests/bpf/test_progs.c +++ b/tools/testing/selftests/bpf/test_progs.c @@ -877,7 +877,7 @@ static void test_stacktrace_map() err = bpf_prog_load(file, BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd); if (CHECK(err, "prog_load", "err %d errno %d\n", err, errno)) - goto out; + return; /* Get the ID for the sched/sched_switch tracepoint */ snprintf(buf, sizeof(buf), @@ -888,8 +888,7 @@ static void test_stacktrace_map() bytes = read(efd, buf, sizeof(buf)); close(efd); - if (CHECK(bytes <= 0 || bytes >= sizeof(buf), - "read", "bytes %d errno %d\n", bytes, errno)) + if (bytes <= 0 || bytes >= sizeof(buf)) goto close_prog; /* Open the perf event and attach bpf progrram */ @@ -906,29 +905,24 @@ static void test_stacktrace_map() goto close_prog; err = ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0); - if (CHECK(err, "perf_event_ioc_enable", "err %d errno %d\n", - err, errno)) - goto close_pmu; + if (err) + goto disable_pmu; err = ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd); - if (CHECK(err, "perf_event_ioc_set_bpf", "err %d errno %d\n", - err, errno)) + if (err) goto disable_pmu; /* find map fds */ control_map_fd = bpf_find_map(__func__, obj, "control_map"); - if (CHECK(control_map_fd < 0, "bpf_find_map control_map", - "err %d errno %d\n", err, errno)) + if (control_map_fd < 0) goto disable_pmu; stackid_hmap_fd = bpf_find_map(__func__, obj, "stackid_hmap"); - if (CHECK(stackid_hmap_fd < 0, "bpf_find_map stackid_hmap", - "err %d errno %d\n", err, errno)) + if (stackid_hmap_fd < 0) goto disable_pmu; stackmap_fd = bpf_find_map(__func__, obj, "stackmap"); - if (CHECK(stackmap_fd < 0, "bpf_find_map stackmap", "err %d errno %d\n", - err, errno)) + if (stackmap_fd < 0) goto disable_pmu; /* give some time for bpf program run */ @@ -945,24 +939,78 @@ static void test_stacktrace_map() err = compare_map_keys(stackid_hmap_fd, stackmap_fd); if (CHECK(err, "compare_map_keys stackid_hmap vs. stackmap", "err %d errno %d\n", err, errno)) - goto disable_pmu; + goto disable_pmu_noerr; err = compare_map_keys(stackmap_fd, stackid_hmap_fd); if (CHECK(err, "compare_map_keys stackmap vs. stackid_hmap", "err %d errno %d\n", err, errno)) - ; /* fall through */ + goto disable_pmu_noerr; + goto disable_pmu_noerr; disable_pmu: + error_cnt++; +disable_pmu_noerr: ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); - -close_pmu: close(pmu_fd); - close_prog: bpf_object__close(obj); +} -out: - return; +static void test_stacktrace_map_raw_tp() +{ + int control_map_fd, stackid_hmap_fd, stackmap_fd; + const char *file = "./test_stacktrace_map.o"; + int efd, err, prog_fd; + __u32 key, val, duration = 0; + struct bpf_object *obj; + + err = bpf_prog_load(file, BPF_PROG_TYPE_RAW_TRACEPOINT, &obj, &prog_fd); + if (CHECK(err, "prog_load raw tp", "err %d errno %d\n", err, errno)) + return; + + efd = bpf_raw_tracepoint_open("sched_switch", prog_fd); + if (CHECK(efd < 0, "raw_tp_open", "err %d errno %d\n", efd, errno)) + goto close_prog; + + /* find map fds */ + control_map_fd = bpf_find_map(__func__, obj, "control_map"); + if (control_map_fd < 0) + goto close_prog; + + stackid_hmap_fd = bpf_find_map(__func__, obj, "stackid_hmap"); + if (stackid_hmap_fd < 0) + goto close_prog; + + stackmap_fd = bpf_find_map(__func__, obj, "stackmap"); + if (stackmap_fd < 0) + goto close_prog; + + /* give some time for bpf program run */ + sleep(1); + + /* disable stack trace collection */ + key = 0; + val = 1; + bpf_map_update_elem(control_map_fd, &key, &val, 0); + + /* for every element in stackid_hmap, we can find a corresponding one + * in stackmap, and vise versa. + */ + err = compare_map_keys(stackid_hmap_fd, stackmap_fd); + if (CHECK(err, "compare_map_keys stackid_hmap vs. stackmap", + "err %d errno %d\n", err, errno)) + goto close_prog; + + err = compare_map_keys(stackmap_fd, stackid_hmap_fd); + if (CHECK(err, "compare_map_keys stackmap vs. stackid_hmap", + "err %d errno %d\n", err, errno)) + goto close_prog; + + goto close_prog_noerr; +close_prog: + error_cnt++; +close_prog_noerr: + bpf_object__close(obj); } static int extract_build_id(char *build_id, size_t size) @@ -1138,6 +1186,7 @@ int main(void) test_tp_attach_query(); test_stacktrace_map(); test_stacktrace_build_id(); + test_stacktrace_map_raw_tp(); printf("Summary: %d PASSED, %d FAILED\n", pass_cnt, error_cnt); return error_cnt ? EXIT_FAILURE : EXIT_SUCCESS; -- cgit v1.3-14-g43fede From 1dad0f9ffff735ca09ea1588a9c279a45c8978be Mon Sep 17 00:00:00 2001 From: Roman Mashak Date: Thu, 29 Mar 2018 08:52:37 -0400 Subject: tc-testing: add connmark action tests Signed-off-by: Roman Mashak Signed-off-by: David S. Miller --- .../tc-testing/tc-tests/actions/connmark.json | 291 +++++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json b/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json new file mode 100644 index 000000000000..70952bd98ff9 --- /dev/null +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/connmark.json @@ -0,0 +1,291 @@ +[ + { + "id": "2002", + "name": "Add valid connmark action with defaults", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark", + "expExitCode": "0", + "verifyCmd": "$TC actions list action connmark", + "matchPattern": "action order [0-9]+: connmark zone 0 pipe", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "56a5", + "name": "Add valid connmark action with control pass", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark pass index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 1", + "matchPattern": "action order [0-9]+: connmark zone 0 pass.*index 1 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "7c66", + "name": "Add valid connmark action with control drop", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark drop index 100", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 100", + "matchPattern": "action order [0-9]+: connmark zone 0 drop.*index 100 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "a913", + "name": "Add valid connmark action with control pipe", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark pipe index 455", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 455", + "matchPattern": "action order [0-9]+: connmark zone 0 pipe.*index 455 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "bdd8", + "name": "Add valid connmark action with control reclassify", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark reclassify index 7", + "expExitCode": "0", + "verifyCmd": "$TC actions list action connmark", + "matchPattern": "action order [0-9]+: connmark zone 0 reclassify.*index 7 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "b8be", + "name": "Add valid connmark action with control continue", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark continue index 17", + "expExitCode": "0", + "verifyCmd": "$TC actions list action connmark", + "matchPattern": "action order [0-9]+: connmark zone 0 continue.*index 17 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "d8a6", + "name": "Add valid connmark action with control jump", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark jump 10 index 17", + "expExitCode": "0", + "verifyCmd": "$TC actions list action connmark", + "matchPattern": "action order [0-9]+: connmark zone 0 jump 10.*index 17 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "aae8", + "name": "Add valid connmark action with zone argument", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark zone 100 pipe index 1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 1", + "matchPattern": "action order [0-9]+: connmark zone 100 pipe.*index 1 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "2f0b", + "name": "Add valid connmark action with invalid zone argument", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark zone 65536 reclassify index 21", + "expExitCode": "255", + "verifyCmd": "$TC actions get action connmark index 1", + "matchPattern": "action order [0-9]+: connmark zone 65536 reclassify.*index 21 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "9305", + "name": "Add connmark action with unsupported argument", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark zone 655 unsupp_arg pass index 2", + "expExitCode": "255", + "verifyCmd": "$TC actions get action connmark index 2", + "matchPattern": "action order [0-9]+: connmark zone 655 unsupp_arg pass.*index 2 ref", + "matchCount": "0", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "71ca", + "name": "Add valid connmark action and replace it", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ], + "$TC actions add action connmark zone 777 pass index 555" + ], + "cmdUnderTest": "$TC actions replace action connmark zone 555 reclassify index 555", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 555", + "matchPattern": "action order [0-9]+: connmark zone 555 reclassify.*index 555 ref", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + }, + { + "id": "5f8f", + "name": "Add valid connmark action with cookie", + "category": [ + "actions", + "connmark" + ], + "setup": [ + [ + "$TC actions flush action connmark", + 0, + 1, + 255 + ] + ], + "cmdUnderTest": "$TC actions add action connmark zone 555 pipe index 5 cookie aabbccddeeff112233445566778800a1", + "expExitCode": "0", + "verifyCmd": "$TC actions get action connmark index 5", + "matchPattern": "action order [0-9]+: connmark zone 555 pipe.*index 5 ref.*cookie aabbccddeeff112233445566778800a1", + "matchCount": "1", + "teardown": [ + "$TC actions flush action connmark" + ] + } +] -- cgit v1.3-14-g43fede From c0b6edef0bf0e33c12eaf80c676ff09def011518 Mon Sep 17 00:00:00 2001 From: Lucas Bates Date: Thu, 29 Mar 2018 15:58:10 -0400 Subject: tc-testing: Add newline when writing test case files When using the -i feature to generate random ID numbers for test cases in tdc, the function that writes the JSON to file doesn't add a newline character to the end of the file, so we have to add our own. Signed-off-by: Lucas Bates Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tdc.py | 1 + 1 file changed, 1 insertion(+) (limited to 'tools/testing') diff --git a/tools/testing/selftests/tc-testing/tdc.py b/tools/testing/selftests/tc-testing/tdc.py index 44de4a272a11..87a04a8a5945 100755 --- a/tools/testing/selftests/tc-testing/tdc.py +++ b/tools/testing/selftests/tc-testing/tdc.py @@ -490,6 +490,7 @@ def generate_case_ids(alltests): testlist.append(t) outfile = open(f, "w") json.dump(testlist, outfile, indent=4) + outfile.write("\n") outfile.close() def filter_tests_by_id(args, testlist): -- cgit v1.3-14-g43fede From e50b0a6f089308bec6b2d0198abed231dee4d277 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Fri, 30 Mar 2018 15:08:03 -0700 Subject: selftests/bpf: Selftest for sys_bind hooks Add selftest to work with bpf_sock_addr context from `BPF_PROG_TYPE_CGROUP_SOCK_ADDR` programs. Try to bind(2) on IP:port and apply: * loads to make sure context can be read correctly, including narrow loads (byte, half) for IP and full-size loads (word) for all fields; * stores to those fields allowed by verifier. All combination from IPv4/IPv6 and TCP/UDP are tested. Both scenarios are tested: * valid programs can be loaded and attached; * invalid programs can be neither loaded nor attached. Test passes when expected data can be read from context in the BPF-program, and after the call to bind(2) socket is bound to IP:port pair that was written by BPF-program to the context. Example: # ./test_sock_addr Attached bind4 program. Test case #1 (IPv4/TCP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Test case #2 (IPv4/UDP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Attached bind6 program. Test case #3 (IPv6/TCP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) Test case #4 (IPv6/UDP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) ### SUCCESS Signed-off-by: Andrey Ignatov Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 23 ++ tools/lib/bpf/libbpf.c | 6 + tools/testing/selftests/bpf/Makefile | 3 +- tools/testing/selftests/bpf/test_sock_addr.c | 486 +++++++++++++++++++++++++++ 4 files changed, 517 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/test_sock_addr.c (limited to 'tools/testing') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e1c1fed63396..f2120c5c0578 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -136,6 +136,7 @@ enum bpf_prog_type { BPF_PROG_TYPE_CGROUP_DEVICE, BPF_PROG_TYPE_SK_MSG, BPF_PROG_TYPE_RAW_TRACEPOINT, + BPF_PROG_TYPE_CGROUP_SOCK_ADDR, }; enum bpf_attach_type { @@ -147,6 +148,8 @@ enum bpf_attach_type { BPF_SK_SKB_STREAM_VERDICT, BPF_CGROUP_DEVICE, BPF_SK_MSG_VERDICT, + BPF_CGROUP_INET4_BIND, + BPF_CGROUP_INET6_BIND, __MAX_BPF_ATTACH_TYPE }; @@ -1009,6 +1012,26 @@ struct bpf_map_info { __u64 netns_ino; } __attribute__((aligned(8))); +/* User bpf_sock_addr struct to access socket fields and sockaddr struct passed + * by user and intended to be used by socket (e.g. to bind to, depends on + * attach attach type). + */ +struct bpf_sock_addr { + __u32 user_family; /* Allows 4-byte read, but no write. */ + __u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write. + * Stored in network byte order. + */ + __u32 user_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write. + * Stored in network byte order. + */ + __u32 user_port; /* Allows 4-byte read and write. + * Stored in network byte order + */ + __u32 family; /* Allows 4-byte read, but no write */ + __u32 type; /* Allows 4-byte read, but no write */ + __u32 protocol; /* Allows 4-byte read, but no write */ +}; + /* User bpf_sock_ops struct to access socket values and specify request ops * and their replies. * Some of this fields are in network (bigendian) byte order and may need diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 48e3e743ebf7..d7ce8818982c 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1859,6 +1859,9 @@ static void bpf_program__set_expected_attach_type(struct bpf_program *prog, #define BPF_PROG_SEC(string, ptype) BPF_PROG_SEC_FULL(string, ptype, 0) +#define BPF_SA_PROG_SEC(string, ptype) \ + BPF_PROG_SEC_FULL(string, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, ptype) + static const struct { const char *sec; size_t len; @@ -1882,10 +1885,13 @@ static const struct { BPF_PROG_SEC("sockops", BPF_PROG_TYPE_SOCK_OPS), BPF_PROG_SEC("sk_skb", BPF_PROG_TYPE_SK_SKB), BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), + BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), + BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), }; #undef BPF_PROG_SEC #undef BPF_PROG_SEC_FULL +#undef BPF_SA_PROG_SEC static int bpf_program__identify_section(struct bpf_program *prog) { diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index f35fb02bdf56..f4717c910874 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -23,7 +23,7 @@ urandom_read: urandom_read.c # Order correspond to 'make run_tests' order TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ - test_align test_verifier_log test_dev_cgroup test_tcpbpf_user + test_align test_verifier_log test_dev_cgroup test_tcpbpf_user test_sock_addr TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ @@ -51,6 +51,7 @@ $(TEST_GEN_PROGS): $(BPFOBJ) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a $(OUTPUT)/test_dev_cgroup: cgroup_helpers.c +$(OUTPUT)/test_sock_addr: cgroup_helpers.c .PHONY: force diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c new file mode 100644 index 000000000000..a57e13a65e37 --- /dev/null +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -0,0 +1,486 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include +#include + +#include +#include +#include + +#include + +#include + +#include "cgroup_helpers.h" + +#define CG_PATH "/foo" + +#define SERV4_IP "192.168.1.254" +#define SERV4_REWRITE_IP "127.0.0.1" +#define SERV4_PORT 4040 +#define SERV4_REWRITE_PORT 4444 + +#define SERV6_IP "face:b00c:1234:5678::abcd" +#define SERV6_REWRITE_IP "::1" +#define SERV6_PORT 6060 +#define SERV6_REWRITE_PORT 6666 + +#define INET_NTOP_BUF 40 + +typedef int (*load_fn)(enum bpf_attach_type, const char *comment); +typedef int (*info_fn)(int, struct sockaddr *, socklen_t *); + +struct program { + enum bpf_attach_type type; + load_fn loadfn; + int fd; + const char *name; + enum bpf_attach_type invalid_type; +}; + +char bpf_log_buf[BPF_LOG_BUF_SIZE]; + +static int mk_sockaddr(int domain, const char *ip, unsigned short port, + struct sockaddr *addr, socklen_t addr_len) +{ + struct sockaddr_in6 *addr6; + struct sockaddr_in *addr4; + + if (domain != AF_INET && domain != AF_INET6) { + log_err("Unsupported address family"); + return -1; + } + + memset(addr, 0, addr_len); + + if (domain == AF_INET) { + if (addr_len < sizeof(struct sockaddr_in)) + return -1; + addr4 = (struct sockaddr_in *)addr; + addr4->sin_family = domain; + addr4->sin_port = htons(port); + if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) { + log_err("Invalid IPv4: %s", ip); + return -1; + } + } else if (domain == AF_INET6) { + if (addr_len < sizeof(struct sockaddr_in6)) + return -1; + addr6 = (struct sockaddr_in6 *)addr; + addr6->sin6_family = domain; + addr6->sin6_port = htons(port); + if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) { + log_err("Invalid IPv6: %s", ip); + return -1; + } + } + + return 0; +} + +static int load_insns(enum bpf_attach_type attach_type, + const struct bpf_insn *insns, size_t insns_cnt, + const char *comment) +{ + struct bpf_load_program_attr load_attr; + int ret; + + memset(&load_attr, 0, sizeof(struct bpf_load_program_attr)); + load_attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; + load_attr.expected_attach_type = attach_type; + load_attr.insns = insns; + load_attr.insns_cnt = insns_cnt; + load_attr.license = "GPL"; + + ret = bpf_load_program_xattr(&load_attr, bpf_log_buf, BPF_LOG_BUF_SIZE); + if (ret < 0 && comment) { + log_err(">>> Loading %s program error.\n" + ">>> Output from verifier:\n%s\n-------\n", + comment, bpf_log_buf); + } + + return ret; +} + +/* [1] These testing programs try to read different context fields, including + * narrow loads of different sizes from user_ip4 and user_ip6, and write to + * those allowed to be overridden. + * + * [2] BPF_LD_IMM64 & BPF_JMP_REG are used below whenever there is a need to + * compare a register with unsigned 32bit integer. BPF_JMP_IMM can't be used + * in such cases since it accepts only _signed_ 32bit integer as IMM + * argument. Also note that BPF_LD_IMM64 contains 2 instructions what matters + * to count jumps properly. + */ + +static int bind4_prog_load(enum bpf_attach_type attach_type, + const char *comment) +{ + union { + uint8_t u4_addr8[4]; + uint16_t u4_addr16[2]; + uint32_t u4_addr32; + } ip4; + struct sockaddr_in addr4_rw; + + if (inet_pton(AF_INET, SERV4_IP, (void *)&ip4) != 1) { + log_err("Invalid IPv4: %s", SERV4_IP); + return -1; + } + + if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT, + (struct sockaddr *)&addr4_rw, sizeof(addr4_rw)) == -1) + return -1; + + /* See [1]. */ + struct bpf_insn insns[] = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + + /* if (sk.family == AF_INET && */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, family)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 16), + + /* (sk.type == SOCK_DGRAM || sk.type == SOCK_STREAM) && */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, type)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 1), + BPF_JMP_A(1), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_STREAM, 12), + + /* 1st_byte_of_user_ip4 == expected && */ + BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip4)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr8[0], 10), + + /* 1st_half_of_user_ip4 == expected && */ + BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip4)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip4.u4_addr16[0], 8), + + /* whole_user_ip4 == expected) { */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip4)), + BPF_LD_IMM64(BPF_REG_8, ip4.u4_addr32), /* See [2]. */ + BPF_JMP_REG(BPF_JNE, BPF_REG_7, BPF_REG_8, 4), + + /* user_ip4 = addr4_rw.sin_addr */ + BPF_MOV32_IMM(BPF_REG_7, addr4_rw.sin_addr.s_addr), + BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, + offsetof(struct bpf_sock_addr, user_ip4)), + + /* user_port = addr4_rw.sin_port */ + BPF_MOV32_IMM(BPF_REG_7, addr4_rw.sin_port), + BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, + offsetof(struct bpf_sock_addr, user_port)), + /* } */ + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }; + + return load_insns(attach_type, insns, + sizeof(insns) / sizeof(struct bpf_insn), comment); +} + +static int bind6_prog_load(enum bpf_attach_type attach_type, + const char *comment) +{ + struct sockaddr_in6 addr6_rw; + struct in6_addr ip6; + + if (inet_pton(AF_INET6, SERV6_IP, (void *)&ip6) != 1) { + log_err("Invalid IPv6: %s", SERV6_IP); + return -1; + } + + if (mk_sockaddr(AF_INET6, SERV6_REWRITE_IP, SERV6_REWRITE_PORT, + (struct sockaddr *)&addr6_rw, sizeof(addr6_rw)) == -1) + return -1; + + /* See [1]. */ + struct bpf_insn insns[] = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + + /* if (sk.family == AF_INET6 && */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, family)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18), + + /* 5th_byte_of_user_ip6 == expected && */ + BPF_LDX_MEM(BPF_B, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip6[1])), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip6.s6_addr[4], 16), + + /* 3rd_half_of_user_ip6 == expected && */ + BPF_LDX_MEM(BPF_H, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip6[1])), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, ip6.s6_addr16[2], 14), + + /* last_word_of_user_ip6 == expected) { */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock_addr, user_ip6[3])), + BPF_LD_IMM64(BPF_REG_8, ip6.s6_addr32[3]), /* See [2]. */ + BPF_JMP_REG(BPF_JNE, BPF_REG_7, BPF_REG_8, 10), + + +#define STORE_IPV6_WORD(N) \ + BPF_MOV32_IMM(BPF_REG_7, addr6_rw.sin6_addr.s6_addr32[N]), \ + BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, \ + offsetof(struct bpf_sock_addr, user_ip6[N])) + + /* user_ip6 = addr6_rw.sin6_addr */ + STORE_IPV6_WORD(0), + STORE_IPV6_WORD(1), + STORE_IPV6_WORD(2), + STORE_IPV6_WORD(3), + + /* user_port = addr6_rw.sin6_port */ + BPF_MOV32_IMM(BPF_REG_7, addr6_rw.sin6_port), + BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7, + offsetof(struct bpf_sock_addr, user_port)), + + /* } */ + + /* return 1 */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }; + + return load_insns(attach_type, insns, + sizeof(insns) / sizeof(struct bpf_insn), comment); +} + +static void print_ip_port(int sockfd, info_fn fn, const char *fmt) +{ + char addr_buf[INET_NTOP_BUF]; + struct sockaddr_storage addr; + struct sockaddr_in6 *addr6; + struct sockaddr_in *addr4; + socklen_t addr_len; + unsigned short port; + void *nip; + + addr_len = sizeof(struct sockaddr_storage); + memset(&addr, 0, addr_len); + + if (fn(sockfd, (struct sockaddr *)&addr, (socklen_t *)&addr_len) == 0) { + if (addr.ss_family == AF_INET) { + addr4 = (struct sockaddr_in *)&addr; + nip = (void *)&addr4->sin_addr; + port = ntohs(addr4->sin_port); + } else if (addr.ss_family == AF_INET6) { + addr6 = (struct sockaddr_in6 *)&addr; + nip = (void *)&addr6->sin6_addr; + port = ntohs(addr6->sin6_port); + } else { + return; + } + const char *addr_str = + inet_ntop(addr.ss_family, nip, addr_buf, INET_NTOP_BUF); + printf(fmt, addr_str ? addr_str : "??", port); + } +} + +static void print_local_ip_port(int sockfd, const char *fmt) +{ + print_ip_port(sockfd, getsockname, fmt); +} + +static int start_server(int type, const struct sockaddr_storage *addr, + socklen_t addr_len) +{ + + int fd; + + fd = socket(addr->ss_family, type, 0); + if (fd == -1) { + log_err("Failed to create server socket"); + goto out; + } + + if (bind(fd, (const struct sockaddr *)addr, addr_len) == -1) { + log_err("Failed to bind server socket"); + goto close_out; + } + + if (type == SOCK_STREAM) { + if (listen(fd, 128) == -1) { + log_err("Failed to listen on server socket"); + goto close_out; + } + } + + print_local_ip_port(fd, "\t Actual: bind(%s, %d)\n"); + + goto out; +close_out: + close(fd); + fd = -1; +out: + return fd; +} + +static void print_test_case_num(int domain, int type) +{ + static int test_num; + + printf("Test case #%d (%s/%s):\n", ++test_num, + (domain == AF_INET ? "IPv4" : + domain == AF_INET6 ? "IPv6" : + "unknown_domain"), + (type == SOCK_STREAM ? "TCP" : + type == SOCK_DGRAM ? "UDP" : + "unknown_type")); +} + +static int run_test_case(int domain, int type, const char *ip, + unsigned short port) +{ + struct sockaddr_storage addr; + socklen_t addr_len = sizeof(addr); + int servfd = -1; + int err = 0; + + print_test_case_num(domain, type); + + if (mk_sockaddr(domain, ip, port, (struct sockaddr *)&addr, + addr_len) == -1) + return -1; + + printf("\tRequested: bind(%s, %d) ..\n", ip, port); + servfd = start_server(type, &addr, addr_len); + if (servfd == -1) + goto err; + + goto out; +err: + err = -1; +out: + close(servfd); + return err; +} + +static void close_progs_fds(struct program *progs, size_t prog_cnt) +{ + size_t i; + + for (i = 0; i < prog_cnt; ++i) { + close(progs[i].fd); + progs[i].fd = -1; + } +} + +static int load_and_attach_progs(int cgfd, struct program *progs, + size_t prog_cnt) +{ + size_t i; + + for (i = 0; i < prog_cnt; ++i) { + progs[i].fd = progs[i].loadfn(progs[i].invalid_type, NULL); + if (progs[i].fd != -1) { + log_err("Load with invalid type accepted for %s", + progs[i].name); + goto err; + } + progs[i].fd = progs[i].loadfn(progs[i].type, progs[i].name); + if (progs[i].fd == -1) { + log_err("Failed to load program %s", progs[i].name); + goto err; + } + if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].invalid_type, + BPF_F_ALLOW_OVERRIDE) != -1) { + log_err("Attach with invalid type accepted for %s", + progs[i].name); + goto err; + } + if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].type, + BPF_F_ALLOW_OVERRIDE) == -1) { + log_err("Failed to attach program %s", progs[i].name); + goto err; + } + printf("Attached %s program.\n", progs[i].name); + } + + return 0; +err: + close_progs_fds(progs, prog_cnt); + return -1; +} + +static int run_domain_test(int domain, int cgfd, struct program *progs, + size_t prog_cnt, const char *ip, unsigned short port) +{ + int err = 0; + + if (load_and_attach_progs(cgfd, progs, prog_cnt) == -1) + goto err; + + if (run_test_case(domain, SOCK_STREAM, ip, port) == -1) + goto err; + + if (run_test_case(domain, SOCK_DGRAM, ip, port) == -1) + goto err; + + goto out; +err: + err = -1; +out: + close_progs_fds(progs, prog_cnt); + return err; +} + +static int run_test(void) +{ + size_t inet6_prog_cnt; + size_t inet_prog_cnt; + int cgfd = -1; + int err = 0; + + struct program inet6_progs[] = { + {BPF_CGROUP_INET6_BIND, bind6_prog_load, -1, "bind6", + BPF_CGROUP_INET4_BIND}, + }; + inet6_prog_cnt = sizeof(inet6_progs) / sizeof(struct program); + + struct program inet_progs[] = { + {BPF_CGROUP_INET4_BIND, bind4_prog_load, -1, "bind4", + BPF_CGROUP_INET6_BIND}, + }; + inet_prog_cnt = sizeof(inet_progs) / sizeof(struct program); + + if (setup_cgroup_environment()) + goto err; + + cgfd = create_and_get_cgroup(CG_PATH); + if (!cgfd) + goto err; + + if (join_cgroup(CG_PATH)) + goto err; + + if (run_domain_test(AF_INET, cgfd, inet_progs, inet_prog_cnt, SERV4_IP, + SERV4_PORT) == -1) + goto err; + + if (run_domain_test(AF_INET6, cgfd, inet6_progs, inet6_prog_cnt, + SERV6_IP, SERV6_PORT) == -1) + goto err; + + goto out; +err: + err = -1; +out: + close(cgfd); + cleanup_cgroup_environment(); + printf(err ? "### FAIL\n" : "### SUCCESS\n"); + return err; +} + +int main(int argc, char **argv) +{ + return run_test(); +} -- cgit v1.3-14-g43fede From 622adafb2a12cac6042d4d0d7eb735b7621bf28c Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Fri, 30 Mar 2018 15:08:06 -0700 Subject: selftests/bpf: Selftest for sys_connect hooks Add selftest for BPF_CGROUP_INET4_CONNECT and BPF_CGROUP_INET6_CONNECT attach types. Try to connect(2) to specified IP:port and test that: * remote IP:port pair is overridden; * local end of connection is bound to specified IP. All combinations of IPv4/IPv6 and TCP/UDP are tested. Example: # tcpdump -pn -i lo -w connect.pcap 2>/dev/null & [1] 478 # strace -qqf -e connect -o connect.trace ./test_sock_addr.sh Wait for testing IPv4/IPv6 to become available ... OK Load bind4 with invalid type (can pollute stderr) ... REJECTED Load bind4 with valid type ... OK Attach bind4 with invalid type ... REJECTED Attach bind4 with valid type ... OK Load connect4 with invalid type (can pollute stderr) libbpf: load bpf \ program failed: Permission denied libbpf: -- BEGIN DUMP LOG --- libbpf: 0: (b7) r2 = 23569 1: (63) *(u32 *)(r1 +24) = r2 2: (b7) r2 = 16777343 3: (63) *(u32 *)(r1 +4) = r2 invalid bpf_context access off=4 size=4 [ 1518.404609] random: crng init done libbpf: -- END LOG -- libbpf: failed to load program 'cgroup/connect4' libbpf: failed to load object './connect4_prog.o' ... REJECTED Load connect4 with valid type ... OK Attach connect4 with invalid type ... REJECTED Attach connect4 with valid type ... OK Test case #1 (IPv4/TCP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Requested: connect(192.168.1.254, 4040) from (*, *) .. Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56068) Test case #2 (IPv4/UDP): Requested: bind(192.168.1.254, 4040) .. Actual: bind(127.0.0.1, 4444) Requested: connect(192.168.1.254, 4040) from (*, *) .. Actual: connect(127.0.0.1, 4444) from (127.0.0.4, 56447) Load bind6 with invalid type (can pollute stderr) ... REJECTED Load bind6 with valid type ... OK Attach bind6 with invalid type ... REJECTED Attach bind6 with valid type ... OK Load connect6 with invalid type (can pollute stderr) libbpf: load bpf \ program failed: Permission denied libbpf: -- BEGIN DUMP LOG --- libbpf: 0: (b7) r6 = 0 1: (63) *(u32 *)(r1 +12) = r6 invalid bpf_context access off=12 size=4 libbpf: -- END LOG -- libbpf: failed to load program 'cgroup/connect6' libbpf: failed to load object './connect6_prog.o' ... REJECTED Load connect6 with valid type ... OK Attach connect6 with invalid type ... REJECTED Attach connect6 with valid type ... OK Test case #3 (IPv6/TCP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *) Actual: connect(::1, 6666) from (::6, 37458) Test case #4 (IPv6/UDP): Requested: bind(face:b00c:1234:5678::abcd, 6060) .. Actual: bind(::1, 6666) Requested: connect(face:b00c:1234:5678::abcd, 6060) from (*, *) Actual: connect(::1, 6666) from (::6, 39315) ### SUCCESS # egrep 'connect\(.*AF_INET' connect.trace | \ > egrep -vw 'htons\(1025\)' | fold -b -s -w 72 502 connect(7, {sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, 128) = 0 502 connect(8, {sa_family=AF_INET, sin_port=htons(4040), sin_addr=inet_addr("192.168.1.254")}, 128) = 0 502 connect(9, {sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0 502 connect(10, {sa_family=AF_INET6, sin6_port=htons(6060), inet_pton(AF_INET6, "face:b00c:1234:5678::abcd", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 128) = 0 # fg tcpdump -pn -i lo -w connect.pcap 2> /dev/null # tcpdump -r connect.pcap -n tcp | cut -c 1-72 reading from file connect.pcap, link-type EN10MB (Ethernet) 17:57:40.383533 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [S], seq 1333 17:57:40.383566 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [S.], seq 112 17:57:40.383589 IP 127.0.0.4.56068 > 127.0.0.1.4444: Flags [.], ack 1, w 17:57:40.384578 IP 127.0.0.1.4444 > 127.0.0.4.56068: Flags [R.], seq 1, 17:57:40.403327 IP6 ::6.37458 > ::1.6666: Flags [S], seq 406513443, win 17:57:40.403357 IP6 ::1.6666 > ::6.37458: Flags [S.], seq 2448389240, ac 17:57:40.403376 IP6 ::6.37458 > ::1.6666: Flags [.], ack 1, win 342, opt 17:57:40.404263 IP6 ::1.6666 > ::6.37458: Flags [R.], seq 1, ack 1, win Signed-off-by: Andrey Ignatov Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 12 ++- tools/lib/bpf/libbpf.c | 2 + tools/testing/selftests/bpf/Makefile | 5 +- tools/testing/selftests/bpf/bpf_helpers.h | 2 + tools/testing/selftests/bpf/connect4_prog.c | 45 +++++++++++ tools/testing/selftests/bpf/connect6_prog.c | 61 +++++++++++++++ tools/testing/selftests/bpf/test_sock_addr.c | 104 +++++++++++++++++++++++++- tools/testing/selftests/bpf/test_sock_addr.sh | 57 ++++++++++++++ 8 files changed, 284 insertions(+), 4 deletions(-) create mode 100644 tools/testing/selftests/bpf/connect4_prog.c create mode 100644 tools/testing/selftests/bpf/connect6_prog.c create mode 100755 tools/testing/selftests/bpf/test_sock_addr.sh (limited to 'tools/testing') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index f2120c5c0578..71051d01e8dd 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -150,6 +150,8 @@ enum bpf_attach_type { BPF_SK_MSG_VERDICT, BPF_CGROUP_INET4_BIND, BPF_CGROUP_INET6_BIND, + BPF_CGROUP_INET4_CONNECT, + BPF_CGROUP_INET6_CONNECT, __MAX_BPF_ATTACH_TYPE }; @@ -744,6 +746,13 @@ union bpf_attr { * @flags: reserved for future use * Return: SK_PASS * + * int bpf_bind(ctx, addr, addr_len) + * Bind socket to address. Only binding to IP is supported, no port can be + * set in addr. + * @ctx: pointer to context of type bpf_sock_addr + * @addr: pointer to struct sockaddr to bind socket to + * @addr_len: length of sockaddr structure + * Return: 0 on success or negative error code */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -809,7 +818,8 @@ union bpf_attr { FN(msg_redirect_map), \ FN(msg_apply_bytes), \ FN(msg_cork_bytes), \ - FN(msg_pull_data), + FN(msg_pull_data), \ + FN(bind), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index d7ce8818982c..5922443063f0 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -1887,6 +1887,8 @@ static const struct { BPF_PROG_SEC("sk_msg", BPF_PROG_TYPE_SK_MSG), BPF_SA_PROG_SEC("cgroup/bind4", BPF_CGROUP_INET4_BIND), BPF_SA_PROG_SEC("cgroup/bind6", BPF_CGROUP_INET6_BIND), + BPF_SA_PROG_SEC("cgroup/connect4", BPF_CGROUP_INET4_CONNECT), + BPF_SA_PROG_SEC("cgroup/connect6", BPF_CGROUP_INET6_CONNECT), }; #undef BPF_PROG_SEC diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index f4717c910874..c64d4ebc77ff 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -30,14 +30,15 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o \ - sockmap_tcp_msg_prog.o + sockmap_tcp_msg_prog.o connect4_prog.o connect6_prog.o # Order correspond to 'make run_tests' order TEST_PROGS := test_kmod.sh \ test_libbpf.sh \ test_xdp_redirect.sh \ test_xdp_meta.sh \ - test_offload.py + test_offload.py \ + test_sock_addr.sh # Compile but not part of 'make run_tests' TEST_GEN_PROGS_EXTENDED = test_libbpf_open diff --git a/tools/testing/selftests/bpf/bpf_helpers.h b/tools/testing/selftests/bpf/bpf_helpers.h index 7cae376d8d0c..d8223d99f96d 100644 --- a/tools/testing/selftests/bpf/bpf_helpers.h +++ b/tools/testing/selftests/bpf/bpf_helpers.h @@ -94,6 +94,8 @@ static int (*bpf_msg_cork_bytes)(void *ctx, int len) = (void *) BPF_FUNC_msg_cork_bytes; static int (*bpf_msg_pull_data)(void *ctx, int start, int end, int flags) = (void *) BPF_FUNC_msg_pull_data; +static int (*bpf_bind)(void *ctx, void *addr, int addr_len) = + (void *) BPF_FUNC_bind; /* llvm builtin functions that eBPF C program may use to * emit BPF_LD_ABS and BPF_LD_IND instructions diff --git a/tools/testing/selftests/bpf/connect4_prog.c b/tools/testing/selftests/bpf/connect4_prog.c new file mode 100644 index 000000000000..5a88a681d2ab --- /dev/null +++ b/tools/testing/selftests/bpf/connect4_prog.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include + +#include +#include +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define SRC_REWRITE_IP4 0x7f000004U +#define DST_REWRITE_IP4 0x7f000001U +#define DST_REWRITE_PORT4 4444 + +int _version SEC("version") = 1; + +SEC("cgroup/connect4") +int connect_v4_prog(struct bpf_sock_addr *ctx) +{ + struct sockaddr_in sa; + + /* Rewrite destination. */ + ctx->user_ip4 = bpf_htonl(DST_REWRITE_IP4); + ctx->user_port = bpf_htons(DST_REWRITE_PORT4); + + if (ctx->type == SOCK_DGRAM || ctx->type == SOCK_STREAM) { + ///* Rewrite source. */ + memset(&sa, 0, sizeof(sa)); + + sa.sin_family = AF_INET; + sa.sin_port = bpf_htons(0); + sa.sin_addr.s_addr = bpf_htonl(SRC_REWRITE_IP4); + + if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) + return 0; + } + + return 1; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/connect6_prog.c b/tools/testing/selftests/bpf/connect6_prog.c new file mode 100644 index 000000000000..8ea3f7d12dee --- /dev/null +++ b/tools/testing/selftests/bpf/connect6_prog.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include + +#include +#include +#include +#include +#include + +#include "bpf_helpers.h" +#include "bpf_endian.h" + +#define SRC_REWRITE_IP6_0 0 +#define SRC_REWRITE_IP6_1 0 +#define SRC_REWRITE_IP6_2 0 +#define SRC_REWRITE_IP6_3 6 + +#define DST_REWRITE_IP6_0 0 +#define DST_REWRITE_IP6_1 0 +#define DST_REWRITE_IP6_2 0 +#define DST_REWRITE_IP6_3 1 + +#define DST_REWRITE_PORT6 6666 + +int _version SEC("version") = 1; + +SEC("cgroup/connect6") +int connect_v6_prog(struct bpf_sock_addr *ctx) +{ + struct sockaddr_in6 sa; + + /* Rewrite destination. */ + ctx->user_ip6[0] = bpf_htonl(DST_REWRITE_IP6_0); + ctx->user_ip6[1] = bpf_htonl(DST_REWRITE_IP6_1); + ctx->user_ip6[2] = bpf_htonl(DST_REWRITE_IP6_2); + ctx->user_ip6[3] = bpf_htonl(DST_REWRITE_IP6_3); + + ctx->user_port = bpf_htons(DST_REWRITE_PORT6); + + if (ctx->type == SOCK_DGRAM || ctx->type == SOCK_STREAM) { + /* Rewrite source. */ + memset(&sa, 0, sizeof(sa)); + + sa.sin6_family = AF_INET6; + sa.sin6_port = bpf_htons(0); + + sa.sin6_addr.s6_addr32[0] = bpf_htonl(SRC_REWRITE_IP6_0); + sa.sin6_addr.s6_addr32[1] = bpf_htonl(SRC_REWRITE_IP6_1); + sa.sin6_addr.s6_addr32[2] = bpf_htonl(SRC_REWRITE_IP6_2); + sa.sin6_addr.s6_addr32[3] = bpf_htonl(SRC_REWRITE_IP6_3); + + if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0) + return 0; + } + + return 1; +} + +char _license[] SEC("license") = "GPL"; diff --git a/tools/testing/selftests/bpf/test_sock_addr.c b/tools/testing/selftests/bpf/test_sock_addr.c index a57e13a65e37..d488f20926e8 100644 --- a/tools/testing/selftests/bpf/test_sock_addr.c +++ b/tools/testing/selftests/bpf/test_sock_addr.c @@ -12,10 +12,13 @@ #include #include +#include #include "cgroup_helpers.h" #define CG_PATH "/foo" +#define CONNECT4_PROG_PATH "./connect4_prog.o" +#define CONNECT6_PROG_PATH "./connect6_prog.o" #define SERV4_IP "192.168.1.254" #define SERV4_REWRITE_IP "127.0.0.1" @@ -254,6 +257,41 @@ static int bind6_prog_load(enum bpf_attach_type attach_type, sizeof(insns) / sizeof(struct bpf_insn), comment); } +static int connect_prog_load_path(const char *path, + enum bpf_attach_type attach_type, + const char *comment) +{ + struct bpf_prog_load_attr attr; + struct bpf_object *obj; + int prog_fd; + + memset(&attr, 0, sizeof(struct bpf_prog_load_attr)); + attr.file = path; + attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK_ADDR; + attr.expected_attach_type = attach_type; + + if (bpf_prog_load_xattr(&attr, &obj, &prog_fd)) { + if (comment) + log_err(">>> Loading %s program at %s error.\n", + comment, path); + return -1; + } + + return prog_fd; +} + +static int connect4_prog_load(enum bpf_attach_type attach_type, + const char *comment) +{ + return connect_prog_load_path(CONNECT4_PROG_PATH, attach_type, comment); +} + +static int connect6_prog_load(enum bpf_attach_type attach_type, + const char *comment) +{ + return connect_prog_load_path(CONNECT6_PROG_PATH, attach_type, comment); +} + static void print_ip_port(int sockfd, info_fn fn, const char *fmt) { char addr_buf[INET_NTOP_BUF]; @@ -290,6 +328,11 @@ static void print_local_ip_port(int sockfd, const char *fmt) print_ip_port(sockfd, getsockname, fmt); } +static void print_remote_ip_port(int sockfd, const char *fmt) +{ + print_ip_port(sockfd, getpeername, fmt); +} + static int start_server(int type, const struct sockaddr_storage *addr, socklen_t addr_len) { @@ -324,6 +367,39 @@ out: return fd; } +static int connect_to_server(int type, const struct sockaddr_storage *addr, + socklen_t addr_len) +{ + int domain; + int fd; + + domain = addr->ss_family; + + if (domain != AF_INET && domain != AF_INET6) { + log_err("Unsupported address family"); + return -1; + } + + fd = socket(domain, type, 0); + if (fd == -1) { + log_err("Failed to creating client socket"); + return -1; + } + + if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) { + log_err("Fail to connect to server"); + goto err; + } + + print_remote_ip_port(fd, "\t Actual: connect(%s, %d)"); + print_local_ip_port(fd, " from (%s, %d)\n"); + + return 0; +err: + close(fd); + return -1; +} + static void print_test_case_num(int domain, int type) { static int test_num; @@ -356,6 +432,10 @@ static int run_test_case(int domain, int type, const char *ip, if (servfd == -1) goto err; + printf("\tRequested: connect(%s, %d) from (*, *) ..\n", ip, port); + if (connect_to_server(type, &addr, addr_len)) + goto err; + goto out; err: err = -1; @@ -380,29 +460,41 @@ static int load_and_attach_progs(int cgfd, struct program *progs, size_t i; for (i = 0; i < prog_cnt; ++i) { + printf("Load %s with invalid type (can pollute stderr) ", + progs[i].name); + fflush(stdout); progs[i].fd = progs[i].loadfn(progs[i].invalid_type, NULL); if (progs[i].fd != -1) { log_err("Load with invalid type accepted for %s", progs[i].name); goto err; } + printf("... REJECTED\n"); + + printf("Load %s with valid type", progs[i].name); progs[i].fd = progs[i].loadfn(progs[i].type, progs[i].name); if (progs[i].fd == -1) { log_err("Failed to load program %s", progs[i].name); goto err; } + printf(" ... OK\n"); + + printf("Attach %s with invalid type", progs[i].name); if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].invalid_type, BPF_F_ALLOW_OVERRIDE) != -1) { log_err("Attach with invalid type accepted for %s", progs[i].name); goto err; } + printf(" ... REJECTED\n"); + + printf("Attach %s with valid type", progs[i].name); if (bpf_prog_attach(progs[i].fd, cgfd, progs[i].type, BPF_F_ALLOW_OVERRIDE) == -1) { log_err("Failed to attach program %s", progs[i].name); goto err; } - printf("Attached %s program.\n", progs[i].name); + printf(" ... OK\n"); } return 0; @@ -443,12 +535,16 @@ static int run_test(void) struct program inet6_progs[] = { {BPF_CGROUP_INET6_BIND, bind6_prog_load, -1, "bind6", BPF_CGROUP_INET4_BIND}, + {BPF_CGROUP_INET6_CONNECT, connect6_prog_load, -1, "connect6", + BPF_CGROUP_INET4_CONNECT}, }; inet6_prog_cnt = sizeof(inet6_progs) / sizeof(struct program); struct program inet_progs[] = { {BPF_CGROUP_INET4_BIND, bind4_prog_load, -1, "bind4", BPF_CGROUP_INET6_BIND}, + {BPF_CGROUP_INET4_CONNECT, connect4_prog_load, -1, "connect4", + BPF_CGROUP_INET6_CONNECT}, }; inet_prog_cnt = sizeof(inet_progs) / sizeof(struct program); @@ -482,5 +578,11 @@ out: int main(int argc, char **argv) { + if (argc < 2) { + fprintf(stderr, + "%s has to be run via %s.sh. Skip direct run.\n", + argv[0], argv[0]); + exit(0); + } return run_test(); } diff --git a/tools/testing/selftests/bpf/test_sock_addr.sh b/tools/testing/selftests/bpf/test_sock_addr.sh new file mode 100755 index 000000000000..c6e1dcf992c4 --- /dev/null +++ b/tools/testing/selftests/bpf/test_sock_addr.sh @@ -0,0 +1,57 @@ +#!/bin/sh + +set -eu + +ping_once() +{ + ping -q -c 1 -W 1 ${1%%/*} >/dev/null 2>&1 +} + +wait_for_ip() +{ + local _i + echo -n "Wait for testing IPv4/IPv6 to become available " + for _i in $(seq ${MAX_PING_TRIES}); do + echo -n "." + if ping_once ${TEST_IPv4} && ping_once ${TEST_IPv6}; then + echo " OK" + return + fi + done + echo 1>&2 "ERROR: Timeout waiting for test IP to become available." + exit 1 +} + +setup() +{ + # Create testing interfaces not to interfere with current environment. + ip link add dev ${TEST_IF} type veth peer name ${TEST_IF_PEER} + ip link set ${TEST_IF} up + ip link set ${TEST_IF_PEER} up + + ip -4 addr add ${TEST_IPv4} dev ${TEST_IF} + ip -6 addr add ${TEST_IPv6} dev ${TEST_IF} + wait_for_ip +} + +cleanup() +{ + ip link del ${TEST_IF} 2>/dev/null || : + ip link del ${TEST_IF_PEER} 2>/dev/null || : +} + +main() +{ + trap cleanup EXIT 2 3 6 15 + setup + ./test_sock_addr setup_done +} + +BASENAME=$(basename $0 .sh) +TEST_IF="${BASENAME}1" +TEST_IF_PEER="${BASENAME}2" +TEST_IPv4="127.0.0.4/8" +TEST_IPv6="::6/128" +MAX_PING_TRIES=5 + +main -- cgit v1.3-14-g43fede From 1d436885b23bf4474617914d7eb15e039c83ed99 Mon Sep 17 00:00:00 2001 From: Andrey Ignatov Date: Fri, 30 Mar 2018 15:08:08 -0700 Subject: selftests/bpf: Selftest for sys_bind post-hooks. Add selftest for attach types `BPF_CGROUP_INET4_POST_BIND` and `BPF_CGROUP_INET6_POST_BIND`. The main things tested are: * prog load behaves as expected (valid/invalid accesses in prog); * prog attach behaves as expected (load- vs attach-time attach types); * `BPF_CGROUP_INET_SOCK_CREATE` can be attached in a backward compatible way; * post-hooks return expected result and errno. Example: # ./test_sock Test case: bind4 load with invalid access: src_ip6 .. [PASS] Test case: bind4 load with invalid access: mark .. [PASS] Test case: bind6 load with invalid access: src_ip4 .. [PASS] Test case: sock_create load with invalid access: src_port .. [PASS] Test case: sock_create load w/o expected_attach_type (compat mode) .. [PASS] Test case: sock_create load w/ expected_attach_type .. [PASS] Test case: attach type mismatch bind4 vs bind6 .. [PASS] Test case: attach type mismatch bind6 vs bind4 .. [PASS] Test case: attach type mismatch default vs bind4 .. [PASS] Test case: attach type mismatch bind6 vs sock_create .. [PASS] Test case: bind4 reject all .. [PASS] Test case: bind6 reject all .. [PASS] Test case: bind6 deny specific IP & port .. [PASS] Test case: bind4 allow specific IP & port .. [PASS] Test case: bind4 allow all .. [PASS] Test case: bind6 allow all .. [PASS] Summary: 16 PASSED, 0 FAILED Signed-off-by: Andrey Ignatov Signed-off-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann --- tools/include/uapi/linux/bpf.h | 11 + tools/testing/selftests/bpf/Makefile | 4 +- tools/testing/selftests/bpf/test_sock.c | 479 ++++++++++++++++++++++++++++++++ 3 files changed, 493 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/bpf/test_sock.c (limited to 'tools/testing') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 71051d01e8dd..9d07465023a2 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -152,6 +152,8 @@ enum bpf_attach_type { BPF_CGROUP_INET6_BIND, BPF_CGROUP_INET4_CONNECT, BPF_CGROUP_INET6_CONNECT, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, __MAX_BPF_ATTACH_TYPE }; @@ -947,6 +949,15 @@ struct bpf_sock { __u32 protocol; __u32 mark; __u32 priority; + __u32 src_ip4; /* Allows 1,2,4-byte read. + * Stored in network byte order. + */ + __u32 src_ip6[4]; /* Allows 1,2,4-byte read. + * Stored in network byte order. + */ + __u32 src_port; /* Allows 4-byte read. + * Stored in host byte order + */ }; #define XDP_PACKET_HEADROOM 256 diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index c64d4ebc77ff..0a315ddabbf4 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -23,7 +23,8 @@ urandom_read: urandom_read.c # Order correspond to 'make run_tests' order TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ - test_align test_verifier_log test_dev_cgroup test_tcpbpf_user test_sock_addr + test_align test_verifier_log test_dev_cgroup test_tcpbpf_user \ + test_sock test_sock_addr TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ @@ -52,6 +53,7 @@ $(TEST_GEN_PROGS): $(BPFOBJ) $(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a $(OUTPUT)/test_dev_cgroup: cgroup_helpers.c +$(OUTPUT)/test_sock: cgroup_helpers.c $(OUTPUT)/test_sock_addr: cgroup_helpers.c .PHONY: force diff --git a/tools/testing/selftests/bpf/test_sock.c b/tools/testing/selftests/bpf/test_sock.c new file mode 100644 index 000000000000..73bb20cfb9b7 --- /dev/null +++ b/tools/testing/selftests/bpf/test_sock.c @@ -0,0 +1,479 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2018 Facebook + +#include +#include + +#include +#include +#include + +#include + +#include + +#include "cgroup_helpers.h" + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +#define CG_PATH "/foo" +#define MAX_INSNS 512 + +char bpf_log_buf[BPF_LOG_BUF_SIZE]; + +struct sock_test { + const char *descr; + /* BPF prog properties */ + struct bpf_insn insns[MAX_INSNS]; + enum bpf_attach_type expected_attach_type; + enum bpf_attach_type attach_type; + /* Socket properties */ + int domain; + int type; + /* Endpoint to bind() to */ + const char *ip; + unsigned short port; + /* Expected test result */ + enum { + LOAD_REJECT, + ATTACH_REJECT, + BIND_REJECT, + SUCCESS, + } result; +}; + +static struct sock_test tests[] = { + { + "bind4 load with invalid access: src_ip6", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_ip6[0])), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + 0, + 0, + NULL, + 0, + LOAD_REJECT, + }, + { + "bind4 load with invalid access: mark", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, mark)), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + 0, + 0, + NULL, + 0, + LOAD_REJECT, + }, + { + "bind6 load with invalid access: src_ip4", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_ip4)), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + 0, + 0, + NULL, + 0, + LOAD_REJECT, + }, + { + "sock_create load with invalid access: src_port", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_port)), + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET_SOCK_CREATE, + BPF_CGROUP_INET_SOCK_CREATE, + 0, + 0, + NULL, + 0, + LOAD_REJECT, + }, + { + "sock_create load w/o expected_attach_type (compat mode)", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + 0, + BPF_CGROUP_INET_SOCK_CREATE, + AF_INET, + SOCK_STREAM, + "127.0.0.1", + 8097, + SUCCESS, + }, + { + "sock_create load w/ expected_attach_type", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET_SOCK_CREATE, + BPF_CGROUP_INET_SOCK_CREATE, + AF_INET, + SOCK_STREAM, + "127.0.0.1", + 8097, + SUCCESS, + }, + { + "attach type mismatch bind4 vs bind6", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + 0, + 0, + NULL, + 0, + ATTACH_REJECT, + }, + { + "attach type mismatch bind6 vs bind4", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + 0, + 0, + NULL, + 0, + ATTACH_REJECT, + }, + { + "attach type mismatch default vs bind4", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + 0, + BPF_CGROUP_INET4_POST_BIND, + 0, + 0, + NULL, + 0, + ATTACH_REJECT, + }, + { + "attach type mismatch bind6 vs sock_create", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET_SOCK_CREATE, + 0, + 0, + NULL, + 0, + ATTACH_REJECT, + }, + { + "bind4 reject all", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + AF_INET, + SOCK_STREAM, + "0.0.0.0", + 0, + BIND_REJECT, + }, + { + "bind6 reject all", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + AF_INET6, + SOCK_STREAM, + "::", + 0, + BIND_REJECT, + }, + { + "bind6 deny specific IP & port", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + + /* if (ip == expected && port == expected) */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_ip6[3])), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x01000000, 4), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_port)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x2001, 2), + + /* return DENY; */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_JMP_A(1), + + /* else return ALLOW; */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + AF_INET6, + SOCK_STREAM, + "::1", + 8193, + BIND_REJECT, + }, + { + "bind4 allow specific IP & port", + .insns = { + BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), + + /* if (ip == expected && port == expected) */ + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_ip4)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x0100007F, 4), + BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6, + offsetof(struct bpf_sock, src_port)), + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x1002, 2), + + /* return ALLOW; */ + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_JMP_A(1), + + /* else return DENY; */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + AF_INET, + SOCK_STREAM, + "127.0.0.1", + 4098, + SUCCESS, + }, + { + "bind4 allow all", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET4_POST_BIND, + BPF_CGROUP_INET4_POST_BIND, + AF_INET, + SOCK_STREAM, + "0.0.0.0", + 0, + SUCCESS, + }, + { + "bind6 allow all", + .insns = { + BPF_MOV64_IMM(BPF_REG_0, 1), + BPF_EXIT_INSN(), + }, + BPF_CGROUP_INET6_POST_BIND, + BPF_CGROUP_INET6_POST_BIND, + AF_INET6, + SOCK_STREAM, + "::", + 0, + SUCCESS, + }, +}; + +static size_t probe_prog_length(const struct bpf_insn *fp) +{ + size_t len; + + for (len = MAX_INSNS - 1; len > 0; --len) + if (fp[len].code != 0 || fp[len].imm != 0) + break; + return len + 1; +} + +static int load_sock_prog(const struct bpf_insn *prog, + enum bpf_attach_type attach_type) +{ + struct bpf_load_program_attr attr; + + memset(&attr, 0, sizeof(struct bpf_load_program_attr)); + attr.prog_type = BPF_PROG_TYPE_CGROUP_SOCK; + attr.expected_attach_type = attach_type; + attr.insns = prog; + attr.insns_cnt = probe_prog_length(attr.insns); + attr.license = "GPL"; + + return bpf_load_program_xattr(&attr, bpf_log_buf, BPF_LOG_BUF_SIZE); +} + +static int attach_sock_prog(int cgfd, int progfd, + enum bpf_attach_type attach_type) +{ + return bpf_prog_attach(progfd, cgfd, attach_type, BPF_F_ALLOW_OVERRIDE); +} + +static int bind_sock(int domain, int type, const char *ip, unsigned short port) +{ + struct sockaddr_storage addr; + struct sockaddr_in6 *addr6; + struct sockaddr_in *addr4; + int sockfd = -1; + socklen_t len; + int err = 0; + + sockfd = socket(domain, type, 0); + if (sockfd < 0) + goto err; + + memset(&addr, 0, sizeof(addr)); + + if (domain == AF_INET) { + len = sizeof(struct sockaddr_in); + addr4 = (struct sockaddr_in *)&addr; + addr4->sin_family = domain; + addr4->sin_port = htons(port); + if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) + goto err; + } else if (domain == AF_INET6) { + len = sizeof(struct sockaddr_in6); + addr6 = (struct sockaddr_in6 *)&addr; + addr6->sin6_family = domain; + addr6->sin6_port = htons(port); + if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) + goto err; + } else { + goto err; + } + + if (bind(sockfd, (const struct sockaddr *)&addr, len) == -1) + goto err; + + goto out; +err: + err = -1; +out: + close(sockfd); + return err; +} + +static int run_test_case(int cgfd, const struct sock_test *test) +{ + int progfd = -1; + int err = 0; + + printf("Test case: %s .. ", test->descr); + progfd = load_sock_prog(test->insns, test->expected_attach_type); + if (progfd < 0) { + if (test->result == LOAD_REJECT) + goto out; + else + goto err; + } + + if (attach_sock_prog(cgfd, progfd, test->attach_type) == -1) { + if (test->result == ATTACH_REJECT) + goto out; + else + goto err; + } + + if (bind_sock(test->domain, test->type, test->ip, test->port) == -1) { + /* sys_bind() may fail for different reasons, errno has to be + * checked to confirm that BPF program rejected it. + */ + if (test->result == BIND_REJECT && errno == EPERM) + goto out; + else + goto err; + } + + + if (test->result != SUCCESS) + goto err; + + goto out; +err: + err = -1; +out: + /* Detaching w/o checking return code: best effort attempt. */ + if (progfd != -1) + bpf_prog_detach(cgfd, test->attach_type); + close(progfd); + printf("[%s]\n", err ? "FAIL" : "PASS"); + return err; +} + +static int run_tests(int cgfd) +{ + int passes = 0; + int fails = 0; + int i; + + for (i = 0; i < ARRAY_SIZE(tests); ++i) { + if (run_test_case(cgfd, &tests[i])) + ++fails; + else + ++passes; + } + printf("Summary: %d PASSED, %d FAILED\n", passes, fails); + return fails ? -1 : 0; +} + +int main(int argc, char **argv) +{ + int cgfd = -1; + int err = 0; + + if (setup_cgroup_environment()) + goto err; + + cgfd = create_and_get_cgroup(CG_PATH); + if (!cgfd) + goto err; + + if (join_cgroup(CG_PATH)) + goto err; + + if (run_tests(cgfd)) + goto err; + + goto out; +err: + err = -1; +out: + close(cgfd); + cleanup_cgroup_environment(); + return err; +} -- cgit v1.3-14-g43fede From 6aa69043d9f3f4adc5b3817ccfcac1fddfe10ded Mon Sep 17 00:00:00 2001 From: Daniel Díaz Date: Wed, 21 Feb 2018 12:07:57 -0600 Subject: selftests/intel_pstate: Fix build rule for x86 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ensure that ARCH is defined and that this only builds for x86 architectures. It is possible to build from the root of the Linux tree, which will define ARCH, or to run make from the selftests/ directory itself, which has no provision for defining ARCH, so this change is to use the current definition (if any), or to check uname -m if undefined. Signed-off-by: Daniel Díaz Signed-off-by: Shuah Khan --- tools/testing/selftests/intel_pstate/Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/intel_pstate/Makefile b/tools/testing/selftests/intel_pstate/Makefile index 5a3f7d37e912..7340fd6a9a9f 100644 --- a/tools/testing/selftests/intel_pstate/Makefile +++ b/tools/testing/selftests/intel_pstate/Makefile @@ -2,7 +2,10 @@ CFLAGS := $(CFLAGS) -Wall -D_GNU_SOURCE LDLIBS := $(LDLIBS) -lm -ifeq (,$(filter $(ARCH),x86)) +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) + +ifeq (x86,$(ARCH)) TEST_GEN_FILES := msr aperf endif -- cgit v1.3-14-g43fede From b6f534d1a642a9b6263fd52df30806171fbc331e Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Tue, 3 Apr 2018 21:24:59 +1000 Subject: selftests/powerpc: Fix copyloops build since Power4 assembler change The recent commit 15a3204d24a3 ("powerpc/64s: Set assembler machine type to POWER4") set the machine type in our ASFLAGS when building the kernel, and removed some ".machine power4" directives from various asm files. This broke the selftests build on old toolchains (that don't assume Power4), because we build the kernel source files into the selftests using different ASFLAGS. The fix is simply to add -mpower4 to the selftest ASFLAGS as well. Fixes: 15a3204d24a3 ("powerpc/64s: Set assembler machine type to POWER4") Signed-off-by: Michael Ellerman --- tools/testing/selftests/powerpc/copyloops/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/powerpc/copyloops/Makefile b/tools/testing/selftests/powerpc/copyloops/Makefile index ac4a52e19e59..eedce3366f64 100644 --- a/tools/testing/selftests/powerpc/copyloops/Makefile +++ b/tools/testing/selftests/powerpc/copyloops/Makefile @@ -5,8 +5,8 @@ CFLAGS += -I$(CURDIR) CFLAGS += -D SELFTEST CFLAGS += -maltivec -# Use our CFLAGS for the implicit .S rule -ASFLAGS = $(CFLAGS) +# Use our CFLAGS for the implicit .S rule & set the asm machine type +ASFLAGS = $(CFLAGS) -Wa,-mpower4 TEST_GEN_PROGS := copyuser_64 copyuser_power7 memcpy_64 memcpy_power7 EXTRA_SOURCES := validate.c ../harness.c -- cgit v1.3-14-g43fede From 783e9e51266ebb7f78c606a53cb0fa41bb7c31a0 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Tue, 27 Mar 2018 11:49:19 +0200 Subject: kvm: selftests: add API testing infrastructure Testsuite contributed by Google and cleaned up by myself for inclusion in Linux. Signed-off-by: Ken Hofsass Signed-off-by: Paolo Bonzini --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/kvm/Makefile | 38 + tools/testing/selftests/kvm/include/kvm_util.h | 139 ++ tools/testing/selftests/kvm/include/sparsebit.h | 75 + tools/testing/selftests/kvm/include/test_util.h | 45 + tools/testing/selftests/kvm/include/x86.h | 1043 ++++++++++ tools/testing/selftests/kvm/lib/assert.c | 87 + tools/testing/selftests/kvm/lib/kvm_util.c | 1480 ++++++++++++++ .../testing/selftests/kvm/lib/kvm_util_internal.h | 67 + tools/testing/selftests/kvm/lib/sparsebit.c | 2087 ++++++++++++++++++++ tools/testing/selftests/kvm/lib/x86.c | 697 +++++++ tools/testing/selftests/kvm/set_sregs_test.c | 54 + 12 files changed, 5813 insertions(+) create mode 100644 tools/testing/selftests/kvm/Makefile create mode 100644 tools/testing/selftests/kvm/include/kvm_util.h create mode 100644 tools/testing/selftests/kvm/include/sparsebit.h create mode 100644 tools/testing/selftests/kvm/include/test_util.h create mode 100644 tools/testing/selftests/kvm/include/x86.h create mode 100644 tools/testing/selftests/kvm/lib/assert.c create mode 100644 tools/testing/selftests/kvm/lib/kvm_util.c create mode 100644 tools/testing/selftests/kvm/lib/kvm_util_internal.h create mode 100644 tools/testing/selftests/kvm/lib/sparsebit.c create mode 100644 tools/testing/selftests/kvm/lib/x86.c create mode 100644 tools/testing/selftests/kvm/set_sregs_test.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 7442dfb73b7f..c98f1b874582 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -14,6 +14,7 @@ TARGETS += gpio TARGETS += intel_pstate TARGETS += ipc TARGETS += kcmp +TARGETS += kvm TARGETS += lib TARGETS += membarrier TARGETS += memfd diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile new file mode 100644 index 000000000000..6aade26e9ca2 --- /dev/null +++ b/tools/testing/selftests/kvm/Makefile @@ -0,0 +1,38 @@ +all: + +top_srcdir = ../../../../ +UNAME_M := $(shell uname -m) + +LIBKVM = lib/assert.c lib/kvm_util.c lib/sparsebit.c +LIBKVM_x86_64 = lib/x86.c + +TEST_GEN_PROGS_x86_64 = set_sregs_test + +TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) +LIBKVM += $(LIBKVM_$(UNAME_M)) + +INSTALL_HDR_PATH = $(top_srcdir)/usr +LINUX_HDR_PATH = $(INSTALL_HDR_PATH)/include/ +CFLAGS += -O2 -g -I$(LINUX_HDR_PATH) -Iinclude -I$( + +#include "sparsebit.h" + +/* + * Memslots can't cover the gfn starting at this gpa otherwise vCPUs can't be + * created. Only applies to VMs using EPT. + */ +#define KVM_DEFAULT_IDENTITY_MAP_ADDRESS 0xfffbc000ul + + +/* Callers of kvm_util only have an incomplete/opaque description of the + * structure kvm_util is using to maintain the state of a VM. + */ +struct kvm_vm; + +typedef uint64_t vm_paddr_t; /* Virtual Machine (Guest) physical address */ +typedef uint64_t vm_vaddr_t; /* Virtual Machine (Guest) virtual address */ + +/* Minimum allocated guest virtual and physical addresses */ +#define KVM_UTIL_MIN_VADDR 0x2000 + +#define DEFAULT_GUEST_PHY_PAGES 512 +#define DEFAULT_GUEST_STACK_VADDR_MIN 0xab6000 +#define DEFAULT_STACK_PGS 5 + +enum vm_guest_mode { + VM_MODE_FLAT48PG, +}; + +enum vm_mem_backing_src_type { + VM_MEM_SRC_ANONYMOUS, + VM_MEM_SRC_ANONYMOUS_THP, + VM_MEM_SRC_ANONYMOUS_HUGETLB, +}; + +int kvm_check_cap(long cap); + +struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm); +void kvm_vm_free(struct kvm_vm *vmp); + +int kvm_memcmp_hva_gva(void *hva, + struct kvm_vm *vm, const vm_vaddr_t gva, size_t len); + +void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); +void vcpu_dump(FILE *stream, struct kvm_vm *vm, + uint32_t vcpuid, uint8_t indent); + +void vm_create_irqchip(struct kvm_vm *vm); + +void vm_userspace_mem_region_add(struct kvm_vm *vm, + enum vm_mem_backing_src_type src_type, + uint64_t guest_paddr, uint32_t slot, uint64_t npages, + uint32_t flags); + +void vcpu_ioctl(struct kvm_vm *vm, + uint32_t vcpuid, unsigned long ioctl, void *arg); +void vm_ioctl(struct kvm_vm *vm, unsigned long ioctl, void *arg); +void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags); +void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid); +vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, + uint32_t data_memslot, uint32_t pgd_memslot); +void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa); +void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva); +vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva); +vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva); + +struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid); +void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); +int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid); +void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_mp_state *mp_state); +void vcpu_regs_get(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_regs *regs); +void vcpu_regs_set(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_regs *regs); +void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...); +void vcpu_sregs_get(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_sregs *sregs); +void vcpu_sregs_set(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_sregs *sregs); +int _vcpu_sregs_set(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_sregs *sregs); +void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_vcpu_events *events); +void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_vcpu_events *events); + +const char *exit_reason_str(unsigned int exit_reason); + +void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot); +void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, + uint32_t pgd_memslot); +vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, + vm_paddr_t paddr_min, uint32_t memslot); + +void kvm_get_supported_cpuid(struct kvm_cpuid2 *cpuid); +void vcpu_set_cpuid( + struct kvm_vm *vm, uint32_t vcpuid, struct kvm_cpuid2 *cpuid); + +struct kvm_cpuid2 *allocate_kvm_cpuid2(void); +struct kvm_cpuid_entry2 * +find_cpuid_index_entry(struct kvm_cpuid2 *cpuid, uint32_t function, + uint32_t index); + +static inline struct kvm_cpuid_entry2 * +find_cpuid_entry(struct kvm_cpuid2 *cpuid, uint32_t function) +{ + return find_cpuid_index_entry(cpuid, function, 0); +} + +struct kvm_vm *vm_create_default(uint32_t vcpuid, void *guest_code); +void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code); + +struct kvm_userspace_memory_region * +kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, + uint64_t end); + +struct kvm_dirty_log * +allocate_kvm_dirty_log(struct kvm_userspace_memory_region *region); + +int vm_create_device(struct kvm_vm *vm, struct kvm_create_device *cd); + +#endif /* SELFTEST_KVM_UTIL_H */ diff --git a/tools/testing/selftests/kvm/include/sparsebit.h b/tools/testing/selftests/kvm/include/sparsebit.h new file mode 100644 index 000000000000..54cfeb6568d3 --- /dev/null +++ b/tools/testing/selftests/kvm/include/sparsebit.h @@ -0,0 +1,75 @@ +/* + * tools/testing/selftests/kvm/include/sparsebit.h + * + * Copyright (C) 2018, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + * + * Header file that describes API to the sparsebit library. + * This library provides a memory efficient means of storing + * the settings of bits indexed via a uint64_t. Memory usage + * is reasonable, significantly less than (2^64 / 8) bytes, as + * long as bits that are mostly set or mostly cleared are close + * to each other. This library is efficient in memory usage + * even in the case where most bits are set. + */ + +#ifndef _TEST_SPARSEBIT_H_ +#define _TEST_SPARSEBIT_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct sparsebit; +typedef uint64_t sparsebit_idx_t; +typedef uint64_t sparsebit_num_t; + +struct sparsebit *sparsebit_alloc(void); +void sparsebit_free(struct sparsebit **sbitp); +void sparsebit_copy(struct sparsebit *dstp, struct sparsebit *src); + +bool sparsebit_is_set(struct sparsebit *sbit, sparsebit_idx_t idx); +bool sparsebit_is_set_num(struct sparsebit *sbit, + sparsebit_idx_t idx, sparsebit_num_t num); +bool sparsebit_is_clear(struct sparsebit *sbit, sparsebit_idx_t idx); +bool sparsebit_is_clear_num(struct sparsebit *sbit, + sparsebit_idx_t idx, sparsebit_num_t num); +sparsebit_num_t sparsebit_num_set(struct sparsebit *sbit); +bool sparsebit_any_set(struct sparsebit *sbit); +bool sparsebit_any_clear(struct sparsebit *sbit); +bool sparsebit_all_set(struct sparsebit *sbit); +bool sparsebit_all_clear(struct sparsebit *sbit); +sparsebit_idx_t sparsebit_first_set(struct sparsebit *sbit); +sparsebit_idx_t sparsebit_first_clear(struct sparsebit *sbit); +sparsebit_idx_t sparsebit_next_set(struct sparsebit *sbit, sparsebit_idx_t prev); +sparsebit_idx_t sparsebit_next_clear(struct sparsebit *sbit, sparsebit_idx_t prev); +sparsebit_idx_t sparsebit_next_set_num(struct sparsebit *sbit, + sparsebit_idx_t start, sparsebit_num_t num); +sparsebit_idx_t sparsebit_next_clear_num(struct sparsebit *sbit, + sparsebit_idx_t start, sparsebit_num_t num); + +void sparsebit_set(struct sparsebit *sbitp, sparsebit_idx_t idx); +void sparsebit_set_num(struct sparsebit *sbitp, sparsebit_idx_t start, + sparsebit_num_t num); +void sparsebit_set_all(struct sparsebit *sbitp); + +void sparsebit_clear(struct sparsebit *sbitp, sparsebit_idx_t idx); +void sparsebit_clear_num(struct sparsebit *sbitp, + sparsebit_idx_t start, sparsebit_num_t num); +void sparsebit_clear_all(struct sparsebit *sbitp); + +void sparsebit_dump(FILE *stream, struct sparsebit *sbit, + unsigned int indent); +void sparsebit_validate_internal(struct sparsebit *sbit); + +#ifdef __cplusplus +} +#endif + +#endif /* _TEST_SPARSEBIT_H_ */ diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h new file mode 100644 index 000000000000..7ab98e41324f --- /dev/null +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -0,0 +1,45 @@ +/* + * tools/testing/selftests/kvm/include/test_util.h + * + * Copyright (C) 2018, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + */ + +#ifndef TEST_UTIL_H +#define TEST_UTIL_H 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +ssize_t test_write(int fd, const void *buf, size_t count); +ssize_t test_read(int fd, void *buf, size_t count); +int test_seq_read(const char *path, char **bufp, size_t *sizep); + +void test_assert(bool exp, const char *exp_str, + const char *file, unsigned int line, const char *fmt, ...); + +#define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) + +#define TEST_ASSERT(e, fmt, ...) \ + test_assert((e), #e, __FILE__, __LINE__, fmt, ##__VA_ARGS__) + +#define ASSERT_EQ(a, b) do { \ + typeof(a) __a = (a); \ + typeof(b) __b = (b); \ + TEST_ASSERT(__a == __b, \ + "ASSERT_EQ(%s, %s) failed.\n" \ + "\t%s is %#lx\n" \ + "\t%s is %#lx", \ + #a, #b, #a, (unsigned long) __a, #b, (unsigned long) __b); \ +} while (0) + +#endif /* TEST_UTIL_H */ diff --git a/tools/testing/selftests/kvm/include/x86.h b/tools/testing/selftests/kvm/include/x86.h new file mode 100644 index 000000000000..4a5b2c4c1a0f --- /dev/null +++ b/tools/testing/selftests/kvm/include/x86.h @@ -0,0 +1,1043 @@ +/* + * tools/testing/selftests/kvm/include/x86.h + * + * Copyright (C) 2018, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + */ + +#ifndef SELFTEST_KVM_X86_H +#define SELFTEST_KVM_X86_H + +#include +#include + +#define X86_EFLAGS_FIXED (1u << 1) + +#define X86_CR4_VME (1ul << 0) +#define X86_CR4_PVI (1ul << 1) +#define X86_CR4_TSD (1ul << 2) +#define X86_CR4_DE (1ul << 3) +#define X86_CR4_PSE (1ul << 4) +#define X86_CR4_PAE (1ul << 5) +#define X86_CR4_MCE (1ul << 6) +#define X86_CR4_PGE (1ul << 7) +#define X86_CR4_PCE (1ul << 8) +#define X86_CR4_OSFXSR (1ul << 9) +#define X86_CR4_OSXMMEXCPT (1ul << 10) +#define X86_CR4_UMIP (1ul << 11) +#define X86_CR4_VMXE (1ul << 13) +#define X86_CR4_SMXE (1ul << 14) +#define X86_CR4_FSGSBASE (1ul << 16) +#define X86_CR4_PCIDE (1ul << 17) +#define X86_CR4_OSXSAVE (1ul << 18) +#define X86_CR4_SMEP (1ul << 20) +#define X86_CR4_SMAP (1ul << 21) +#define X86_CR4_PKE (1ul << 22) + +/* The enum values match the intruction encoding of each register */ +enum x86_register { + RAX = 0, + RCX, + RDX, + RBX, + RSP, + RBP, + RSI, + RDI, + R8, + R9, + R10, + R11, + R12, + R13, + R14, + R15, +}; + +struct desc64 { + uint16_t limit0; + uint16_t base0; + unsigned base1:8, type:5, dpl:2, p:1; + unsigned limit1:4, zero0:3, g:1, base2:8; + uint32_t base3; + uint32_t zero1; +} __attribute__((packed)); + +struct desc_ptr { + uint16_t size; + uint64_t address; +} __attribute__((packed)); + +static inline uint64_t get_desc64_base(const struct desc64 *desc) +{ + return ((uint64_t)desc->base3 << 32) | + (desc->base0 | ((desc->base1) << 16) | ((desc->base2) << 24)); +} + +static inline uint64_t rdtsc(void) +{ + uint32_t eax, edx; + + /* + * The lfence is to wait (on Intel CPUs) until all previous + * instructions have been executed. + */ + __asm__ __volatile__("lfence; rdtsc" : "=a"(eax), "=d"(edx)); + return ((uint64_t)edx) << 32 | eax; +} + +static inline uint64_t rdtscp(uint32_t *aux) +{ + uint32_t eax, edx; + + __asm__ __volatile__("rdtscp" : "=a"(eax), "=d"(edx), "=c"(*aux)); + return ((uint64_t)edx) << 32 | eax; +} + +static inline uint64_t rdmsr(uint32_t msr) +{ + uint32_t a, d; + + __asm__ __volatile__("rdmsr" : "=a"(a), "=d"(d) : "c"(msr) : "memory"); + + return a | ((uint64_t) d << 32); +} + +static inline void wrmsr(uint32_t msr, uint64_t value) +{ + uint32_t a = value; + uint32_t d = value >> 32; + + __asm__ __volatile__("wrmsr" :: "a"(a), "d"(d), "c"(msr) : "memory"); +} + + +static inline uint16_t inw(uint16_t port) +{ + uint16_t tmp; + + __asm__ __volatile__("in %%dx, %%ax" + : /* output */ "=a" (tmp) + : /* input */ "d" (port)); + + return tmp; +} + +static inline uint16_t get_es(void) +{ + uint16_t es; + + __asm__ __volatile__("mov %%es, %[es]" + : /* output */ [es]"=rm"(es)); + return es; +} + +static inline uint16_t get_cs(void) +{ + uint16_t cs; + + __asm__ __volatile__("mov %%cs, %[cs]" + : /* output */ [cs]"=rm"(cs)); + return cs; +} + +static inline uint16_t get_ss(void) +{ + uint16_t ss; + + __asm__ __volatile__("mov %%ss, %[ss]" + : /* output */ [ss]"=rm"(ss)); + return ss; +} + +static inline uint16_t get_ds(void) +{ + uint16_t ds; + + __asm__ __volatile__("mov %%ds, %[ds]" + : /* output */ [ds]"=rm"(ds)); + return ds; +} + +static inline uint16_t get_fs(void) +{ + uint16_t fs; + + __asm__ __volatile__("mov %%fs, %[fs]" + : /* output */ [fs]"=rm"(fs)); + return fs; +} + +static inline uint16_t get_gs(void) +{ + uint16_t gs; + + __asm__ __volatile__("mov %%gs, %[gs]" + : /* output */ [gs]"=rm"(gs)); + return gs; +} + +static inline uint16_t get_tr(void) +{ + uint16_t tr; + + __asm__ __volatile__("str %[tr]" + : /* output */ [tr]"=rm"(tr)); + return tr; +} + +static inline uint64_t get_cr0(void) +{ + uint64_t cr0; + + __asm__ __volatile__("mov %%cr0, %[cr0]" + : /* output */ [cr0]"=r"(cr0)); + return cr0; +} + +static inline uint64_t get_cr3(void) +{ + uint64_t cr3; + + __asm__ __volatile__("mov %%cr3, %[cr3]" + : /* output */ [cr3]"=r"(cr3)); + return cr3; +} + +static inline uint64_t get_cr4(void) +{ + uint64_t cr4; + + __asm__ __volatile__("mov %%cr4, %[cr4]" + : /* output */ [cr4]"=r"(cr4)); + return cr4; +} + +static inline void set_cr4(uint64_t val) +{ + __asm__ __volatile__("mov %0, %%cr4" : : "r" (val) : "memory"); +} + +static inline uint64_t get_gdt_base(void) +{ + struct desc_ptr gdt; + __asm__ __volatile__("sgdt %[gdt]" + : /* output */ [gdt]"=m"(gdt)); + return gdt.address; +} + +static inline uint64_t get_idt_base(void) +{ + struct desc_ptr idt; + __asm__ __volatile__("sidt %[idt]" + : /* output */ [idt]"=m"(idt)); + return idt.address; +} + +#define SET_XMM(__var, __xmm) \ + asm volatile("movq %0, %%"#__xmm : : "r"(__var) : #__xmm) + +static inline void set_xmm(int n, unsigned long val) +{ + switch (n) { + case 0: + SET_XMM(val, xmm0); + break; + case 1: + SET_XMM(val, xmm1); + break; + case 2: + SET_XMM(val, xmm2); + break; + case 3: + SET_XMM(val, xmm3); + break; + case 4: + SET_XMM(val, xmm4); + break; + case 5: + SET_XMM(val, xmm5); + break; + case 6: + SET_XMM(val, xmm6); + break; + case 7: + SET_XMM(val, xmm7); + break; + } +} + +typedef unsigned long v1di __attribute__ ((vector_size (8))); +static inline unsigned long get_xmm(int n) +{ + assert(n >= 0 && n <= 7); + + register v1di xmm0 __asm__("%xmm0"); + register v1di xmm1 __asm__("%xmm1"); + register v1di xmm2 __asm__("%xmm2"); + register v1di xmm3 __asm__("%xmm3"); + register v1di xmm4 __asm__("%xmm4"); + register v1di xmm5 __asm__("%xmm5"); + register v1di xmm6 __asm__("%xmm6"); + register v1di xmm7 __asm__("%xmm7"); + switch (n) { + case 0: + return (unsigned long)xmm0; + case 1: + return (unsigned long)xmm1; + case 2: + return (unsigned long)xmm2; + case 3: + return (unsigned long)xmm3; + case 4: + return (unsigned long)xmm4; + case 5: + return (unsigned long)xmm5; + case 6: + return (unsigned long)xmm6; + case 7: + return (unsigned long)xmm7; + } + return 0; +} + +/* + * Basic CPU control in CR0 + */ +#define X86_CR0_PE (1UL<<0) /* Protection Enable */ +#define X86_CR0_MP (1UL<<1) /* Monitor Coprocessor */ +#define X86_CR0_EM (1UL<<2) /* Emulation */ +#define X86_CR0_TS (1UL<<3) /* Task Switched */ +#define X86_CR0_ET (1UL<<4) /* Extension Type */ +#define X86_CR0_NE (1UL<<5) /* Numeric Error */ +#define X86_CR0_WP (1UL<<16) /* Write Protect */ +#define X86_CR0_AM (1UL<<18) /* Alignment Mask */ +#define X86_CR0_NW (1UL<<29) /* Not Write-through */ +#define X86_CR0_CD (1UL<<30) /* Cache Disable */ +#define X86_CR0_PG (1UL<<31) /* Paging */ + +/* + * CPU model specific register (MSR) numbers. + */ + +/* x86-64 specific MSRs */ +#define MSR_EFER 0xc0000080 /* extended feature register */ +#define MSR_STAR 0xc0000081 /* legacy mode SYSCALL target */ +#define MSR_LSTAR 0xc0000082 /* long mode SYSCALL target */ +#define MSR_CSTAR 0xc0000083 /* compat mode SYSCALL target */ +#define MSR_SYSCALL_MASK 0xc0000084 /* EFLAGS mask for syscall */ +#define MSR_FS_BASE 0xc0000100 /* 64bit FS base */ +#define MSR_GS_BASE 0xc0000101 /* 64bit GS base */ +#define MSR_KERNEL_GS_BASE 0xc0000102 /* SwapGS GS shadow */ +#define MSR_TSC_AUX 0xc0000103 /* Auxiliary TSC */ + +/* EFER bits: */ +#define EFER_SCE (1<<0) /* SYSCALL/SYSRET */ +#define EFER_LME (1<<8) /* Long mode enable */ +#define EFER_LMA (1<<10) /* Long mode active (read-only) */ +#define EFER_NX (1<<11) /* No execute enable */ +#define EFER_SVME (1<<12) /* Enable virtualization */ +#define EFER_LMSLE (1<<13) /* Long Mode Segment Limit Enable */ +#define EFER_FFXSR (1<<14) /* Enable Fast FXSAVE/FXRSTOR */ + +/* Intel MSRs. Some also available on other CPUs */ + +#define MSR_PPIN_CTL 0x0000004e +#define MSR_PPIN 0x0000004f + +#define MSR_IA32_PERFCTR0 0x000000c1 +#define MSR_IA32_PERFCTR1 0x000000c2 +#define MSR_FSB_FREQ 0x000000cd +#define MSR_PLATFORM_INFO 0x000000ce +#define MSR_PLATFORM_INFO_CPUID_FAULT_BIT 31 +#define MSR_PLATFORM_INFO_CPUID_FAULT BIT_ULL(MSR_PLATFORM_INFO_CPUID_FAULT_BIT) + +#define MSR_PKG_CST_CONFIG_CONTROL 0x000000e2 +#define NHM_C3_AUTO_DEMOTE (1UL << 25) +#define NHM_C1_AUTO_DEMOTE (1UL << 26) +#define ATM_LNC_C6_AUTO_DEMOTE (1UL << 25) +#define SNB_C1_AUTO_UNDEMOTE (1UL << 27) +#define SNB_C3_AUTO_UNDEMOTE (1UL << 28) + +#define MSR_MTRRcap 0x000000fe +#define MSR_IA32_BBL_CR_CTL 0x00000119 +#define MSR_IA32_BBL_CR_CTL3 0x0000011e + +#define MSR_IA32_SYSENTER_CS 0x00000174 +#define MSR_IA32_SYSENTER_ESP 0x00000175 +#define MSR_IA32_SYSENTER_EIP 0x00000176 + +#define MSR_IA32_MCG_CAP 0x00000179 +#define MSR_IA32_MCG_STATUS 0x0000017a +#define MSR_IA32_MCG_CTL 0x0000017b +#define MSR_IA32_MCG_EXT_CTL 0x000004d0 + +#define MSR_OFFCORE_RSP_0 0x000001a6 +#define MSR_OFFCORE_RSP_1 0x000001a7 +#define MSR_TURBO_RATIO_LIMIT 0x000001ad +#define MSR_TURBO_RATIO_LIMIT1 0x000001ae +#define MSR_TURBO_RATIO_LIMIT2 0x000001af + +#define MSR_LBR_SELECT 0x000001c8 +#define MSR_LBR_TOS 0x000001c9 +#define MSR_LBR_NHM_FROM 0x00000680 +#define MSR_LBR_NHM_TO 0x000006c0 +#define MSR_LBR_CORE_FROM 0x00000040 +#define MSR_LBR_CORE_TO 0x00000060 + +#define MSR_LBR_INFO_0 0x00000dc0 /* ... 0xddf for _31 */ +#define LBR_INFO_MISPRED BIT_ULL(63) +#define LBR_INFO_IN_TX BIT_ULL(62) +#define LBR_INFO_ABORT BIT_ULL(61) +#define LBR_INFO_CYCLES 0xffff + +#define MSR_IA32_PEBS_ENABLE 0x000003f1 +#define MSR_IA32_DS_AREA 0x00000600 +#define MSR_IA32_PERF_CAPABILITIES 0x00000345 +#define MSR_PEBS_LD_LAT_THRESHOLD 0x000003f6 + +#define MSR_IA32_RTIT_CTL 0x00000570 +#define MSR_IA32_RTIT_STATUS 0x00000571 +#define MSR_IA32_RTIT_ADDR0_A 0x00000580 +#define MSR_IA32_RTIT_ADDR0_B 0x00000581 +#define MSR_IA32_RTIT_ADDR1_A 0x00000582 +#define MSR_IA32_RTIT_ADDR1_B 0x00000583 +#define MSR_IA32_RTIT_ADDR2_A 0x00000584 +#define MSR_IA32_RTIT_ADDR2_B 0x00000585 +#define MSR_IA32_RTIT_ADDR3_A 0x00000586 +#define MSR_IA32_RTIT_ADDR3_B 0x00000587 +#define MSR_IA32_RTIT_CR3_MATCH 0x00000572 +#define MSR_IA32_RTIT_OUTPUT_BASE 0x00000560 +#define MSR_IA32_RTIT_OUTPUT_MASK 0x00000561 + +#define MSR_MTRRfix64K_00000 0x00000250 +#define MSR_MTRRfix16K_80000 0x00000258 +#define MSR_MTRRfix16K_A0000 0x00000259 +#define MSR_MTRRfix4K_C0000 0x00000268 +#define MSR_MTRRfix4K_C8000 0x00000269 +#define MSR_MTRRfix4K_D0000 0x0000026a +#define MSR_MTRRfix4K_D8000 0x0000026b +#define MSR_MTRRfix4K_E0000 0x0000026c +#define MSR_MTRRfix4K_E8000 0x0000026d +#define MSR_MTRRfix4K_F0000 0x0000026e +#define MSR_MTRRfix4K_F8000 0x0000026f +#define MSR_MTRRdefType 0x000002ff + +#define MSR_IA32_CR_PAT 0x00000277 + +#define MSR_IA32_DEBUGCTLMSR 0x000001d9 +#define MSR_IA32_LASTBRANCHFROMIP 0x000001db +#define MSR_IA32_LASTBRANCHTOIP 0x000001dc +#define MSR_IA32_LASTINTFROMIP 0x000001dd +#define MSR_IA32_LASTINTTOIP 0x000001de + +/* DEBUGCTLMSR bits (others vary by model): */ +#define DEBUGCTLMSR_LBR (1UL << 0) /* last branch recording */ +#define DEBUGCTLMSR_BTF_SHIFT 1 +#define DEBUGCTLMSR_BTF (1UL << 1) /* single-step on branches */ +#define DEBUGCTLMSR_TR (1UL << 6) +#define DEBUGCTLMSR_BTS (1UL << 7) +#define DEBUGCTLMSR_BTINT (1UL << 8) +#define DEBUGCTLMSR_BTS_OFF_OS (1UL << 9) +#define DEBUGCTLMSR_BTS_OFF_USR (1UL << 10) +#define DEBUGCTLMSR_FREEZE_LBRS_ON_PMI (1UL << 11) +#define DEBUGCTLMSR_FREEZE_IN_SMM_BIT 14 +#define DEBUGCTLMSR_FREEZE_IN_SMM (1UL << DEBUGCTLMSR_FREEZE_IN_SMM_BIT) + +#define MSR_PEBS_FRONTEND 0x000003f7 + +#define MSR_IA32_POWER_CTL 0x000001fc + +#define MSR_IA32_MC0_CTL 0x00000400 +#define MSR_IA32_MC0_STATUS 0x00000401 +#define MSR_IA32_MC0_ADDR 0x00000402 +#define MSR_IA32_MC0_MISC 0x00000403 + +/* C-state Residency Counters */ +#define MSR_PKG_C3_RESIDENCY 0x000003f8 +#define MSR_PKG_C6_RESIDENCY 0x000003f9 +#define MSR_ATOM_PKG_C6_RESIDENCY 0x000003fa +#define MSR_PKG_C7_RESIDENCY 0x000003fa +#define MSR_CORE_C3_RESIDENCY 0x000003fc +#define MSR_CORE_C6_RESIDENCY 0x000003fd +#define MSR_CORE_C7_RESIDENCY 0x000003fe +#define MSR_KNL_CORE_C6_RESIDENCY 0x000003ff +#define MSR_PKG_C2_RESIDENCY 0x0000060d +#define MSR_PKG_C8_RESIDENCY 0x00000630 +#define MSR_PKG_C9_RESIDENCY 0x00000631 +#define MSR_PKG_C10_RESIDENCY 0x00000632 + +/* Interrupt Response Limit */ +#define MSR_PKGC3_IRTL 0x0000060a +#define MSR_PKGC6_IRTL 0x0000060b +#define MSR_PKGC7_IRTL 0x0000060c +#define MSR_PKGC8_IRTL 0x00000633 +#define MSR_PKGC9_IRTL 0x00000634 +#define MSR_PKGC10_IRTL 0x00000635 + +/* Run Time Average Power Limiting (RAPL) Interface */ + +#define MSR_RAPL_POWER_UNIT 0x00000606 + +#define MSR_PKG_POWER_LIMIT 0x00000610 +#define MSR_PKG_ENERGY_STATUS 0x00000611 +#define MSR_PKG_PERF_STATUS 0x00000613 +#define MSR_PKG_POWER_INFO 0x00000614 + +#define MSR_DRAM_POWER_LIMIT 0x00000618 +#define MSR_DRAM_ENERGY_STATUS 0x00000619 +#define MSR_DRAM_PERF_STATUS 0x0000061b +#define MSR_DRAM_POWER_INFO 0x0000061c + +#define MSR_PP0_POWER_LIMIT 0x00000638 +#define MSR_PP0_ENERGY_STATUS 0x00000639 +#define MSR_PP0_POLICY 0x0000063a +#define MSR_PP0_PERF_STATUS 0x0000063b + +#define MSR_PP1_POWER_LIMIT 0x00000640 +#define MSR_PP1_ENERGY_STATUS 0x00000641 +#define MSR_PP1_POLICY 0x00000642 + +/* Config TDP MSRs */ +#define MSR_CONFIG_TDP_NOMINAL 0x00000648 +#define MSR_CONFIG_TDP_LEVEL_1 0x00000649 +#define MSR_CONFIG_TDP_LEVEL_2 0x0000064A +#define MSR_CONFIG_TDP_CONTROL 0x0000064B +#define MSR_TURBO_ACTIVATION_RATIO 0x0000064C + +#define MSR_PLATFORM_ENERGY_STATUS 0x0000064D + +#define MSR_PKG_WEIGHTED_CORE_C0_RES 0x00000658 +#define MSR_PKG_ANY_CORE_C0_RES 0x00000659 +#define MSR_PKG_ANY_GFXE_C0_RES 0x0000065A +#define MSR_PKG_BOTH_CORE_GFXE_C0_RES 0x0000065B + +#define MSR_CORE_C1_RES 0x00000660 +#define MSR_MODULE_C6_RES_MS 0x00000664 + +#define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668 +#define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669 + +#define MSR_ATOM_CORE_RATIOS 0x0000066a +#define MSR_ATOM_CORE_VIDS 0x0000066b +#define MSR_ATOM_CORE_TURBO_RATIOS 0x0000066c +#define MSR_ATOM_CORE_TURBO_VIDS 0x0000066d + + +#define MSR_CORE_PERF_LIMIT_REASONS 0x00000690 +#define MSR_GFX_PERF_LIMIT_REASONS 0x000006B0 +#define MSR_RING_PERF_LIMIT_REASONS 0x000006B1 + +/* Hardware P state interface */ +#define MSR_PPERF 0x0000064e +#define MSR_PERF_LIMIT_REASONS 0x0000064f +#define MSR_PM_ENABLE 0x00000770 +#define MSR_HWP_CAPABILITIES 0x00000771 +#define MSR_HWP_REQUEST_PKG 0x00000772 +#define MSR_HWP_INTERRUPT 0x00000773 +#define MSR_HWP_REQUEST 0x00000774 +#define MSR_HWP_STATUS 0x00000777 + +/* CPUID.6.EAX */ +#define HWP_BASE_BIT (1<<7) +#define HWP_NOTIFICATIONS_BIT (1<<8) +#define HWP_ACTIVITY_WINDOW_BIT (1<<9) +#define HWP_ENERGY_PERF_PREFERENCE_BIT (1<<10) +#define HWP_PACKAGE_LEVEL_REQUEST_BIT (1<<11) + +/* IA32_HWP_CAPABILITIES */ +#define HWP_HIGHEST_PERF(x) (((x) >> 0) & 0xff) +#define HWP_GUARANTEED_PERF(x) (((x) >> 8) & 0xff) +#define HWP_MOSTEFFICIENT_PERF(x) (((x) >> 16) & 0xff) +#define HWP_LOWEST_PERF(x) (((x) >> 24) & 0xff) + +/* IA32_HWP_REQUEST */ +#define HWP_MIN_PERF(x) (x & 0xff) +#define HWP_MAX_PERF(x) ((x & 0xff) << 8) +#define HWP_DESIRED_PERF(x) ((x & 0xff) << 16) +#define HWP_ENERGY_PERF_PREFERENCE(x) (((unsigned long long) x & 0xff) << 24) +#define HWP_EPP_PERFORMANCE 0x00 +#define HWP_EPP_BALANCE_PERFORMANCE 0x80 +#define HWP_EPP_BALANCE_POWERSAVE 0xC0 +#define HWP_EPP_POWERSAVE 0xFF +#define HWP_ACTIVITY_WINDOW(x) ((unsigned long long)(x & 0xff3) << 32) +#define HWP_PACKAGE_CONTROL(x) ((unsigned long long)(x & 0x1) << 42) + +/* IA32_HWP_STATUS */ +#define HWP_GUARANTEED_CHANGE(x) (x & 0x1) +#define HWP_EXCURSION_TO_MINIMUM(x) (x & 0x4) + +/* IA32_HWP_INTERRUPT */ +#define HWP_CHANGE_TO_GUARANTEED_INT(x) (x & 0x1) +#define HWP_EXCURSION_TO_MINIMUM_INT(x) (x & 0x2) + +#define MSR_AMD64_MC0_MASK 0xc0010044 + +#define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x)) +#define MSR_IA32_MCx_STATUS(x) (MSR_IA32_MC0_STATUS + 4*(x)) +#define MSR_IA32_MCx_ADDR(x) (MSR_IA32_MC0_ADDR + 4*(x)) +#define MSR_IA32_MCx_MISC(x) (MSR_IA32_MC0_MISC + 4*(x)) + +#define MSR_AMD64_MCx_MASK(x) (MSR_AMD64_MC0_MASK + (x)) + +/* These are consecutive and not in the normal 4er MCE bank block */ +#define MSR_IA32_MC0_CTL2 0x00000280 +#define MSR_IA32_MCx_CTL2(x) (MSR_IA32_MC0_CTL2 + (x)) + +#define MSR_P6_PERFCTR0 0x000000c1 +#define MSR_P6_PERFCTR1 0x000000c2 +#define MSR_P6_EVNTSEL0 0x00000186 +#define MSR_P6_EVNTSEL1 0x00000187 + +#define MSR_KNC_PERFCTR0 0x00000020 +#define MSR_KNC_PERFCTR1 0x00000021 +#define MSR_KNC_EVNTSEL0 0x00000028 +#define MSR_KNC_EVNTSEL1 0x00000029 + +/* Alternative perfctr range with full access. */ +#define MSR_IA32_PMC0 0x000004c1 + +/* AMD64 MSRs. Not complete. See the architecture manual for a more + complete list. */ + +#define MSR_AMD64_PATCH_LEVEL 0x0000008b +#define MSR_AMD64_TSC_RATIO 0xc0000104 +#define MSR_AMD64_NB_CFG 0xc001001f +#define MSR_AMD64_PATCH_LOADER 0xc0010020 +#define MSR_AMD64_OSVW_ID_LENGTH 0xc0010140 +#define MSR_AMD64_OSVW_STATUS 0xc0010141 +#define MSR_AMD64_LS_CFG 0xc0011020 +#define MSR_AMD64_DC_CFG 0xc0011022 +#define MSR_AMD64_BU_CFG2 0xc001102a +#define MSR_AMD64_IBSFETCHCTL 0xc0011030 +#define MSR_AMD64_IBSFETCHLINAD 0xc0011031 +#define MSR_AMD64_IBSFETCHPHYSAD 0xc0011032 +#define MSR_AMD64_IBSFETCH_REG_COUNT 3 +#define MSR_AMD64_IBSFETCH_REG_MASK ((1UL< +#include + +/* Dumps the current stack trace to stderr. */ +static void __attribute__((noinline)) test_dump_stack(void); +static void test_dump_stack(void) +{ + /* + * Build and run this command: + * + * addr2line -s -e /proc/$PPID/exe -fpai {backtrace addresses} | \ + * grep -v test_dump_stack | cat -n 1>&2 + * + * Note that the spacing is different and there's no newline. + */ + size_t i; + size_t n = 20; + void *stack[n]; + const char *addr2line = "addr2line -s -e /proc/$PPID/exe -fpai"; + const char *pipeline = "|cat -n 1>&2"; + char cmd[strlen(addr2line) + strlen(pipeline) + + /* N bytes per addr * 2 digits per byte + 1 space per addr: */ + n * (((sizeof(void *)) * 2) + 1) + + /* Null terminator: */ + 1]; + char *c; + + n = backtrace(stack, n); + c = &cmd[0]; + c += sprintf(c, "%s", addr2line); + /* + * Skip the first 3 frames: backtrace, test_dump_stack, and + * test_assert. We hope that backtrace isn't inlined and the other two + * we've declared noinline. + */ + for (i = 2; i < n; i++) + c += sprintf(c, " %lx", ((unsigned long) stack[i]) - 1); + c += sprintf(c, "%s", pipeline); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + system(cmd); +#pragma GCC diagnostic pop +} + +static pid_t gettid(void) +{ + return syscall(SYS_gettid); +} + +void __attribute__((noinline)) +test_assert(bool exp, const char *exp_str, + const char *file, unsigned int line, const char *fmt, ...) +{ + va_list ap; + + if (!(exp)) { + va_start(ap, fmt); + + fprintf(stderr, "==== Test Assertion Failure ====\n" + " %s:%u: %s\n" + " pid=%d tid=%d\n", + file, line, exp_str, getpid(), gettid()); + test_dump_stack(); + if (fmt) { + fputs(" ", stderr); + vfprintf(stderr, fmt, ap); + fputs("\n", stderr); + } + va_end(ap); + + exit(254); + } + + return; +} diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c new file mode 100644 index 000000000000..7ca1bb40c498 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -0,0 +1,1480 @@ +/* + * tools/testing/selftests/kvm/lib/kvm_util.c + * + * Copyright (C) 2018, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#include "test_util.h" +#include "kvm_util.h" +#include "kvm_util_internal.h" + +#include +#include +#include +#include + +#define KVM_DEV_PATH "/dev/kvm" + +#define KVM_UTIL_PGS_PER_HUGEPG 512 +#define KVM_UTIL_MIN_PADDR 0x2000 + +/* Aligns x up to the next multiple of size. Size must be a power of 2. */ +static void *align(void *x, size_t size) +{ + size_t mask = size - 1; + TEST_ASSERT(size != 0 && !(size & (size - 1)), + "size not a power of 2: %lu", size); + return (void *) (((size_t) x + mask) & ~mask); +} + +/* Capability + * + * Input Args: + * cap - Capability + * + * Output Args: None + * + * Return: + * On success, the Value corresponding to the capability (KVM_CAP_*) + * specified by the value of cap. On failure a TEST_ASSERT failure + * is produced. + * + * Looks up and returns the value corresponding to the capability + * (KVM_CAP_*) given by cap. + */ +int kvm_check_cap(long cap) +{ + int ret; + int kvm_fd; + + kvm_fd = open(KVM_DEV_PATH, O_RDONLY); + TEST_ASSERT(kvm_fd >= 0, "open %s failed, rc: %i errno: %i", + KVM_DEV_PATH, kvm_fd, errno); + + ret = ioctl(kvm_fd, KVM_CHECK_EXTENSION, cap); + TEST_ASSERT(ret != -1, "KVM_CHECK_EXTENSION IOCTL failed,\n" + " rc: %i errno: %i", ret, errno); + + close(kvm_fd); + + return ret; +} + +/* VM Create + * + * Input Args: + * mode - VM Mode (e.g. VM_MODE_FLAT48PG) + * phy_pages - Physical memory pages + * perm - permission + * + * Output Args: None + * + * Return: + * Pointer to opaque structure that describes the created VM. + * + * Creates a VM with the mode specified by mode (e.g. VM_MODE_FLAT48PG). + * When phy_pages is non-zero, a memory region of phy_pages physical pages + * is created and mapped starting at guest physical address 0. The file + * descriptor to control the created VM is created with the permissions + * given by perm (e.g. O_RDWR). + */ +struct kvm_vm *vm_create(enum vm_guest_mode mode, uint64_t phy_pages, int perm) +{ + struct kvm_vm *vm; + int kvm_fd; + + /* Allocate memory. */ + vm = calloc(1, sizeof(*vm)); + TEST_ASSERT(vm != NULL, "Insufficent Memory"); + + vm->mode = mode; + kvm_fd = open(KVM_DEV_PATH, perm); + TEST_ASSERT(kvm_fd >= 0, "open %s failed, rc: %i errno: %i", + KVM_DEV_PATH, kvm_fd, errno); + + /* Create VM. */ + vm->fd = ioctl(kvm_fd, KVM_CREATE_VM, NULL); + TEST_ASSERT(vm->fd >= 0, "KVM_CREATE_VM ioctl failed, " + "rc: %i errno: %i", vm->fd, errno); + + close(kvm_fd); + + /* Setup mode specific traits. */ + switch (vm->mode) { + case VM_MODE_FLAT48PG: + vm->page_size = 0x1000; + vm->page_shift = 12; + + /* Limit to 48-bit canonical virtual addresses. */ + vm->vpages_valid = sparsebit_alloc(); + sparsebit_set_num(vm->vpages_valid, + 0, (1ULL << (48 - 1)) >> vm->page_shift); + sparsebit_set_num(vm->vpages_valid, + (~((1ULL << (48 - 1)) - 1)) >> vm->page_shift, + (1ULL << (48 - 1)) >> vm->page_shift); + + /* Limit physical addresses to 52-bits. */ + vm->max_gfn = ((1ULL << 52) >> vm->page_shift) - 1; + break; + + default: + TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", mode); + } + + /* Allocate and setup memory for guest. */ + vm->vpages_mapped = sparsebit_alloc(); + if (phy_pages != 0) + vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, + 0, 0, phy_pages, 0); + + return vm; +} + +/* Userspace Memory Region Find + * + * Input Args: + * vm - Virtual Machine + * start - Starting VM physical address + * end - Ending VM physical address, inclusive. + * + * Output Args: None + * + * Return: + * Pointer to overlapping region, NULL if no such region. + * + * Searches for a region with any physical memory that overlaps with + * any portion of the guest physical addresses from start to end + * inclusive. If multiple overlapping regions exist, a pointer to any + * of the regions is returned. Null is returned only when no overlapping + * region exists. + */ +static struct userspace_mem_region *userspace_mem_region_find( + struct kvm_vm *vm, uint64_t start, uint64_t end) +{ + struct userspace_mem_region *region; + + for (region = vm->userspace_mem_region_head; region; + region = region->next) { + uint64_t existing_start = region->region.guest_phys_addr; + uint64_t existing_end = region->region.guest_phys_addr + + region->region.memory_size - 1; + if (start <= existing_end && end >= existing_start) + return region; + } + + return NULL; +} + +/* KVM Userspace Memory Region Find + * + * Input Args: + * vm - Virtual Machine + * start - Starting VM physical address + * end - Ending VM physical address, inclusive. + * + * Output Args: None + * + * Return: + * Pointer to overlapping region, NULL if no such region. + * + * Public interface to userspace_mem_region_find. Allows tests to look up + * the memslot datastructure for a given range of guest physical memory. + */ +struct kvm_userspace_memory_region * +kvm_userspace_memory_region_find(struct kvm_vm *vm, uint64_t start, + uint64_t end) +{ + struct userspace_mem_region *region; + + region = userspace_mem_region_find(vm, start, end); + if (!region) + return NULL; + + return ®ion->region; +} + +/* VCPU Find + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * + * Output Args: None + * + * Return: + * Pointer to VCPU structure + * + * Locates a vcpu structure that describes the VCPU specified by vcpuid and + * returns a pointer to it. Returns NULL if the VM doesn't contain a VCPU + * for the specified vcpuid. + */ +struct vcpu *vcpu_find(struct kvm_vm *vm, + uint32_t vcpuid) +{ + struct vcpu *vcpup; + + for (vcpup = vm->vcpu_head; vcpup; vcpup = vcpup->next) { + if (vcpup->id == vcpuid) + return vcpup; + } + + return NULL; +} + +/* VM VCPU Remove + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * + * Output Args: None + * + * Return: None, TEST_ASSERT failures for all error conditions + * + * Within the VM specified by vm, removes the VCPU given by vcpuid. + */ +static void vm_vcpu_rm(struct kvm_vm *vm, uint32_t vcpuid) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + + int ret = close(vcpu->fd); + TEST_ASSERT(ret == 0, "Close of VCPU fd failed, rc: %i " + "errno: %i", ret, errno); + + if (vcpu->next) + vcpu->next->prev = vcpu->prev; + if (vcpu->prev) + vcpu->prev->next = vcpu->next; + else + vm->vcpu_head = vcpu->next; + free(vcpu); +} + + +/* Destroys and frees the VM pointed to by vmp. + */ +void kvm_vm_free(struct kvm_vm *vmp) +{ + int ret; + + if (vmp == NULL) + return; + + /* Free userspace_mem_regions. */ + while (vmp->userspace_mem_region_head) { + struct userspace_mem_region *region + = vmp->userspace_mem_region_head; + + region->region.memory_size = 0; + ret = ioctl(vmp->fd, KVM_SET_USER_MEMORY_REGION, + ®ion->region); + TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed, " + "rc: %i errno: %i", ret, errno); + + vmp->userspace_mem_region_head = region->next; + sparsebit_free(®ion->unused_phy_pages); + ret = munmap(region->mmap_start, region->mmap_size); + TEST_ASSERT(ret == 0, "munmap failed, rc: %i errno: %i", + ret, errno); + + free(region); + } + + /* Free VCPUs. */ + while (vmp->vcpu_head) + vm_vcpu_rm(vmp, vmp->vcpu_head->id); + + /* Free sparsebit arrays. */ + sparsebit_free(&vmp->vpages_valid); + sparsebit_free(&vmp->vpages_mapped); + + /* Close file descriptor for the VM. */ + ret = close(vmp->fd); + TEST_ASSERT(ret == 0, "Close of vm fd failed,\n" + " vmp->fd: %i rc: %i errno: %i", vmp->fd, ret, errno); + + /* Free the structure describing the VM. */ + free(vmp); +} + +/* Memory Compare, host virtual to guest virtual + * + * Input Args: + * hva - Starting host virtual address + * vm - Virtual Machine + * gva - Starting guest virtual address + * len - number of bytes to compare + * + * Output Args: None + * + * Input/Output Args: None + * + * Return: + * Returns 0 if the bytes starting at hva for a length of len + * are equal the guest virtual bytes starting at gva. Returns + * a value < 0, if bytes at hva are less than those at gva. + * Otherwise a value > 0 is returned. + * + * Compares the bytes starting at the host virtual address hva, for + * a length of len, to the guest bytes starting at the guest virtual + * address given by gva. + */ +int kvm_memcmp_hva_gva(void *hva, + struct kvm_vm *vm, vm_vaddr_t gva, size_t len) +{ + size_t amt; + + /* Compare a batch of bytes until either a match is found + * or all the bytes have been compared. + */ + for (uintptr_t offset = 0; offset < len; offset += amt) { + uintptr_t ptr1 = (uintptr_t)hva + offset; + + /* Determine host address for guest virtual address + * at offset. + */ + uintptr_t ptr2 = (uintptr_t)addr_gva2hva(vm, gva + offset); + + /* Determine amount to compare on this pass. + * Don't allow the comparsion to cross a page boundary. + */ + amt = len - offset; + if ((ptr1 >> vm->page_shift) != ((ptr1 + amt) >> vm->page_shift)) + amt = vm->page_size - (ptr1 % vm->page_size); + if ((ptr2 >> vm->page_shift) != ((ptr2 + amt) >> vm->page_shift)) + amt = vm->page_size - (ptr2 % vm->page_size); + + assert((ptr1 >> vm->page_shift) == ((ptr1 + amt - 1) >> vm->page_shift)); + assert((ptr2 >> vm->page_shift) == ((ptr2 + amt - 1) >> vm->page_shift)); + + /* Perform the comparison. If there is a difference + * return that result to the caller, otherwise need + * to continue on looking for a mismatch. + */ + int ret = memcmp((void *)ptr1, (void *)ptr2, amt); + if (ret != 0) + return ret; + } + + /* No mismatch found. Let the caller know the two memory + * areas are equal. + */ + return 0; +} + +/* Allocate an instance of struct kvm_cpuid2 + * + * Input Args: None + * + * Output Args: None + * + * Return: A pointer to the allocated struct. The caller is responsible + * for freeing this struct. + * + * Since kvm_cpuid2 uses a 0-length array to allow a the size of the + * array to be decided at allocation time, allocation is slightly + * complicated. This function uses a reasonable default length for + * the array and performs the appropriate allocation. + */ +struct kvm_cpuid2 *allocate_kvm_cpuid2(void) +{ + struct kvm_cpuid2 *cpuid; + int nent = 100; + size_t size; + + size = sizeof(*cpuid); + size += nent * sizeof(struct kvm_cpuid_entry2); + cpuid = malloc(size); + if (!cpuid) { + perror("malloc"); + abort(); + } + + cpuid->nent = nent; + + return cpuid; +} + +/* KVM Supported CPUID Get + * + * Input Args: None + * + * Output Args: + * cpuid - The supported KVM CPUID + * + * Return: void + * + * Get the guest CPUID supported by KVM. + */ +void kvm_get_supported_cpuid(struct kvm_cpuid2 *cpuid) +{ + int ret; + int kvm_fd; + + kvm_fd = open(KVM_DEV_PATH, O_RDONLY); + TEST_ASSERT(kvm_fd >= 0, "open %s failed, rc: %i errno: %i", + KVM_DEV_PATH, kvm_fd, errno); + + ret = ioctl(kvm_fd, KVM_GET_SUPPORTED_CPUID, cpuid); + TEST_ASSERT(ret == 0, "KVM_GET_SUPPORTED_CPUID failed %d %d\n", + ret, errno); + + close(kvm_fd); +} + +/* Locate a cpuid entry. + * + * Input Args: + * cpuid: The cpuid. + * function: The function of the cpuid entry to find. + * + * Output Args: None + * + * Return: A pointer to the cpuid entry. Never returns NULL. + */ +struct kvm_cpuid_entry2 * +find_cpuid_index_entry(struct kvm_cpuid2 *cpuid, uint32_t function, + uint32_t index) +{ + struct kvm_cpuid_entry2 *entry = NULL; + int i; + + for (i = 0; i < cpuid->nent; i++) { + if (cpuid->entries[i].function == function && + cpuid->entries[i].index == index) { + entry = &cpuid->entries[i]; + break; + } + } + + TEST_ASSERT(entry, "Guest CPUID entry not found: (EAX=%x, ECX=%x).", + function, index); + return entry; +} + +/* VM Userspace Memory Region Add + * + * Input Args: + * vm - Virtual Machine + * backing_src - Storage source for this region. + * NULL to use anonymous memory. + * guest_paddr - Starting guest physical address + * slot - KVM region slot + * npages - Number of physical pages + * flags - KVM memory region flags (e.g. KVM_MEM_LOG_DIRTY_PAGES) + * + * Output Args: None + * + * Return: None + * + * Allocates a memory area of the number of pages specified by npages + * and maps it to the VM specified by vm, at a starting physical address + * given by guest_paddr. The region is created with a KVM region slot + * given by slot, which must be unique and < KVM_MEM_SLOTS_NUM. The + * region is created with the flags given by flags. + */ +void vm_userspace_mem_region_add(struct kvm_vm *vm, + enum vm_mem_backing_src_type src_type, + uint64_t guest_paddr, uint32_t slot, uint64_t npages, + uint32_t flags) +{ + int ret; + unsigned long pmem_size = 0; + struct userspace_mem_region *region; + size_t huge_page_size = KVM_UTIL_PGS_PER_HUGEPG * vm->page_size; + + TEST_ASSERT((guest_paddr % vm->page_size) == 0, "Guest physical " + "address not on a page boundary.\n" + " guest_paddr: 0x%lx vm->page_size: 0x%x", + guest_paddr, vm->page_size); + TEST_ASSERT((((guest_paddr >> vm->page_shift) + npages) - 1) + <= vm->max_gfn, "Physical range beyond maximum " + "supported physical address,\n" + " guest_paddr: 0x%lx npages: 0x%lx\n" + " vm->max_gfn: 0x%lx vm->page_size: 0x%x", + guest_paddr, npages, vm->max_gfn, vm->page_size); + + /* Confirm a mem region with an overlapping address doesn't + * already exist. + */ + region = (struct userspace_mem_region *) userspace_mem_region_find( + vm, guest_paddr, guest_paddr + npages * vm->page_size); + if (region != NULL) + TEST_ASSERT(false, "overlapping userspace_mem_region already " + "exists\n" + " requested guest_paddr: 0x%lx npages: 0x%lx " + "page_size: 0x%x\n" + " existing guest_paddr: 0x%lx size: 0x%lx", + guest_paddr, npages, vm->page_size, + (uint64_t) region->region.guest_phys_addr, + (uint64_t) region->region.memory_size); + + /* Confirm no region with the requested slot already exists. */ + for (region = vm->userspace_mem_region_head; region; + region = region->next) { + if (region->region.slot == slot) + break; + if ((guest_paddr <= (region->region.guest_phys_addr + + region->region.memory_size)) + && ((guest_paddr + npages * vm->page_size) + >= region->region.guest_phys_addr)) + break; + } + if (region != NULL) + TEST_ASSERT(false, "A mem region with the requested slot " + "or overlapping physical memory range already exists.\n" + " requested slot: %u paddr: 0x%lx npages: 0x%lx\n" + " existing slot: %u paddr: 0x%lx size: 0x%lx", + slot, guest_paddr, npages, + region->region.slot, + (uint64_t) region->region.guest_phys_addr, + (uint64_t) region->region.memory_size); + + /* Allocate and initialize new mem region structure. */ + region = calloc(1, sizeof(*region)); + TEST_ASSERT(region != NULL, "Insufficient Memory"); + region->mmap_size = npages * vm->page_size; + + /* Enough memory to align up to a huge page. */ + if (src_type == VM_MEM_SRC_ANONYMOUS_THP) + region->mmap_size += huge_page_size; + region->mmap_start = mmap(NULL, region->mmap_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS + | (src_type == VM_MEM_SRC_ANONYMOUS_HUGETLB ? MAP_HUGETLB : 0), + -1, 0); + TEST_ASSERT(region->mmap_start != MAP_FAILED, + "test_malloc failed, mmap_start: %p errno: %i", + region->mmap_start, errno); + + /* Align THP allocation up to start of a huge page. */ + region->host_mem = align(region->mmap_start, + src_type == VM_MEM_SRC_ANONYMOUS_THP ? huge_page_size : 1); + + /* As needed perform madvise */ + if (src_type == VM_MEM_SRC_ANONYMOUS || src_type == VM_MEM_SRC_ANONYMOUS_THP) { + ret = madvise(region->host_mem, npages * vm->page_size, + src_type == VM_MEM_SRC_ANONYMOUS ? MADV_NOHUGEPAGE : MADV_HUGEPAGE); + TEST_ASSERT(ret == 0, "madvise failed,\n" + " addr: %p\n" + " length: 0x%lx\n" + " src_type: %x", + region->host_mem, npages * vm->page_size, src_type); + } + + region->unused_phy_pages = sparsebit_alloc(); + sparsebit_set_num(region->unused_phy_pages, + guest_paddr >> vm->page_shift, npages); + region->region.slot = slot; + region->region.flags = flags; + region->region.guest_phys_addr = guest_paddr; + region->region.memory_size = npages * vm->page_size; + region->region.userspace_addr = (uintptr_t) region->host_mem; + ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); + TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" + " rc: %i errno: %i\n" + " slot: %u flags: 0x%x\n" + " guest_phys_addr: 0x%lx size: 0x%lx", + ret, errno, slot, flags, + guest_paddr, (uint64_t) region->region.memory_size); + + /* Add to linked-list of memory regions. */ + if (vm->userspace_mem_region_head) + vm->userspace_mem_region_head->prev = region; + region->next = vm->userspace_mem_region_head; + vm->userspace_mem_region_head = region; +} + +/* Memslot to region + * + * Input Args: + * vm - Virtual Machine + * memslot - KVM memory slot ID + * + * Output Args: None + * + * Return: + * Pointer to memory region structure that describe memory region + * using kvm memory slot ID given by memslot. TEST_ASSERT failure + * on error (e.g. currently no memory region using memslot as a KVM + * memory slot ID). + */ +static struct userspace_mem_region *memslot2region(struct kvm_vm *vm, + uint32_t memslot) +{ + struct userspace_mem_region *region; + + for (region = vm->userspace_mem_region_head; region; + region = region->next) { + if (region->region.slot == memslot) + break; + } + if (region == NULL) { + fprintf(stderr, "No mem region with the requested slot found,\n" + " requested slot: %u\n", memslot); + fputs("---- vm dump ----\n", stderr); + vm_dump(stderr, vm, 2); + TEST_ASSERT(false, "Mem region not found"); + } + + return region; +} + +/* VM Memory Region Flags Set + * + * Input Args: + * vm - Virtual Machine + * flags - Starting guest physical address + * + * Output Args: None + * + * Return: None + * + * Sets the flags of the memory region specified by the value of slot, + * to the values given by flags. + */ +void vm_mem_region_set_flags(struct kvm_vm *vm, uint32_t slot, uint32_t flags) +{ + int ret; + struct userspace_mem_region *region; + + /* Locate memory region. */ + region = memslot2region(vm, slot); + + region->region.flags = flags; + + ret = ioctl(vm->fd, KVM_SET_USER_MEMORY_REGION, ®ion->region); + + TEST_ASSERT(ret == 0, "KVM_SET_USER_MEMORY_REGION IOCTL failed,\n" + " rc: %i errno: %i slot: %u flags: 0x%x", + ret, errno, slot, flags); +} + +/* VCPU mmap Size + * + * Input Args: None + * + * Output Args: None + * + * Return: + * Size of VCPU state + * + * Returns the size of the structure pointed to by the return value + * of vcpu_state(). + */ +static int vcpu_mmap_sz(void) +{ + int dev_fd, ret; + + dev_fd = open(KVM_DEV_PATH, O_RDONLY); + TEST_ASSERT(dev_fd >= 0, "%s open %s failed, rc: %i errno: %i", + __func__, KVM_DEV_PATH, dev_fd, errno); + + ret = ioctl(dev_fd, KVM_GET_VCPU_MMAP_SIZE, NULL); + TEST_ASSERT(ret >= sizeof(struct kvm_run), + "%s KVM_GET_VCPU_MMAP_SIZE ioctl failed, rc: %i errno: %i", + __func__, ret, errno); + + close(dev_fd); + + return ret; +} + +/* VM VCPU Add + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * + * Output Args: None + * + * Return: None + * + * Creates and adds to the VM specified by vm and virtual CPU with + * the ID given by vcpuid. + */ +void vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpuid) +{ + struct vcpu *vcpu; + + /* Confirm a vcpu with the specified id doesn't already exist. */ + vcpu = vcpu_find(vm, vcpuid); + if (vcpu != NULL) + TEST_ASSERT(false, "vcpu with the specified id " + "already exists,\n" + " requested vcpuid: %u\n" + " existing vcpuid: %u state: %p", + vcpuid, vcpu->id, vcpu->state); + + /* Allocate and initialize new vcpu structure. */ + vcpu = calloc(1, sizeof(*vcpu)); + TEST_ASSERT(vcpu != NULL, "Insufficient Memory"); + vcpu->id = vcpuid; + vcpu->fd = ioctl(vm->fd, KVM_CREATE_VCPU, vcpuid); + TEST_ASSERT(vcpu->fd >= 0, "KVM_CREATE_VCPU failed, rc: %i errno: %i", + vcpu->fd, errno); + + TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->state), "vcpu mmap size " + "smaller than expected, vcpu_mmap_sz: %i expected_min: %zi", + vcpu_mmap_sz(), sizeof(*vcpu->state)); + vcpu->state = (struct kvm_run *) mmap(NULL, sizeof(*vcpu->state), + PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, 0); + TEST_ASSERT(vcpu->state != MAP_FAILED, "mmap vcpu_state failed, " + "vcpu id: %u errno: %i", vcpuid, errno); + + /* Add to linked-list of VCPUs. */ + if (vm->vcpu_head) + vm->vcpu_head->prev = vcpu; + vcpu->next = vm->vcpu_head; + vm->vcpu_head = vcpu; + + vcpu_setup(vm, vcpuid); +} + +/* VM Virtual Address Unused Gap + * + * Input Args: + * vm - Virtual Machine + * sz - Size (bytes) + * vaddr_min - Minimum Virtual Address + * + * Output Args: None + * + * Return: + * Lowest virtual address at or below vaddr_min, with at least + * sz unused bytes. TEST_ASSERT failure if no area of at least + * size sz is available. + * + * Within the VM specified by vm, locates the lowest starting virtual + * address >= vaddr_min, that has at least sz unallocated bytes. A + * TEST_ASSERT failure occurs for invalid input or no area of at least + * sz unallocated bytes >= vaddr_min is available. + */ +static vm_vaddr_t vm_vaddr_unused_gap(struct kvm_vm *vm, size_t sz, + vm_vaddr_t vaddr_min) +{ + uint64_t pages = (sz + vm->page_size - 1) >> vm->page_shift; + + /* Determine lowest permitted virtual page index. */ + uint64_t pgidx_start = (vaddr_min + vm->page_size - 1) >> vm->page_shift; + if ((pgidx_start * vm->page_size) < vaddr_min) + goto no_va_found; + + /* Loop over section with enough valid virtual page indexes. */ + if (!sparsebit_is_set_num(vm->vpages_valid, + pgidx_start, pages)) + pgidx_start = sparsebit_next_set_num(vm->vpages_valid, + pgidx_start, pages); + do { + /* + * Are there enough unused virtual pages available at + * the currently proposed starting virtual page index. + * If not, adjust proposed starting index to next + * possible. + */ + if (sparsebit_is_clear_num(vm->vpages_mapped, + pgidx_start, pages)) + goto va_found; + pgidx_start = sparsebit_next_clear_num(vm->vpages_mapped, + pgidx_start, pages); + if (pgidx_start == 0) + goto no_va_found; + + /* + * If needed, adjust proposed starting virtual address, + * to next range of valid virtual addresses. + */ + if (!sparsebit_is_set_num(vm->vpages_valid, + pgidx_start, pages)) { + pgidx_start = sparsebit_next_set_num( + vm->vpages_valid, pgidx_start, pages); + if (pgidx_start == 0) + goto no_va_found; + } + } while (pgidx_start != 0); + +no_va_found: + TEST_ASSERT(false, "No vaddr of specified pages available, " + "pages: 0x%lx", pages); + + /* NOT REACHED */ + return -1; + +va_found: + TEST_ASSERT(sparsebit_is_set_num(vm->vpages_valid, + pgidx_start, pages), + "Unexpected, invalid virtual page index range,\n" + " pgidx_start: 0x%lx\n" + " pages: 0x%lx", + pgidx_start, pages); + TEST_ASSERT(sparsebit_is_clear_num(vm->vpages_mapped, + pgidx_start, pages), + "Unexpected, pages already mapped,\n" + " pgidx_start: 0x%lx\n" + " pages: 0x%lx", + pgidx_start, pages); + + return pgidx_start * vm->page_size; +} + +/* VM Virtual Address Allocate + * + * Input Args: + * vm - Virtual Machine + * sz - Size in bytes + * vaddr_min - Minimum starting virtual address + * data_memslot - Memory region slot for data pages + * pgd_memslot - Memory region slot for new virtual translation tables + * + * Output Args: None + * + * Return: + * Starting guest virtual address + * + * Allocates at least sz bytes within the virtual address space of the vm + * given by vm. The allocated bytes are mapped to a virtual address >= + * the address given by vaddr_min. Note that each allocation uses a + * a unique set of pages, with the minimum real allocation being at least + * a page. + */ +vm_vaddr_t vm_vaddr_alloc(struct kvm_vm *vm, size_t sz, vm_vaddr_t vaddr_min, + uint32_t data_memslot, uint32_t pgd_memslot) +{ + uint64_t pages = (sz >> vm->page_shift) + ((sz % vm->page_size) != 0); + + virt_pgd_alloc(vm, pgd_memslot); + + /* Find an unused range of virtual page addresses of at least + * pages in length. + */ + vm_vaddr_t vaddr_start = vm_vaddr_unused_gap(vm, sz, vaddr_min); + + /* Map the virtual pages. */ + for (vm_vaddr_t vaddr = vaddr_start; pages > 0; + pages--, vaddr += vm->page_size) { + vm_paddr_t paddr; + + paddr = vm_phy_page_alloc(vm, KVM_UTIL_MIN_PADDR, data_memslot); + + virt_pg_map(vm, vaddr, paddr, pgd_memslot); + + sparsebit_set(vm->vpages_mapped, + vaddr >> vm->page_shift); + } + + return vaddr_start; +} + +/* Address VM Physical to Host Virtual + * + * Input Args: + * vm - Virtual Machine + * gpa - VM physical address + * + * Output Args: None + * + * Return: + * Equivalent host virtual address + * + * Locates the memory region containing the VM physical address given + * by gpa, within the VM given by vm. When found, the host virtual + * address providing the memory to the vm physical address is returned. + * A TEST_ASSERT failure occurs if no region containing gpa exists. + */ +void *addr_gpa2hva(struct kvm_vm *vm, vm_paddr_t gpa) +{ + struct userspace_mem_region *region; + for (region = vm->userspace_mem_region_head; region; + region = region->next) { + if ((gpa >= region->region.guest_phys_addr) + && (gpa <= (region->region.guest_phys_addr + + region->region.memory_size - 1))) + return (void *) ((uintptr_t) region->host_mem + + (gpa - region->region.guest_phys_addr)); + } + + TEST_ASSERT(false, "No vm physical memory at 0x%lx", gpa); + return NULL; +} + +/* Address Host Virtual to VM Physical + * + * Input Args: + * vm - Virtual Machine + * hva - Host virtual address + * + * Output Args: None + * + * Return: + * Equivalent VM physical address + * + * Locates the memory region containing the host virtual address given + * by hva, within the VM given by vm. When found, the equivalent + * VM physical address is returned. A TEST_ASSERT failure occurs if no + * region containing hva exists. + */ +vm_paddr_t addr_hva2gpa(struct kvm_vm *vm, void *hva) +{ + struct userspace_mem_region *region; + for (region = vm->userspace_mem_region_head; region; + region = region->next) { + if ((hva >= region->host_mem) + && (hva <= (region->host_mem + + region->region.memory_size - 1))) + return (vm_paddr_t) ((uintptr_t) + region->region.guest_phys_addr + + (hva - (uintptr_t) region->host_mem)); + } + + TEST_ASSERT(false, "No mapping to a guest physical address, " + "hva: %p", hva); + return -1; +} + +/* VM Create IRQ Chip + * + * Input Args: + * vm - Virtual Machine + * + * Output Args: None + * + * Return: None + * + * Creates an interrupt controller chip for the VM specified by vm. + */ +void vm_create_irqchip(struct kvm_vm *vm) +{ + int ret; + + ret = ioctl(vm->fd, KVM_CREATE_IRQCHIP, 0); + TEST_ASSERT(ret == 0, "KVM_CREATE_IRQCHIP IOCTL failed, " + "rc: %i errno: %i", ret, errno); +} + +/* VM VCPU State + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * + * Output Args: None + * + * Return: + * Pointer to structure that describes the state of the VCPU. + * + * Locates and returns a pointer to a structure that describes the + * state of the VCPU with the given vcpuid. + */ +struct kvm_run *vcpu_state(struct kvm_vm *vm, uint32_t vcpuid) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + + return vcpu->state; +} + +/* VM VCPU Run + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * + * Output Args: None + * + * Return: None + * + * Switch to executing the code for the VCPU given by vcpuid, within the VM + * given by vm. + */ +void vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) +{ + int ret = _vcpu_run(vm, vcpuid); + TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " + "rc: %i errno: %i", ret, errno); +} + +int _vcpu_run(struct kvm_vm *vm, uint32_t vcpuid) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int rc; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + do { + rc = ioctl(vcpu->fd, KVM_RUN, NULL); + } while (rc == -1 && errno == EINTR); + return rc; +} + +/* VM VCPU Set MP State + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * mp_state - mp_state to be set + * + * Output Args: None + * + * Return: None + * + * Sets the MP state of the VCPU given by vcpuid, to the state given + * by mp_state. + */ +void vcpu_set_mp_state(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_mp_state *mp_state) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int ret; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + + ret = ioctl(vcpu->fd, KVM_SET_MP_STATE, mp_state); + TEST_ASSERT(ret == 0, "KVM_SET_MP_STATE IOCTL failed, " + "rc: %i errno: %i", ret, errno); +} + +/* VM VCPU Regs Get + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * + * Output Args: + * regs - current state of VCPU regs + * + * Return: None + * + * Obtains the current register state for the VCPU specified by vcpuid + * and stores it at the location given by regs. + */ +void vcpu_regs_get(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_regs *regs) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int ret; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + + /* Get the regs. */ + ret = ioctl(vcpu->fd, KVM_GET_REGS, regs); + TEST_ASSERT(ret == 0, "KVM_GET_REGS failed, rc: %i errno: %i", + ret, errno); +} + +/* VM VCPU Regs Set + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * regs - Values to set VCPU regs to + * + * Output Args: None + * + * Return: None + * + * Sets the regs of the VCPU specified by vcpuid to the values + * given by regs. + */ +void vcpu_regs_set(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_regs *regs) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int ret; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + + /* Set the regs. */ + ret = ioctl(vcpu->fd, KVM_SET_REGS, regs); + TEST_ASSERT(ret == 0, "KVM_SET_REGS failed, rc: %i errno: %i", + ret, errno); +} + +void vcpu_events_get(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_vcpu_events *events) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int ret; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + + /* Get the regs. */ + ret = ioctl(vcpu->fd, KVM_GET_VCPU_EVENTS, events); + TEST_ASSERT(ret == 0, "KVM_GET_VCPU_EVENTS, failed, rc: %i errno: %i", + ret, errno); +} + +void vcpu_events_set(struct kvm_vm *vm, uint32_t vcpuid, + struct kvm_vcpu_events *events) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int ret; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + + /* Set the regs. */ + ret = ioctl(vcpu->fd, KVM_SET_VCPU_EVENTS, events); + TEST_ASSERT(ret == 0, "KVM_SET_VCPU_EVENTS, failed, rc: %i errno: %i", + ret, errno); +} + +/* VM VCPU Args Set + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * num - number of arguments + * ... - arguments, each of type uint64_t + * + * Output Args: None + * + * Return: None + * + * Sets the first num function input arguments to the values + * given as variable args. Each of the variable args is expected to + * be of type uint64_t. + */ +void vcpu_args_set(struct kvm_vm *vm, uint32_t vcpuid, unsigned int num, ...) +{ + va_list ap; + struct kvm_regs regs; + + TEST_ASSERT(num >= 1 && num <= 6, "Unsupported number of args,\n" + " num: %u\n", + num); + + va_start(ap, num); + vcpu_regs_get(vm, vcpuid, ®s); + + if (num >= 1) + regs.rdi = va_arg(ap, uint64_t); + + if (num >= 2) + regs.rsi = va_arg(ap, uint64_t); + + if (num >= 3) + regs.rdx = va_arg(ap, uint64_t); + + if (num >= 4) + regs.rcx = va_arg(ap, uint64_t); + + if (num >= 5) + regs.r8 = va_arg(ap, uint64_t); + + if (num >= 6) + regs.r9 = va_arg(ap, uint64_t); + + vcpu_regs_set(vm, vcpuid, ®s); + va_end(ap); +} + +/* VM VCPU System Regs Get + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * + * Output Args: + * sregs - current state of VCPU system regs + * + * Return: None + * + * Obtains the current system register state for the VCPU specified by + * vcpuid and stores it at the location given by sregs. + */ +void vcpu_sregs_get(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_sregs *sregs) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int ret; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + + /* Get the regs. */ + /* Get the regs. */ + ret = ioctl(vcpu->fd, KVM_GET_SREGS, sregs); + TEST_ASSERT(ret == 0, "KVM_GET_SREGS failed, rc: %i errno: %i", + ret, errno); +} + +/* VM VCPU System Regs Set + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * sregs - Values to set VCPU system regs to + * + * Output Args: None + * + * Return: None + * + * Sets the system regs of the VCPU specified by vcpuid to the values + * given by sregs. + */ +void vcpu_sregs_set(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_sregs *sregs) +{ + int ret = _vcpu_sregs_set(vm, vcpuid, sregs); + TEST_ASSERT(ret == 0, "KVM_RUN IOCTL failed, " + "rc: %i errno: %i", ret, errno); +} + +int _vcpu_sregs_set(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_sregs *sregs) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int ret; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + + /* Get the regs. */ + return ioctl(vcpu->fd, KVM_SET_SREGS, sregs); +} + +/* VCPU Ioctl + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * cmd - Ioctl number + * arg - Argument to pass to the ioctl + * + * Return: None + * + * Issues an arbitrary ioctl on a VCPU fd. + */ +void vcpu_ioctl(struct kvm_vm *vm, + uint32_t vcpuid, unsigned long cmd, void *arg) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int ret; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + + ret = ioctl(vcpu->fd, cmd, arg); + TEST_ASSERT(ret == 0, "vcpu ioctl %lu failed, rc: %i errno: %i (%s)", + cmd, ret, errno, strerror(errno)); +} + +/* VM Ioctl + * + * Input Args: + * vm - Virtual Machine + * cmd - Ioctl number + * arg - Argument to pass to the ioctl + * + * Return: None + * + * Issues an arbitrary ioctl on a VM fd. + */ +void vm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg) +{ + int ret; + + ret = ioctl(vm->fd, cmd, arg); + TEST_ASSERT(ret == 0, "vm ioctl %lu failed, rc: %i errno: %i (%s)", + cmd, ret, errno, strerror(errno)); +} + +/* VM Dump + * + * Input Args: + * vm - Virtual Machine + * indent - Left margin indent amount + * + * Output Args: + * stream - Output FILE stream + * + * Return: None + * + * Dumps the current state of the VM given by vm, to the FILE stream + * given by stream. + */ +void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) +{ + struct userspace_mem_region *region; + struct vcpu *vcpu; + + fprintf(stream, "%*smode: 0x%x\n", indent, "", vm->mode); + fprintf(stream, "%*sfd: %i\n", indent, "", vm->fd); + fprintf(stream, "%*spage_size: 0x%x\n", indent, "", vm->page_size); + fprintf(stream, "%*sMem Regions:\n", indent, ""); + for (region = vm->userspace_mem_region_head; region; + region = region->next) { + fprintf(stream, "%*sguest_phys: 0x%lx size: 0x%lx " + "host_virt: %p\n", indent + 2, "", + (uint64_t) region->region.guest_phys_addr, + (uint64_t) region->region.memory_size, + region->host_mem); + fprintf(stream, "%*sunused_phy_pages: ", indent + 2, ""); + sparsebit_dump(stream, region->unused_phy_pages, 0); + } + fprintf(stream, "%*sMapped Virtual Pages:\n", indent, ""); + sparsebit_dump(stream, vm->vpages_mapped, indent + 2); + fprintf(stream, "%*spgd_created: %u\n", indent, "", + vm->pgd_created); + if (vm->pgd_created) { + fprintf(stream, "%*sVirtual Translation Tables:\n", + indent + 2, ""); + virt_dump(stream, vm, indent + 4); + } + fprintf(stream, "%*sVCPUs:\n", indent, ""); + for (vcpu = vm->vcpu_head; vcpu; vcpu = vcpu->next) + vcpu_dump(stream, vm, vcpu->id, indent + 2); +} + +/* VM VCPU Dump + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU ID + * indent - Left margin indent amount + * + * Output Args: + * stream - Output FILE stream + * + * Return: None + * + * Dumps the current state of the VCPU specified by vcpuid, within the VM + * given by vm, to the FILE stream given by stream. + */ +void vcpu_dump(FILE *stream, struct kvm_vm *vm, + uint32_t vcpuid, uint8_t indent) +{ + struct kvm_regs regs; + struct kvm_sregs sregs; + + fprintf(stream, "%*scpuid: %u\n", indent, "", vcpuid); + + fprintf(stream, "%*sregs:\n", indent + 2, ""); + vcpu_regs_get(vm, vcpuid, ®s); + regs_dump(stream, ®s, indent + 4); + + fprintf(stream, "%*ssregs:\n", indent + 2, ""); + vcpu_sregs_get(vm, vcpuid, &sregs); + sregs_dump(stream, &sregs, indent + 4); +} + +/* Known KVM exit reasons */ +static struct exit_reason { + unsigned int reason; + const char *name; +} exit_reasons_known[] = { + {KVM_EXIT_UNKNOWN, "UNKNOWN"}, + {KVM_EXIT_EXCEPTION, "EXCEPTION"}, + {KVM_EXIT_IO, "IO"}, + {KVM_EXIT_HYPERCALL, "HYPERCALL"}, + {KVM_EXIT_DEBUG, "DEBUG"}, + {KVM_EXIT_HLT, "HLT"}, + {KVM_EXIT_MMIO, "MMIO"}, + {KVM_EXIT_IRQ_WINDOW_OPEN, "IRQ_WINDOW_OPEN"}, + {KVM_EXIT_SHUTDOWN, "SHUTDOWN"}, + {KVM_EXIT_FAIL_ENTRY, "FAIL_ENTRY"}, + {KVM_EXIT_INTR, "INTR"}, + {KVM_EXIT_SET_TPR, "SET_TPR"}, + {KVM_EXIT_TPR_ACCESS, "TPR_ACCESS"}, + {KVM_EXIT_S390_SIEIC, "S390_SIEIC"}, + {KVM_EXIT_S390_RESET, "S390_RESET"}, + {KVM_EXIT_DCR, "DCR"}, + {KVM_EXIT_NMI, "NMI"}, + {KVM_EXIT_INTERNAL_ERROR, "INTERNAL_ERROR"}, + {KVM_EXIT_OSI, "OSI"}, + {KVM_EXIT_PAPR_HCALL, "PAPR_HCALL"}, +#ifdef KVM_EXIT_MEMORY_NOT_PRESENT + {KVM_EXIT_MEMORY_NOT_PRESENT, "MEMORY_NOT_PRESENT"}, +#endif +}; + +/* Exit Reason String + * + * Input Args: + * exit_reason - Exit reason + * + * Output Args: None + * + * Return: + * Constant string pointer describing the exit reason. + * + * Locates and returns a constant string that describes the KVM exit + * reason given by exit_reason. If no such string is found, a constant + * string of "Unknown" is returned. + */ +const char *exit_reason_str(unsigned int exit_reason) +{ + unsigned int n1; + + for (n1 = 0; n1 < ARRAY_SIZE(exit_reasons_known); n1++) { + if (exit_reason == exit_reasons_known[n1].reason) + return exit_reasons_known[n1].name; + } + + return "Unknown"; +} + +/* Physical Page Allocate + * + * Input Args: + * vm - Virtual Machine + * paddr_min - Physical address minimum + * memslot - Memory region to allocate page from + * + * Output Args: None + * + * Return: + * Starting physical address + * + * Within the VM specified by vm, locates an available physical page + * at or above paddr_min. If found, the page is marked as in use + * and its address is returned. A TEST_ASSERT failure occurs if no + * page is available at or above paddr_min. + */ +vm_paddr_t vm_phy_page_alloc(struct kvm_vm *vm, + vm_paddr_t paddr_min, uint32_t memslot) +{ + struct userspace_mem_region *region; + sparsebit_idx_t pg; + + TEST_ASSERT((paddr_min % vm->page_size) == 0, "Min physical address " + "not divisable by page size.\n" + " paddr_min: 0x%lx page_size: 0x%x", + paddr_min, vm->page_size); + + /* Locate memory region. */ + region = memslot2region(vm, memslot); + + /* Locate next available physical page at or above paddr_min. */ + pg = paddr_min >> vm->page_shift; + + if (!sparsebit_is_set(region->unused_phy_pages, pg)) { + pg = sparsebit_next_set(region->unused_phy_pages, pg); + if (pg == 0) { + fprintf(stderr, "No guest physical page available, " + "paddr_min: 0x%lx page_size: 0x%x memslot: %u", + paddr_min, vm->page_size, memslot); + fputs("---- vm dump ----\n", stderr); + vm_dump(stderr, vm, 2); + abort(); + } + } + + /* Specify page as in use and return its address. */ + sparsebit_clear(region->unused_phy_pages, pg); + + return pg * vm->page_size; +} + +/* Address Guest Virtual to Host Virtual + * + * Input Args: + * vm - Virtual Machine + * gva - VM virtual address + * + * Output Args: None + * + * Return: + * Equivalent host virtual address + */ +void *addr_gva2hva(struct kvm_vm *vm, vm_vaddr_t gva) +{ + return addr_gpa2hva(vm, addr_gva2gpa(vm, gva)); +} diff --git a/tools/testing/selftests/kvm/lib/kvm_util_internal.h b/tools/testing/selftests/kvm/lib/kvm_util_internal.h new file mode 100644 index 000000000000..a0bd1980c81c --- /dev/null +++ b/tools/testing/selftests/kvm/lib/kvm_util_internal.h @@ -0,0 +1,67 @@ +/* + * tools/testing/selftests/kvm/lib/kvm_util.c + * + * Copyright (C) 2018, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#ifndef KVM_UTIL_INTERNAL_H +#define KVM_UTIL_INTERNAL_H 1 + +#include "sparsebit.h" + +#ifndef BITS_PER_BYTE +#define BITS_PER_BYTE 8 +#endif + +#ifndef BITS_PER_LONG +#define BITS_PER_LONG (BITS_PER_BYTE * sizeof(long)) +#endif + +#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) +#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_LONG) + +/* Concrete definition of struct kvm_vm. */ +struct userspace_mem_region { + struct userspace_mem_region *next, *prev; + struct kvm_userspace_memory_region region; + struct sparsebit *unused_phy_pages; + int fd; + off_t offset; + void *host_mem; + void *mmap_start; + size_t mmap_size; +}; + +struct vcpu { + struct vcpu *next, *prev; + uint32_t id; + int fd; + struct kvm_run *state; +}; + +struct kvm_vm { + int mode; + int fd; + unsigned int page_size; + unsigned int page_shift; + uint64_t max_gfn; + struct vcpu *vcpu_head; + struct userspace_mem_region *userspace_mem_region_head; + struct sparsebit *vpages_valid; + struct sparsebit *vpages_mapped; + bool pgd_created; + vm_paddr_t pgd; +}; + +struct vcpu *vcpu_find(struct kvm_vm *vm, + uint32_t vcpuid); +void vcpu_setup(struct kvm_vm *vm, int vcpuid); +void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); +void regs_dump(FILE *stream, struct kvm_regs *regs, + uint8_t indent); +void sregs_dump(FILE *stream, struct kvm_sregs *sregs, + uint8_t indent); + +#endif diff --git a/tools/testing/selftests/kvm/lib/sparsebit.c b/tools/testing/selftests/kvm/lib/sparsebit.c new file mode 100644 index 000000000000..0c5cf3e0cb6f --- /dev/null +++ b/tools/testing/selftests/kvm/lib/sparsebit.c @@ -0,0 +1,2087 @@ +/* + * Sparse bit array + * + * Copyright (C) 2018, Google LLC. + * Copyright (C) 2018, Red Hat, Inc. (code style cleanup and fuzzing driver) + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + * This library provides functions to support a memory efficient bit array, + * with an index size of 2^64. A sparsebit array is allocated through + * the use sparsebit_alloc() and free'd via sparsebit_free(), + * such as in the following: + * + * struct sparsebit *s; + * s = sparsebit_alloc(); + * sparsebit_free(&s); + * + * The struct sparsebit type resolves down to a struct sparsebit. + * Note that, sparsebit_free() takes a pointer to the sparsebit + * structure. This is so that sparsebit_free() is able to poison + * the pointer (e.g. set it to NULL) to the struct sparsebit before + * returning to the caller. + * + * Between the return of sparsebit_alloc() and the call of + * sparsebit_free(), there are multiple query and modifying operations + * that can be performed on the allocated sparsebit array. All of + * these operations take as a parameter the value returned from + * sparsebit_alloc() and most also take a bit index. Frequently + * used routines include: + * + * ---- Query Operations + * sparsebit_is_set(s, idx) + * sparsebit_is_clear(s, idx) + * sparsebit_any_set(s) + * sparsebit_first_set(s) + * sparsebit_next_set(s, prev_idx) + * + * ---- Modifying Operations + * sparsebit_set(s, idx) + * sparsebit_clear(s, idx) + * sparsebit_set_num(s, idx, num); + * sparsebit_clear_num(s, idx, num); + * + * A common operation, is to itterate over all the bits set in a test + * sparsebit array. This can be done via code with the following structure: + * + * sparsebit_idx_t idx; + * if (sparsebit_any_set(s)) { + * idx = sparsebit_first_set(s); + * do { + * ... + * idx = sparsebit_next_set(s, idx); + * } while (idx != 0); + * } + * + * The index of the first bit set needs to be obtained via + * sparsebit_first_set(), because sparsebit_next_set(), needs + * the index of the previously set. The sparsebit_idx_t type is + * unsigned, so there is no previous index before 0 that is available. + * Also, the call to sparsebit_first_set() is not made unless there + * is at least 1 bit in the array set. This is because sparsebit_first_set() + * aborts if sparsebit_first_set() is called with no bits set. + * It is the callers responsibility to assure that the + * sparsebit array has at least a single bit set before calling + * sparsebit_first_set(). + * + * ==== Implementation Overview ==== + * For the most part the internal implementation of sparsebit is + * opaque to the caller. One important implementation detail that the + * caller may need to be aware of is the spatial complexity of the + * implementation. This implementation of a sparsebit array is not + * only sparse, in that it uses memory proportional to the number of bits + * set. It is also efficient in memory usage when most of the bits are + * set. + * + * At a high-level the state of the bit settings are maintained through + * the use of a binary-search tree, where each node contains at least + * the following members: + * + * typedef uint64_t sparsebit_idx_t; + * typedef uint64_t sparsebit_num_t; + * + * sparsebit_idx_t idx; + * uint32_t mask; + * sparsebit_num_t num_after; + * + * The idx member contains the bit index of the first bit described by this + * node, while the mask member stores the setting of the first 32-bits. + * The setting of the bit at idx + n, where 0 <= n < 32, is located in the + * mask member at 1 << n. + * + * Nodes are sorted by idx and the bits described by two nodes will never + * overlap. The idx member is always aligned to the mask size, i.e. a + * multiple of 32. + * + * Beyond a typical implementation, the nodes in this implementation also + * contains a member named num_after. The num_after member holds the + * number of bits immediately after the mask bits that are contiguously set. + * The use of the num_after member allows this implementation to efficiently + * represent cases where most bits are set. For example, the case of all + * but the last two bits set, is represented by the following two nodes: + * + * node 0 - idx: 0x0 mask: 0xffffffff num_after: 0xffffffffffffffc0 + * node 1 - idx: 0xffffffffffffffe0 mask: 0x3fffffff num_after: 0 + * + * ==== Invariants ==== + * This implementation usses the following invariants: + * + * + Node are only used to represent bits that are set. + * Nodes with a mask of 0 and num_after of 0 are not allowed. + * + * + Sum of bits set in all the nodes is equal to the value of + * the struct sparsebit_pvt num_set member. + * + * + The setting of at least one bit is always described in a nodes + * mask (mask >= 1). + * + * + A node with all mask bits set only occurs when the last bit + * described by the previous node is not equal to this nodes + * starting index - 1. All such occurences of this condition are + * avoided by moving the setting of the nodes mask bits into + * the previous nodes num_after setting. + * + * + Node starting index is evenly divisable by the number of bits + * within a nodes mask member. + * + * + Nodes never represent a range of bits that wrap around the + * highest supported index. + * + * (idx + MASK_BITS + num_after - 1) <= ((sparsebit_idx_t) 0) - 1) + * + * As a consequence of the above, the num_after member of a node + * will always be <=: + * + * maximum_index - nodes_starting_index - number_of_mask_bits + * + * + Nodes within the binary search tree are sorted based on each + * nodes starting index. + * + * + The range of bits described by any two nodes do not overlap. The + * range of bits described by a single node is: + * + * start: node->idx + * end (inclusive): node->idx + MASK_BITS + node->num_after - 1; + * + * Note, at times these invariants are temporarily violated for a + * specific portion of the code. For example, when setting a mask + * bit, there is a small delay between when the mask bit is set and the + * value in the struct sparsebit_pvt num_set member is updated. Other + * temporary violations occur when node_split() is called with a specified + * index and assures that a node where its mask represents the bit + * at the specified index exists. At times to do this node_split() + * must split an existing node into two nodes or create a node that + * has no bits set. Such temporary violations must be corrected before + * returning to the caller. These corrections are typically performed + * by the local function node_reduce(). + */ + +#include "test_util.h" +#include "sparsebit.h" +#include +#include + +#define DUMP_LINE_MAX 100 /* Does not include indent amount */ + +typedef uint32_t mask_t; +#define MASK_BITS (sizeof(mask_t) * CHAR_BIT) + +struct node { + struct node *parent; + struct node *left; + struct node *right; + sparsebit_idx_t idx; /* index of least-significant bit in mask */ + sparsebit_num_t num_after; /* num contiguously set after mask */ + mask_t mask; +}; + +struct sparsebit { + /* + * Points to root node of the binary search + * tree. Equal to NULL when no bits are set in + * the entire sparsebit array. + */ + struct node *root; + + /* + * A redundant count of the total number of bits set. Used for + * diagnostic purposes and to change the time complexity of + * sparsebit_num_set() from O(n) to O(1). + * Note: Due to overflow, a value of 0 means none or all set. + */ + sparsebit_num_t num_set; +}; + +/* Returns the number of set bits described by the settings + * of the node pointed to by nodep. + */ +static sparsebit_num_t node_num_set(struct node *nodep) +{ + return nodep->num_after + __builtin_popcount(nodep->mask); +} + +/* Returns a pointer to the node that describes the + * lowest bit index. + */ +static struct node *node_first(struct sparsebit *s) +{ + struct node *nodep; + + for (nodep = s->root; nodep && nodep->left; nodep = nodep->left) + ; + + return nodep; +} + +/* Returns a pointer to the node that describes the + * lowest bit index > the index of the node pointed to by np. + * Returns NULL if no node with a higher index exists. + */ +static struct node *node_next(struct sparsebit *s, struct node *np) +{ + struct node *nodep = np; + + /* + * If current node has a right child, next node is the left-most + * of the right child. + */ + if (nodep->right) { + for (nodep = nodep->right; nodep->left; nodep = nodep->left) + ; + return nodep; + } + + /* + * No right child. Go up until node is left child of a parent. + * That parent is then the next node. + */ + while (nodep->parent && nodep == nodep->parent->right) + nodep = nodep->parent; + + return nodep->parent; +} + +/* Searches for and returns a pointer to the node that describes the + * highest index < the index of the node pointed to by np. + * Returns NULL if no node with a lower index exists. + */ +static struct node *node_prev(struct sparsebit *s, struct node *np) +{ + struct node *nodep = np; + + /* + * If current node has a left child, next node is the right-most + * of the left child. + */ + if (nodep->left) { + for (nodep = nodep->left; nodep->right; nodep = nodep->right) + ; + return (struct node *) nodep; + } + + /* + * No left child. Go up until node is right child of a parent. + * That parent is then the next node. + */ + while (nodep->parent && nodep == nodep->parent->left) + nodep = nodep->parent; + + return (struct node *) nodep->parent; +} + + +/* Allocates space to hold a copy of the node sub-tree pointed to by + * subtree and duplicates the bit settings to the newly allocated nodes. + * Returns the newly allocated copy of subtree. + */ +static struct node *node_copy_subtree(struct node *subtree) +{ + struct node *root; + + /* Duplicate the node at the root of the subtree */ + root = calloc(1, sizeof(*root)); + if (!root) { + perror("calloc"); + abort(); + } + + root->idx = subtree->idx; + root->mask = subtree->mask; + root->num_after = subtree->num_after; + + /* As needed, recursively duplicate the left and right subtrees */ + if (subtree->left) { + root->left = node_copy_subtree(subtree->left); + root->left->parent = root; + } + + if (subtree->right) { + root->right = node_copy_subtree(subtree->right); + root->right->parent = root; + } + + return root; +} + +/* Searches for and returns a pointer to the node that describes the setting + * of the bit given by idx. A node describes the setting of a bit if its + * index is within the bits described by the mask bits or the number of + * contiguous bits set after the mask. Returns NULL if there is no such node. + */ +static struct node *node_find(struct sparsebit *s, sparsebit_idx_t idx) +{ + struct node *nodep; + + /* Find the node that describes the setting of the bit at idx */ + for (nodep = s->root; nodep; + nodep = nodep->idx > idx ? nodep->left : nodep->right) { + if (idx >= nodep->idx && + idx <= nodep->idx + MASK_BITS + nodep->num_after - 1) + break; + } + + return nodep; +} + +/* Entry Requirements: + * + A node that describes the setting of idx is not already present. + * + * Adds a new node to describe the setting of the bit at the index given + * by idx. Returns a pointer to the newly added node. + * + * TODO(lhuemill): Degenerate cases causes the tree to get unbalanced. + */ +static struct node *node_add(struct sparsebit *s, sparsebit_idx_t idx) +{ + struct node *nodep, *parentp, *prev; + + /* Allocate and initialize the new node. */ + nodep = calloc(1, sizeof(*nodep)); + if (!nodep) { + perror("calloc"); + abort(); + } + + nodep->idx = idx & -MASK_BITS; + + /* If no nodes, set it up as the root node. */ + if (!s->root) { + s->root = nodep; + return nodep; + } + + /* + * Find the parent where the new node should be attached + * and add the node there. + */ + parentp = s->root; + while (true) { + if (idx < parentp->idx) { + if (!parentp->left) { + parentp->left = nodep; + nodep->parent = parentp; + break; + } + parentp = parentp->left; + } else { + assert(idx > parentp->idx + MASK_BITS + parentp->num_after - 1); + if (!parentp->right) { + parentp->right = nodep; + nodep->parent = parentp; + break; + } + parentp = parentp->right; + } + } + + /* + * Does num_after bits of previous node overlap with the mask + * of the new node? If so set the bits in the new nodes mask + * and reduce the previous nodes num_after. + */ + prev = node_prev(s, nodep); + while (prev && prev->idx + MASK_BITS + prev->num_after - 1 >= nodep->idx) { + unsigned int n1 = (prev->idx + MASK_BITS + prev->num_after - 1) + - nodep->idx; + assert(prev->num_after > 0); + assert(n1 < MASK_BITS); + assert(!(nodep->mask & (1 << n1))); + nodep->mask |= (1 << n1); + prev->num_after--; + } + + return nodep; +} + +/* Returns whether all the bits in the sparsebit array are set. */ +bool sparsebit_all_set(struct sparsebit *s) +{ + /* + * If any nodes there must be at least one bit set. Only case + * where a bit is set and total num set is 0, is when all bits + * are set. + */ + return s->root && s->num_set == 0; +} + +/* Clears all bits described by the node pointed to by nodep, then + * removes the node. + */ +static void node_rm(struct sparsebit *s, struct node *nodep) +{ + struct node *tmp; + sparsebit_num_t num_set; + + num_set = node_num_set(nodep); + assert(s->num_set >= num_set || sparsebit_all_set(s)); + s->num_set -= node_num_set(nodep); + + /* Have both left and right child */ + if (nodep->left && nodep->right) { + /* + * Move left children to the leftmost leaf node + * of the right child. + */ + for (tmp = nodep->right; tmp->left; tmp = tmp->left) + ; + tmp->left = nodep->left; + nodep->left = NULL; + tmp->left->parent = tmp; + } + + /* Left only child */ + if (nodep->left) { + if (!nodep->parent) { + s->root = nodep->left; + nodep->left->parent = NULL; + } else { + nodep->left->parent = nodep->parent; + if (nodep == nodep->parent->left) + nodep->parent->left = nodep->left; + else { + assert(nodep == nodep->parent->right); + nodep->parent->right = nodep->left; + } + } + + nodep->parent = nodep->left = nodep->right = NULL; + free(nodep); + + return; + } + + + /* Right only child */ + if (nodep->right) { + if (!nodep->parent) { + s->root = nodep->right; + nodep->right->parent = NULL; + } else { + nodep->right->parent = nodep->parent; + if (nodep == nodep->parent->left) + nodep->parent->left = nodep->right; + else { + assert(nodep == nodep->parent->right); + nodep->parent->right = nodep->right; + } + } + + nodep->parent = nodep->left = nodep->right = NULL; + free(nodep); + + return; + } + + /* Leaf Node */ + if (!nodep->parent) { + s->root = NULL; + } else { + if (nodep->parent->left == nodep) + nodep->parent->left = NULL; + else { + assert(nodep == nodep->parent->right); + nodep->parent->right = NULL; + } + } + + nodep->parent = nodep->left = nodep->right = NULL; + free(nodep); + + return; +} + +/* Splits the node containing the bit at idx so that there is a node + * that starts at the specified index. If no such node exists, a new + * node at the specified index is created. Returns the new node. + * + * idx must start of a mask boundary. + */ +static struct node *node_split(struct sparsebit *s, sparsebit_idx_t idx) +{ + struct node *nodep1, *nodep2; + sparsebit_idx_t offset; + sparsebit_num_t orig_num_after; + + assert(!(idx % MASK_BITS)); + + /* + * Is there a node that describes the setting of idx? + * If not, add it. + */ + nodep1 = node_find(s, idx); + if (!nodep1) + return node_add(s, idx); + + /* + * All done if the starting index of the node is where the + * split should occur. + */ + if (nodep1->idx == idx) + return nodep1; + + /* + * Split point not at start of mask, so it must be part of + * bits described by num_after. + */ + + /* + * Calculate offset within num_after for where the split is + * to occur. + */ + offset = idx - (nodep1->idx + MASK_BITS); + orig_num_after = nodep1->num_after; + + /* + * Add a new node to describe the bits starting at + * the split point. + */ + nodep1->num_after = offset; + nodep2 = node_add(s, idx); + + /* Move bits after the split point into the new node */ + nodep2->num_after = orig_num_after - offset; + if (nodep2->num_after >= MASK_BITS) { + nodep2->mask = ~(mask_t) 0; + nodep2->num_after -= MASK_BITS; + } else { + nodep2->mask = (1 << nodep2->num_after) - 1; + nodep2->num_after = 0; + } + + return nodep2; +} + +/* Iteratively reduces the node pointed to by nodep and its adjacent + * nodes into a more compact form. For example, a node with a mask with + * all bits set adjacent to a previous node, will get combined into a + * single node with an increased num_after setting. + * + * After each reduction, a further check is made to see if additional + * reductions are possible with the new previous and next nodes. Note, + * a search for a reduction is only done across the nodes nearest nodep + * and those that became part of a reduction. Reductions beyond nodep + * and the adjacent nodes that are reduced are not discovered. It is the + * responsibility of the caller to pass a nodep that is within one node + * of each possible reduction. + * + * This function does not fix the temporary violation of all invariants. + * For example it does not fix the case where the bit settings described + * by two or more nodes overlap. Such a violation introduces the potential + * complication of a bit setting for a specific index having different settings + * in different nodes. This would then introduce the further complication + * of which node has the correct setting of the bit and thus such conditions + * are not allowed. + * + * This function is designed to fix invariant violations that are introduced + * by node_split() and by changes to the nodes mask or num_after members. + * For example, when setting a bit within a nodes mask, the function that + * sets the bit doesn't have to worry about whether the setting of that + * bit caused the mask to have leading only or trailing only bits set. + * Instead, the function can call node_reduce(), with nodep equal to the + * node address that it set a mask bit in, and node_reduce() will notice + * the cases of leading or trailing only bits and that there is an + * adjacent node that the bit settings could be merged into. + * + * This implementation specifically detects and corrects violation of the + * following invariants: + * + * + Node are only used to represent bits that are set. + * Nodes with a mask of 0 and num_after of 0 are not allowed. + * + * + The setting of at least one bit is always described in a nodes + * mask (mask >= 1). + * + * + A node with all mask bits set only occurs when the last bit + * described by the previous node is not equal to this nodes + * starting index - 1. All such occurences of this condition are + * avoided by moving the setting of the nodes mask bits into + * the previous nodes num_after setting. + */ +static void node_reduce(struct sparsebit *s, struct node *nodep) +{ + bool reduction_performed; + + do { + reduction_performed = false; + struct node *prev, *next, *tmp; + + /* 1) Potential reductions within the current node. */ + + /* Nodes with all bits cleared may be removed. */ + if (nodep->mask == 0 && nodep->num_after == 0) { + /* + * About to remove the node pointed to by + * nodep, which normally would cause a problem + * for the next pass through the reduction loop, + * because the node at the starting point no longer + * exists. This potential problem is handled + * by first remembering the location of the next + * or previous nodes. Doesn't matter which, because + * once the node at nodep is removed, there will be + * no other nodes between prev and next. + * + * Note, the checks performed on nodep against both + * both prev and next both check for an adjacent + * node that can be reduced into a single node. As + * such, after removing the node at nodep, doesn't + * matter whether the nodep for the next pass + * through the loop is equal to the previous pass + * prev or next node. Either way, on the next pass + * the one not selected will become either the + * prev or next node. + */ + tmp = node_next(s, nodep); + if (!tmp) + tmp = node_prev(s, nodep); + + node_rm(s, nodep); + nodep = NULL; + + nodep = tmp; + reduction_performed = true; + continue; + } + + /* + * When the mask is 0, can reduce the amount of num_after + * bits by moving the initial num_after bits into the mask. + */ + if (nodep->mask == 0) { + assert(nodep->num_after != 0); + assert(nodep->idx + MASK_BITS > nodep->idx); + + nodep->idx += MASK_BITS; + + if (nodep->num_after >= MASK_BITS) { + nodep->mask = ~0; + nodep->num_after -= MASK_BITS; + } else { + nodep->mask = (1u << nodep->num_after) - 1; + nodep->num_after = 0; + } + + reduction_performed = true; + continue; + } + + /* + * 2) Potential reductions between the current and + * previous nodes. + */ + prev = node_prev(s, nodep); + if (prev) { + sparsebit_idx_t prev_highest_bit; + + /* Nodes with no bits set can be removed. */ + if (prev->mask == 0 && prev->num_after == 0) { + node_rm(s, prev); + + reduction_performed = true; + continue; + } + + /* + * All mask bits set and previous node has + * adjacent index. + */ + if (nodep->mask + 1 == 0 && + prev->idx + MASK_BITS == nodep->idx) { + prev->num_after += MASK_BITS + nodep->num_after; + nodep->mask = 0; + nodep->num_after = 0; + + reduction_performed = true; + continue; + } + + /* + * Is node adjacent to previous node and the node + * contains a single contiguous range of bits + * starting from the beginning of the mask? + */ + prev_highest_bit = prev->idx + MASK_BITS - 1 + prev->num_after; + if (prev_highest_bit + 1 == nodep->idx && + (nodep->mask | (nodep->mask >> 1)) == nodep->mask) { + /* + * How many contiguous bits are there? + * Is equal to the total number of set + * bits, due to an earlier check that + * there is a single contiguous range of + * set bits. + */ + unsigned int num_contiguous + = __builtin_popcount(nodep->mask); + assert((num_contiguous > 0) && + ((1ULL << num_contiguous) - 1) == nodep->mask); + + prev->num_after += num_contiguous; + nodep->mask = 0; + + /* + * For predictable performance, handle special + * case where all mask bits are set and there + * is a non-zero num_after setting. This code + * is functionally correct without the following + * conditionalized statements, but without them + * the value of num_after is only reduced by + * the number of mask bits per pass. There are + * cases where num_after can be close to 2^64. + * Without this code it could take nearly + * (2^64) / 32 passes to perform the full + * reduction. + */ + if (num_contiguous == MASK_BITS) { + prev->num_after += nodep->num_after; + nodep->num_after = 0; + } + + reduction_performed = true; + continue; + } + } + + /* + * 3) Potential reductions between the current and + * next nodes. + */ + next = node_next(s, nodep); + if (next) { + /* Nodes with no bits set can be removed. */ + if (next->mask == 0 && next->num_after == 0) { + node_rm(s, next); + reduction_performed = true; + continue; + } + + /* + * Is next node index adjacent to current node + * and has a mask with all bits set? + */ + if (next->idx == nodep->idx + MASK_BITS + nodep->num_after && + next->mask == ~(mask_t) 0) { + nodep->num_after += MASK_BITS; + next->mask = 0; + nodep->num_after += next->num_after; + next->num_after = 0; + + node_rm(s, next); + next = NULL; + + reduction_performed = true; + continue; + } + } + } while (nodep && reduction_performed); +} + +/* Returns whether the bit at the index given by idx, within the + * sparsebit array is set or not. + */ +bool sparsebit_is_set(struct sparsebit *s, sparsebit_idx_t idx) +{ + struct node *nodep; + + /* Find the node that describes the setting of the bit at idx */ + for (nodep = s->root; nodep; + nodep = nodep->idx > idx ? nodep->left : nodep->right) + if (idx >= nodep->idx && + idx <= nodep->idx + MASK_BITS + nodep->num_after - 1) + goto have_node; + + return false; + +have_node: + /* Bit is set if it is any of the bits described by num_after */ + if (nodep->num_after && idx >= nodep->idx + MASK_BITS) + return true; + + /* Is the corresponding mask bit set */ + assert(idx >= nodep->idx && idx - nodep->idx < MASK_BITS); + return !!(nodep->mask & (1 << (idx - nodep->idx))); +} + +/* Within the sparsebit array pointed to by s, sets the bit + * at the index given by idx. + */ +static void bit_set(struct sparsebit *s, sparsebit_idx_t idx) +{ + struct node *nodep; + + /* Skip bits that are already set */ + if (sparsebit_is_set(s, idx)) + return; + + /* + * Get a node where the bit at idx is described by the mask. + * The node_split will also create a node, if there isn't + * already a node that describes the setting of bit. + */ + nodep = node_split(s, idx & -MASK_BITS); + + /* Set the bit within the nodes mask */ + assert(idx >= nodep->idx && idx <= nodep->idx + MASK_BITS - 1); + assert(!(nodep->mask & (1 << (idx - nodep->idx)))); + nodep->mask |= 1 << (idx - nodep->idx); + s->num_set++; + + node_reduce(s, nodep); +} + +/* Within the sparsebit array pointed to by s, clears the bit + * at the index given by idx. + */ +static void bit_clear(struct sparsebit *s, sparsebit_idx_t idx) +{ + struct node *nodep; + + /* Skip bits that are already cleared */ + if (!sparsebit_is_set(s, idx)) + return; + + /* Is there a node that describes the setting of this bit? */ + nodep = node_find(s, idx); + if (!nodep) + return; + + /* + * If a num_after bit, split the node, so that the bit is + * part of a node mask. + */ + if (idx >= nodep->idx + MASK_BITS) + nodep = node_split(s, idx & -MASK_BITS); + + /* + * After node_split above, bit at idx should be within the mask. + * Clear that bit. + */ + assert(idx >= nodep->idx && idx <= nodep->idx + MASK_BITS - 1); + assert(nodep->mask & (1 << (idx - nodep->idx))); + nodep->mask &= ~(1 << (idx - nodep->idx)); + assert(s->num_set > 0 || sparsebit_all_set(s)); + s->num_set--; + + node_reduce(s, nodep); +} + +/* Recursively dumps to the FILE stream given by stream the contents + * of the sub-tree of nodes pointed to by nodep. Each line of output + * is prefixed by the number of spaces given by indent. On each + * recursion, the indent amount is increased by 2. This causes nodes + * at each level deeper into the binary search tree to be displayed + * with a greater indent. + */ +static void dump_nodes(FILE *stream, struct node *nodep, + unsigned int indent) +{ + char *node_type; + + /* Dump contents of node */ + if (!nodep->parent) + node_type = "root"; + else if (nodep == nodep->parent->left) + node_type = "left"; + else { + assert(nodep == nodep->parent->right); + node_type = "right"; + } + fprintf(stream, "%*s---- %s nodep: %p\n", indent, "", node_type, nodep); + fprintf(stream, "%*s parent: %p left: %p right: %p\n", indent, "", + nodep->parent, nodep->left, nodep->right); + fprintf(stream, "%*s idx: 0x%lx mask: 0x%x num_after: 0x%lx\n", + indent, "", nodep->idx, nodep->mask, nodep->num_after); + + /* If present, dump contents of left child nodes */ + if (nodep->left) + dump_nodes(stream, nodep->left, indent + 2); + + /* If present, dump contents of right child nodes */ + if (nodep->right) + dump_nodes(stream, nodep->right, indent + 2); +} + +static inline sparsebit_idx_t node_first_set(struct node *nodep, int start) +{ + mask_t leading = (mask_t)1 << start; + int n1 = __builtin_ctz(nodep->mask & -leading); + + return nodep->idx + n1; +} + +static inline sparsebit_idx_t node_first_clear(struct node *nodep, int start) +{ + mask_t leading = (mask_t)1 << start; + int n1 = __builtin_ctz(~nodep->mask & -leading); + + return nodep->idx + n1; +} + +/* Dumps to the FILE stream specified by stream, the implementation dependent + * internal state of s. Each line of output is prefixed with the number + * of spaces given by indent. The output is completely implementation + * dependent and subject to change. Output from this function should only + * be used for diagnostic purposes. For example, this function can be + * used by test cases after they detect an unexpected condition, as a means + * to capture diagnostic information. + */ +static void sparsebit_dump_internal(FILE *stream, struct sparsebit *s, + unsigned int indent) +{ + /* Dump the contents of s */ + fprintf(stream, "%*sroot: %p\n", indent, "", s->root); + fprintf(stream, "%*snum_set: 0x%lx\n", indent, "", s->num_set); + + if (s->root) + dump_nodes(stream, s->root, indent); +} + +/* Allocates and returns a new sparsebit array. The initial state + * of the newly allocated sparsebit array has all bits cleared. + */ +struct sparsebit *sparsebit_alloc(void) +{ + struct sparsebit *s; + + /* Allocate top level structure. */ + s = calloc(1, sizeof(*s)); + if (!s) { + perror("calloc"); + abort(); + } + + return s; +} + +/* Frees the implementation dependent data for the sparsebit array + * pointed to by s and poisons the pointer to that data. + */ +void sparsebit_free(struct sparsebit **sbitp) +{ + struct sparsebit *s = *sbitp; + + if (!s) + return; + + sparsebit_clear_all(s); + free(s); + *sbitp = NULL; +} + +/* Makes a copy of the sparsebit array given by s, to the sparsebit + * array given by d. Note, d must have already been allocated via + * sparsebit_alloc(). It can though already have bits set, which + * if different from src will be cleared. + */ +void sparsebit_copy(struct sparsebit *d, struct sparsebit *s) +{ + /* First clear any bits already set in the destination */ + sparsebit_clear_all(d); + + if (s->root) { + d->root = node_copy_subtree(s->root); + d->num_set = s->num_set; + } +} + +/* Returns whether num consecutive bits starting at idx are all set. */ +bool sparsebit_is_set_num(struct sparsebit *s, + sparsebit_idx_t idx, sparsebit_num_t num) +{ + sparsebit_idx_t next_cleared; + + assert(num > 0); + assert(idx + num - 1 >= idx); + + /* With num > 0, the first bit must be set. */ + if (!sparsebit_is_set(s, idx)) + return false; + + /* Find the next cleared bit */ + next_cleared = sparsebit_next_clear(s, idx); + + /* + * If no cleared bits beyond idx, then there are at least num + * set bits. idx + num doesn't wrap. Otherwise check if + * there are enough set bits between idx and the next cleared bit. + */ + return next_cleared == 0 || next_cleared - idx >= num; +} + +/* Returns whether the bit at the index given by idx. */ +bool sparsebit_is_clear(struct sparsebit *s, + sparsebit_idx_t idx) +{ + return !sparsebit_is_set(s, idx); +} + +/* Returns whether num consecutive bits starting at idx are all cleared. */ +bool sparsebit_is_clear_num(struct sparsebit *s, + sparsebit_idx_t idx, sparsebit_num_t num) +{ + sparsebit_idx_t next_set; + + assert(num > 0); + assert(idx + num - 1 >= idx); + + /* With num > 0, the first bit must be cleared. */ + if (!sparsebit_is_clear(s, idx)) + return false; + + /* Find the next set bit */ + next_set = sparsebit_next_set(s, idx); + + /* + * If no set bits beyond idx, then there are at least num + * cleared bits. idx + num doesn't wrap. Otherwise check if + * there are enough cleared bits between idx and the next set bit. + */ + return next_set == 0 || next_set - idx >= num; +} + +/* Returns the total number of bits set. Note: 0 is also returned for + * the case of all bits set. This is because with all bits set, there + * is 1 additional bit set beyond what can be represented in the return + * value. Use sparsebit_any_set(), instead of sparsebit_num_set() > 0, + * to determine if the sparsebit array has any bits set. + */ +sparsebit_num_t sparsebit_num_set(struct sparsebit *s) +{ + return s->num_set; +} + +/* Returns whether any bit is set in the sparsebit array. */ +bool sparsebit_any_set(struct sparsebit *s) +{ + /* + * Nodes only describe set bits. If any nodes then there + * is at least 1 bit set. + */ + if (!s->root) + return false; + + /* + * Every node should have a non-zero mask. For now will + * just assure that the root node has a non-zero mask, + * which is a quick check that at least 1 bit is set. + */ + assert(s->root->mask != 0); + assert(s->num_set > 0 || + (s->root->num_after == ((sparsebit_num_t) 0) - MASK_BITS && + s->root->mask == ~(mask_t) 0)); + + return true; +} + +/* Returns whether all the bits in the sparsebit array are cleared. */ +bool sparsebit_all_clear(struct sparsebit *s) +{ + return !sparsebit_any_set(s); +} + +/* Returns whether all the bits in the sparsebit array are set. */ +bool sparsebit_any_clear(struct sparsebit *s) +{ + return !sparsebit_all_set(s); +} + +/* Returns the index of the first set bit. Abort if no bits are set. + */ +sparsebit_idx_t sparsebit_first_set(struct sparsebit *s) +{ + struct node *nodep; + + /* Validate at least 1 bit is set */ + assert(sparsebit_any_set(s)); + + nodep = node_first(s); + return node_first_set(nodep, 0); +} + +/* Returns the index of the first cleared bit. Abort if + * no bits are cleared. + */ +sparsebit_idx_t sparsebit_first_clear(struct sparsebit *s) +{ + struct node *nodep1, *nodep2; + + /* Validate at least 1 bit is cleared. */ + assert(sparsebit_any_clear(s)); + + /* If no nodes or first node index > 0 then lowest cleared is 0 */ + nodep1 = node_first(s); + if (!nodep1 || nodep1->idx > 0) + return 0; + + /* Does the mask in the first node contain any cleared bits. */ + if (nodep1->mask != ~(mask_t) 0) + return node_first_clear(nodep1, 0); + + /* + * All mask bits set in first node. If there isn't a second node + * then the first cleared bit is the first bit after the bits + * described by the first node. + */ + nodep2 = node_next(s, nodep1); + if (!nodep2) { + /* + * No second node. First cleared bit is first bit beyond + * bits described by first node. + */ + assert(nodep1->mask == ~(mask_t) 0); + assert(nodep1->idx + MASK_BITS + nodep1->num_after != (sparsebit_idx_t) 0); + return nodep1->idx + MASK_BITS + nodep1->num_after; + } + + /* + * There is a second node. + * If it is not adjacent to the first node, then there is a gap + * of cleared bits between the nodes, and the first cleared bit + * is the first bit within the gap. + */ + if (nodep1->idx + MASK_BITS + nodep1->num_after != nodep2->idx) + return nodep1->idx + MASK_BITS + nodep1->num_after; + + /* + * Second node is adjacent to the first node. + * Because it is adjacent, its mask should be non-zero. If all + * its mask bits are set, then with it being adjacent, it should + * have had the mask bits moved into the num_after setting of the + * previous node. + */ + return node_first_clear(nodep2, 0); +} + +/* Returns index of next bit set within s after the index given by prev. + * Returns 0 if there are no bits after prev that are set. + */ +sparsebit_idx_t sparsebit_next_set(struct sparsebit *s, + sparsebit_idx_t prev) +{ + sparsebit_idx_t lowest_possible = prev + 1; + sparsebit_idx_t start; + struct node *nodep; + + /* A bit after the highest index can't be set. */ + if (lowest_possible == 0) + return 0; + + /* + * Find the leftmost 'candidate' overlapping or to the right + * of lowest_possible. + */ + struct node *candidate = NULL; + + /* True iff lowest_possible is within candidate */ + bool contains = false; + + /* + * Find node that describes setting of bit at lowest_possible. + * If such a node doesn't exist, find the node with the lowest + * starting index that is > lowest_possible. + */ + for (nodep = s->root; nodep;) { + if ((nodep->idx + MASK_BITS + nodep->num_after - 1) + >= lowest_possible) { + candidate = nodep; + if (candidate->idx <= lowest_possible) { + contains = true; + break; + } + nodep = nodep->left; + } else { + nodep = nodep->right; + } + } + if (!candidate) + return 0; + + assert(candidate->mask != 0); + + /* Does the candidate node describe the setting of lowest_possible? */ + if (!contains) { + /* + * Candidate doesn't describe setting of bit at lowest_possible. + * Candidate points to the first node with a starting index + * > lowest_possible. + */ + assert(candidate->idx > lowest_possible); + + return node_first_set(candidate, 0); + } + + /* + * Candidate describes setting of bit at lowest_possible. + * Note: although the node describes the setting of the bit + * at lowest_possible, its possible that its setting and the + * setting of all latter bits described by this node are 0. + * For now, just handle the cases where this node describes + * a bit at or after an index of lowest_possible that is set. + */ + start = lowest_possible - candidate->idx; + + if (start < MASK_BITS && candidate->mask >= (1 << start)) + return node_first_set(candidate, start); + + if (candidate->num_after) { + sparsebit_idx_t first_num_after_idx = candidate->idx + MASK_BITS; + + return lowest_possible < first_num_after_idx + ? first_num_after_idx : lowest_possible; + } + + /* + * Although candidate node describes setting of bit at + * the index of lowest_possible, all bits at that index and + * latter that are described by candidate are cleared. With + * this, the next bit is the first bit in the next node, if + * such a node exists. If a next node doesn't exist, then + * there is no next set bit. + */ + candidate = node_next(s, candidate); + if (!candidate) + return 0; + + return node_first_set(candidate, 0); +} + +/* Returns index of next bit cleared within s after the index given by prev. + * Returns 0 if there are no bits after prev that are cleared. + */ +sparsebit_idx_t sparsebit_next_clear(struct sparsebit *s, + sparsebit_idx_t prev) +{ + sparsebit_idx_t lowest_possible = prev + 1; + sparsebit_idx_t idx; + struct node *nodep1, *nodep2; + + /* A bit after the highest index can't be set. */ + if (lowest_possible == 0) + return 0; + + /* + * Does a node describing the setting of lowest_possible exist? + * If not, the bit at lowest_possible is cleared. + */ + nodep1 = node_find(s, lowest_possible); + if (!nodep1) + return lowest_possible; + + /* Does a mask bit in node 1 describe the next cleared bit. */ + for (idx = lowest_possible - nodep1->idx; idx < MASK_BITS; idx++) + if (!(nodep1->mask & (1 << idx))) + return nodep1->idx + idx; + + /* + * Next cleared bit is not described by node 1. If there + * isn't a next node, then next cleared bit is described + * by bit after the bits described by the first node. + */ + nodep2 = node_next(s, nodep1); + if (!nodep2) + return nodep1->idx + MASK_BITS + nodep1->num_after; + + /* + * There is a second node. + * If it is not adjacent to the first node, then there is a gap + * of cleared bits between the nodes, and the next cleared bit + * is the first bit within the gap. + */ + if (nodep1->idx + MASK_BITS + nodep1->num_after != nodep2->idx) + return nodep1->idx + MASK_BITS + nodep1->num_after; + + /* + * Second node is adjacent to the first node. + * Because it is adjacent, its mask should be non-zero. If all + * its mask bits are set, then with it being adjacent, it should + * have had the mask bits moved into the num_after setting of the + * previous node. + */ + return node_first_clear(nodep2, 0); +} + +/* Starting with the index 1 greater than the index given by start, finds + * and returns the index of the first sequence of num consecutively set + * bits. Returns a value of 0 of no such sequence exists. + */ +sparsebit_idx_t sparsebit_next_set_num(struct sparsebit *s, + sparsebit_idx_t start, sparsebit_num_t num) +{ + sparsebit_idx_t idx; + + assert(num >= 1); + + for (idx = sparsebit_next_set(s, start); + idx != 0 && idx + num - 1 >= idx; + idx = sparsebit_next_set(s, idx)) { + assert(sparsebit_is_set(s, idx)); + + /* + * Does the sequence of bits starting at idx consist of + * num set bits? + */ + if (sparsebit_is_set_num(s, idx, num)) + return idx; + + /* + * Sequence of set bits at idx isn't large enough. + * Skip this entire sequence of set bits. + */ + idx = sparsebit_next_clear(s, idx); + if (idx == 0) + return 0; + } + + return 0; +} + +/* Starting with the index 1 greater than the index given by start, finds + * and returns the index of the first sequence of num consecutively cleared + * bits. Returns a value of 0 of no such sequence exists. + */ +sparsebit_idx_t sparsebit_next_clear_num(struct sparsebit *s, + sparsebit_idx_t start, sparsebit_num_t num) +{ + sparsebit_idx_t idx; + + assert(num >= 1); + + for (idx = sparsebit_next_clear(s, start); + idx != 0 && idx + num - 1 >= idx; + idx = sparsebit_next_clear(s, idx)) { + assert(sparsebit_is_clear(s, idx)); + + /* + * Does the sequence of bits starting at idx consist of + * num cleared bits? + */ + if (sparsebit_is_clear_num(s, idx, num)) + return idx; + + /* + * Sequence of cleared bits at idx isn't large enough. + * Skip this entire sequence of cleared bits. + */ + idx = sparsebit_next_set(s, idx); + if (idx == 0) + return 0; + } + + return 0; +} + +/* Sets the bits * in the inclusive range idx through idx + num - 1. */ +void sparsebit_set_num(struct sparsebit *s, + sparsebit_idx_t start, sparsebit_num_t num) +{ + struct node *nodep, *next; + unsigned int n1; + sparsebit_idx_t idx; + sparsebit_num_t n; + sparsebit_idx_t middle_start, middle_end; + + assert(num > 0); + assert(start + num - 1 >= start); + + /* + * Leading - bits before first mask boundary. + * + * TODO(lhuemill): With some effort it may be possible to + * replace the following loop with a sequential sequence + * of statements. High level sequence would be: + * + * 1. Use node_split() to force node that describes setting + * of idx to be within the mask portion of a node. + * 2. Form mask of bits to be set. + * 3. Determine number of mask bits already set in the node + * and store in a local variable named num_already_set. + * 4. Set the appropriate mask bits within the node. + * 5. Increment struct sparsebit_pvt num_set member + * by the number of bits that were actually set. + * Exclude from the counts bits that were already set. + * 6. Before returning to the caller, use node_reduce() to + * handle the multiple corner cases that this method + * introduces. + */ + for (idx = start, n = num; n > 0 && idx % MASK_BITS != 0; idx++, n--) + bit_set(s, idx); + + /* Middle - bits spanning one or more entire mask */ + middle_start = idx; + middle_end = middle_start + (n & -MASK_BITS) - 1; + if (n >= MASK_BITS) { + nodep = node_split(s, middle_start); + + /* + * As needed, split just after end of middle bits. + * No split needed if end of middle bits is at highest + * supported bit index. + */ + if (middle_end + 1 > middle_end) + (void) node_split(s, middle_end + 1); + + /* Delete nodes that only describe bits within the middle. */ + for (next = node_next(s, nodep); + next && (next->idx < middle_end); + next = node_next(s, nodep)) { + assert(next->idx + MASK_BITS + next->num_after - 1 <= middle_end); + node_rm(s, next); + next = NULL; + } + + /* As needed set each of the mask bits */ + for (n1 = 0; n1 < MASK_BITS; n1++) { + if (!(nodep->mask & (1 << n1))) { + nodep->mask |= 1 << n1; + s->num_set++; + } + } + + s->num_set -= nodep->num_after; + nodep->num_after = middle_end - middle_start + 1 - MASK_BITS; + s->num_set += nodep->num_after; + + node_reduce(s, nodep); + } + idx = middle_end + 1; + n -= middle_end - middle_start + 1; + + /* Trailing - bits at and beyond last mask boundary */ + assert(n < MASK_BITS); + for (; n > 0; idx++, n--) + bit_set(s, idx); +} + +/* Clears the bits * in the inclusive range idx through idx + num - 1. */ +void sparsebit_clear_num(struct sparsebit *s, + sparsebit_idx_t start, sparsebit_num_t num) +{ + struct node *nodep, *next; + unsigned int n1; + sparsebit_idx_t idx; + sparsebit_num_t n; + sparsebit_idx_t middle_start, middle_end; + + assert(num > 0); + assert(start + num - 1 >= start); + + /* Leading - bits before first mask boundary */ + for (idx = start, n = num; n > 0 && idx % MASK_BITS != 0; idx++, n--) + bit_clear(s, idx); + + /* Middle - bits spanning one or more entire mask */ + middle_start = idx; + middle_end = middle_start + (n & -MASK_BITS) - 1; + if (n >= MASK_BITS) { + nodep = node_split(s, middle_start); + + /* + * As needed, split just after end of middle bits. + * No split needed if end of middle bits is at highest + * supported bit index. + */ + if (middle_end + 1 > middle_end) + (void) node_split(s, middle_end + 1); + + /* Delete nodes that only describe bits within the middle. */ + for (next = node_next(s, nodep); + next && (next->idx < middle_end); + next = node_next(s, nodep)) { + assert(next->idx + MASK_BITS + next->num_after - 1 <= middle_end); + node_rm(s, next); + next = NULL; + } + + /* As needed clear each of the mask bits */ + for (n1 = 0; n1 < MASK_BITS; n1++) { + if (nodep->mask & (1 << n1)) { + nodep->mask &= ~(1 << n1); + s->num_set--; + } + } + + /* Clear any bits described by num_after */ + s->num_set -= nodep->num_after; + nodep->num_after = 0; + + /* + * Delete the node that describes the beginning of + * the middle bits and perform any allowed reductions + * with the nodes prev or next of nodep. + */ + node_reduce(s, nodep); + nodep = NULL; + } + idx = middle_end + 1; + n -= middle_end - middle_start + 1; + + /* Trailing - bits at and beyond last mask boundary */ + assert(n < MASK_BITS); + for (; n > 0; idx++, n--) + bit_clear(s, idx); +} + +/* Sets the bit at the index given by idx. */ +void sparsebit_set(struct sparsebit *s, sparsebit_idx_t idx) +{ + sparsebit_set_num(s, idx, 1); +} + +/* Clears the bit at the index given by idx. */ +void sparsebit_clear(struct sparsebit *s, sparsebit_idx_t idx) +{ + sparsebit_clear_num(s, idx, 1); +} + +/* Sets the bits in the entire addressable range of the sparsebit array. */ +void sparsebit_set_all(struct sparsebit *s) +{ + sparsebit_set(s, 0); + sparsebit_set_num(s, 1, ~(sparsebit_idx_t) 0); + assert(sparsebit_all_set(s)); +} + +/* Clears the bits in the entire addressable range of the sparsebit array. */ +void sparsebit_clear_all(struct sparsebit *s) +{ + sparsebit_clear(s, 0); + sparsebit_clear_num(s, 1, ~(sparsebit_idx_t) 0); + assert(!sparsebit_any_set(s)); +} + +static size_t display_range(FILE *stream, sparsebit_idx_t low, + sparsebit_idx_t high, bool prepend_comma_space) +{ + char *fmt_str; + size_t sz; + + /* Determine the printf format string */ + if (low == high) + fmt_str = prepend_comma_space ? ", 0x%lx" : "0x%lx"; + else + fmt_str = prepend_comma_space ? ", 0x%lx:0x%lx" : "0x%lx:0x%lx"; + + /* + * When stream is NULL, just determine the size of what would + * have been printed, else print the range. + */ + if (!stream) + sz = snprintf(NULL, 0, fmt_str, low, high); + else + sz = fprintf(stream, fmt_str, low, high); + + return sz; +} + + +/* Dumps to the FILE stream given by stream, the bit settings + * of s. Each line of output is prefixed with the number of + * spaces given by indent. The length of each line is implementation + * dependent and does not depend on the indent amount. The following + * is an example output of a sparsebit array that has bits: + * + * 0x5, 0x8, 0xa:0xe, 0x12 + * + * This corresponds to a sparsebit whose bits 5, 8, 10, 11, 12, 13, 14, 18 + * are set. Note that a ':', instead of a '-' is used to specify a range of + * contiguous bits. This is done because '-' is used to specify command-line + * options, and sometimes ranges are specified as command-line arguments. + */ +void sparsebit_dump(FILE *stream, struct sparsebit *s, + unsigned int indent) +{ + size_t current_line_len = 0; + size_t sz; + struct node *nodep; + + if (!sparsebit_any_set(s)) + return; + + /* Display initial indent */ + fprintf(stream, "%*s", indent, ""); + + /* For each node */ + for (nodep = node_first(s); nodep; nodep = node_next(s, nodep)) { + unsigned int n1; + sparsebit_idx_t low, high; + + /* For each group of bits in the mask */ + for (n1 = 0; n1 < MASK_BITS; n1++) { + if (nodep->mask & (1 << n1)) { + low = high = nodep->idx + n1; + + for (; n1 < MASK_BITS; n1++) { + if (nodep->mask & (1 << n1)) + high = nodep->idx + n1; + else + break; + } + + if ((n1 == MASK_BITS) && nodep->num_after) + high += nodep->num_after; + + /* + * How much room will it take to display + * this range. + */ + sz = display_range(NULL, low, high, + current_line_len != 0); + + /* + * If there is not enough room, display + * a newline plus the indent of the next + * line. + */ + if (current_line_len + sz > DUMP_LINE_MAX) { + fputs("\n", stream); + fprintf(stream, "%*s", indent, ""); + current_line_len = 0; + } + + /* Display the range */ + sz = display_range(stream, low, high, + current_line_len != 0); + current_line_len += sz; + } + } + + /* + * If num_after and most significant-bit of mask is not + * set, then still need to display a range for the bits + * described by num_after. + */ + if (!(nodep->mask & (1 << (MASK_BITS - 1))) && nodep->num_after) { + low = nodep->idx + MASK_BITS; + high = nodep->idx + MASK_BITS + nodep->num_after - 1; + + /* + * How much room will it take to display + * this range. + */ + sz = display_range(NULL, low, high, + current_line_len != 0); + + /* + * If there is not enough room, display + * a newline plus the indent of the next + * line. + */ + if (current_line_len + sz > DUMP_LINE_MAX) { + fputs("\n", stream); + fprintf(stream, "%*s", indent, ""); + current_line_len = 0; + } + + /* Display the range */ + sz = display_range(stream, low, high, + current_line_len != 0); + current_line_len += sz; + } + } + fputs("\n", stream); +} + +/* Validates the internal state of the sparsebit array given by + * s. On error, diagnostic information is printed to stderr and + * abort is called. + */ +void sparsebit_validate_internal(struct sparsebit *s) +{ + bool error_detected = false; + struct node *nodep, *prev = NULL; + sparsebit_num_t total_bits_set = 0; + unsigned int n1; + + /* For each node */ + for (nodep = node_first(s); nodep; + prev = nodep, nodep = node_next(s, nodep)) { + + /* + * Increase total bits set by the number of bits set + * in this node. + */ + for (n1 = 0; n1 < MASK_BITS; n1++) + if (nodep->mask & (1 << n1)) + total_bits_set++; + + total_bits_set += nodep->num_after; + + /* + * Arbitrary choice as to whether a mask of 0 is allowed + * or not. For diagnostic purposes it is beneficial to + * have only one valid means to represent a set of bits. + * To support this an arbitrary choice has been made + * to not allow a mask of zero. + */ + if (nodep->mask == 0) { + fprintf(stderr, "Node mask of zero, " + "nodep: %p nodep->mask: 0x%x", + nodep, nodep->mask); + error_detected = true; + break; + } + + /* + * Validate num_after is not greater than the max index + * - the number of mask bits. The num_after member + * uses 0-based indexing and thus has no value that + * represents all bits set. This limitation is handled + * by requiring a non-zero mask. With a non-zero mask, + * MASK_BITS worth of bits are described by the mask, + * which makes the largest needed num_after equal to: + * + * (~(sparsebit_num_t) 0) - MASK_BITS + 1 + */ + if (nodep->num_after + > (~(sparsebit_num_t) 0) - MASK_BITS + 1) { + fprintf(stderr, "num_after too large, " + "nodep: %p nodep->num_after: 0x%lx", + nodep, nodep->num_after); + error_detected = true; + break; + } + + /* Validate node index is divisible by the mask size */ + if (nodep->idx % MASK_BITS) { + fprintf(stderr, "Node index not divisable by " + "mask size,\n" + " nodep: %p nodep->idx: 0x%lx " + "MASK_BITS: %lu\n", + nodep, nodep->idx, MASK_BITS); + error_detected = true; + break; + } + + /* + * Validate bits described by node don't wrap beyond the + * highest supported index. + */ + if ((nodep->idx + MASK_BITS + nodep->num_after - 1) < nodep->idx) { + fprintf(stderr, "Bits described by node wrap " + "beyond highest supported index,\n" + " nodep: %p nodep->idx: 0x%lx\n" + " MASK_BITS: %lu nodep->num_after: 0x%lx", + nodep, nodep->idx, MASK_BITS, nodep->num_after); + error_detected = true; + break; + } + + /* Check parent pointers. */ + if (nodep->left) { + if (nodep->left->parent != nodep) { + fprintf(stderr, "Left child parent pointer " + "doesn't point to this node,\n" + " nodep: %p nodep->left: %p " + "nodep->left->parent: %p", + nodep, nodep->left, + nodep->left->parent); + error_detected = true; + break; + } + } + + if (nodep->right) { + if (nodep->right->parent != nodep) { + fprintf(stderr, "Right child parent pointer " + "doesn't point to this node,\n" + " nodep: %p nodep->right: %p " + "nodep->right->parent: %p", + nodep, nodep->right, + nodep->right->parent); + error_detected = true; + break; + } + } + + if (!nodep->parent) { + if (s->root != nodep) { + fprintf(stderr, "Unexpected root node, " + "s->root: %p nodep: %p", + s->root, nodep); + error_detected = true; + break; + } + } + + if (prev) { + /* + * Is index of previous node before index of + * current node? + */ + if (prev->idx >= nodep->idx) { + fprintf(stderr, "Previous node index " + ">= current node index,\n" + " prev: %p prev->idx: 0x%lx\n" + " nodep: %p nodep->idx: 0x%lx", + prev, prev->idx, nodep, nodep->idx); + error_detected = true; + break; + } + + /* + * Nodes occur in asscending order, based on each + * nodes starting index. + */ + if ((prev->idx + MASK_BITS + prev->num_after - 1) + >= nodep->idx) { + fprintf(stderr, "Previous node bit range " + "overlap with current node bit range,\n" + " prev: %p prev->idx: 0x%lx " + "prev->num_after: 0x%lx\n" + " nodep: %p nodep->idx: 0x%lx " + "nodep->num_after: 0x%lx\n" + " MASK_BITS: %lu", + prev, prev->idx, prev->num_after, + nodep, nodep->idx, nodep->num_after, + MASK_BITS); + error_detected = true; + break; + } + + /* + * When the node has all mask bits set, it shouldn't + * be adjacent to the last bit described by the + * previous node. + */ + if (nodep->mask == ~(mask_t) 0 && + prev->idx + MASK_BITS + prev->num_after == nodep->idx) { + fprintf(stderr, "Current node has mask with " + "all bits set and is adjacent to the " + "previous node,\n" + " prev: %p prev->idx: 0x%lx " + "prev->num_after: 0x%lx\n" + " nodep: %p nodep->idx: 0x%lx " + "nodep->num_after: 0x%lx\n" + " MASK_BITS: %lu", + prev, prev->idx, prev->num_after, + nodep, nodep->idx, nodep->num_after, + MASK_BITS); + + error_detected = true; + break; + } + } + } + + if (!error_detected) { + /* + * Is sum of bits set in each node equal to the count + * of total bits set. + */ + if (s->num_set != total_bits_set) { + fprintf(stderr, "Number of bits set missmatch,\n" + " s->num_set: 0x%lx total_bits_set: 0x%lx", + s->num_set, total_bits_set); + + error_detected = true; + } + } + + if (error_detected) { + fputs(" dump_internal:\n", stderr); + sparsebit_dump_internal(stderr, s, 4); + abort(); + } +} + + +#ifdef FUZZ +/* A simple but effective fuzzing driver. Look for bugs with the help + * of some invariants and of a trivial representation of sparsebit. + * Just use 512 bytes of /dev/zero and /dev/urandom as inputs, and let + * afl-fuzz do the magic. :) + */ + +#include +#include + +struct range { + sparsebit_idx_t first, last; + bool set; +}; + +struct sparsebit *s; +struct range ranges[1000]; +int num_ranges; + +static bool get_value(sparsebit_idx_t idx) +{ + int i; + + for (i = num_ranges; --i >= 0; ) + if (ranges[i].first <= idx && idx <= ranges[i].last) + return ranges[i].set; + + return false; +} + +static void operate(int code, sparsebit_idx_t first, sparsebit_idx_t last) +{ + sparsebit_num_t num; + sparsebit_idx_t next; + + if (first < last) { + num = last - first + 1; + } else { + num = first - last + 1; + first = last; + last = first + num - 1; + } + + switch (code) { + case 0: + sparsebit_set(s, first); + assert(sparsebit_is_set(s, first)); + assert(!sparsebit_is_clear(s, first)); + assert(sparsebit_any_set(s)); + assert(!sparsebit_all_clear(s)); + if (get_value(first)) + return; + if (num_ranges == 1000) + exit(0); + ranges[num_ranges++] = (struct range) + { .first = first, .last = first, .set = true }; + break; + case 1: + sparsebit_clear(s, first); + assert(!sparsebit_is_set(s, first)); + assert(sparsebit_is_clear(s, first)); + assert(sparsebit_any_clear(s)); + assert(!sparsebit_all_set(s)); + if (!get_value(first)) + return; + if (num_ranges == 1000) + exit(0); + ranges[num_ranges++] = (struct range) + { .first = first, .last = first, .set = false }; + break; + case 2: + assert(sparsebit_is_set(s, first) == get_value(first)); + assert(sparsebit_is_clear(s, first) == !get_value(first)); + break; + case 3: + if (sparsebit_any_set(s)) + assert(get_value(sparsebit_first_set(s))); + if (sparsebit_any_clear(s)) + assert(!get_value(sparsebit_first_clear(s))); + sparsebit_set_all(s); + assert(!sparsebit_any_clear(s)); + assert(sparsebit_all_set(s)); + num_ranges = 0; + ranges[num_ranges++] = (struct range) + { .first = 0, .last = ~(sparsebit_idx_t)0, .set = true }; + break; + case 4: + if (sparsebit_any_set(s)) + assert(get_value(sparsebit_first_set(s))); + if (sparsebit_any_clear(s)) + assert(!get_value(sparsebit_first_clear(s))); + sparsebit_clear_all(s); + assert(!sparsebit_any_set(s)); + assert(sparsebit_all_clear(s)); + num_ranges = 0; + break; + case 5: + next = sparsebit_next_set(s, first); + assert(next == 0 || next > first); + assert(next == 0 || get_value(next)); + break; + case 6: + next = sparsebit_next_clear(s, first); + assert(next == 0 || next > first); + assert(next == 0 || !get_value(next)); + break; + case 7: + next = sparsebit_next_clear(s, first); + if (sparsebit_is_set_num(s, first, num)) { + assert(next == 0 || next > last); + if (first) + next = sparsebit_next_set(s, first - 1); + else if (sparsebit_any_set(s)) + next = sparsebit_first_set(s); + else + return; + assert(next == first); + } else { + assert(sparsebit_is_clear(s, first) || next <= last); + } + break; + case 8: + next = sparsebit_next_set(s, first); + if (sparsebit_is_clear_num(s, first, num)) { + assert(next == 0 || next > last); + if (first) + next = sparsebit_next_clear(s, first - 1); + else if (sparsebit_any_clear(s)) + next = sparsebit_first_clear(s); + else + return; + assert(next == first); + } else { + assert(sparsebit_is_set(s, first) || next <= last); + } + break; + case 9: + sparsebit_set_num(s, first, num); + assert(sparsebit_is_set_num(s, first, num)); + assert(!sparsebit_is_clear_num(s, first, num)); + assert(sparsebit_any_set(s)); + assert(!sparsebit_all_clear(s)); + if (num_ranges == 1000) + exit(0); + ranges[num_ranges++] = (struct range) + { .first = first, .last = last, .set = true }; + break; + case 10: + sparsebit_clear_num(s, first, num); + assert(!sparsebit_is_set_num(s, first, num)); + assert(sparsebit_is_clear_num(s, first, num)); + assert(sparsebit_any_clear(s)); + assert(!sparsebit_all_set(s)); + if (num_ranges == 1000) + exit(0); + ranges[num_ranges++] = (struct range) + { .first = first, .last = last, .set = false }; + break; + case 11: + sparsebit_validate_internal(s); + break; + default: + break; + } +} + +unsigned char get8(void) +{ + int ch; + + ch = getchar(); + if (ch == EOF) + exit(0); + return ch; +} + +uint64_t get64(void) +{ + uint64_t x; + + x = get8(); + x = (x << 8) | get8(); + x = (x << 8) | get8(); + x = (x << 8) | get8(); + x = (x << 8) | get8(); + x = (x << 8) | get8(); + x = (x << 8) | get8(); + return (x << 8) | get8(); +} + +int main(void) +{ + s = sparsebit_alloc(); + for (;;) { + uint8_t op = get8() & 0xf; + uint64_t first = get64(); + uint64_t last = get64(); + + operate(op, first, last); + } +} +#endif diff --git a/tools/testing/selftests/kvm/lib/x86.c b/tools/testing/selftests/kvm/lib/x86.c new file mode 100644 index 000000000000..12df46280b23 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/x86.c @@ -0,0 +1,697 @@ +/* + * tools/testing/selftests/kvm/lib/x86.c + * + * Copyright (C) 2018, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#define _GNU_SOURCE /* for program_invocation_name */ + +#include "test_util.h" +#include "kvm_util.h" +#include "kvm_util_internal.h" +#include "x86.h" + +/* Minimum physical address used for virtual translation tables. */ +#define KVM_GUEST_PAGE_TABLE_MIN_PADDR 0x180000 + +/* Virtual translation table structure declarations */ +struct pageMapL4Entry { + uint64_t present:1; + uint64_t writable:1; + uint64_t user:1; + uint64_t write_through:1; + uint64_t cache_disable:1; + uint64_t accessed:1; + uint64_t ignored_06:1; + uint64_t page_size:1; + uint64_t ignored_11_08:4; + uint64_t address:40; + uint64_t ignored_62_52:11; + uint64_t execute_disable:1; +}; + +struct pageDirectoryPointerEntry { + uint64_t present:1; + uint64_t writable:1; + uint64_t user:1; + uint64_t write_through:1; + uint64_t cache_disable:1; + uint64_t accessed:1; + uint64_t ignored_06:1; + uint64_t page_size:1; + uint64_t ignored_11_08:4; + uint64_t address:40; + uint64_t ignored_62_52:11; + uint64_t execute_disable:1; +}; + +struct pageDirectoryEntry { + uint64_t present:1; + uint64_t writable:1; + uint64_t user:1; + uint64_t write_through:1; + uint64_t cache_disable:1; + uint64_t accessed:1; + uint64_t ignored_06:1; + uint64_t page_size:1; + uint64_t ignored_11_08:4; + uint64_t address:40; + uint64_t ignored_62_52:11; + uint64_t execute_disable:1; +}; + +struct pageTableEntry { + uint64_t present:1; + uint64_t writable:1; + uint64_t user:1; + uint64_t write_through:1; + uint64_t cache_disable:1; + uint64_t accessed:1; + uint64_t dirty:1; + uint64_t reserved_07:1; + uint64_t global:1; + uint64_t ignored_11_09:3; + uint64_t address:40; + uint64_t ignored_62_52:11; + uint64_t execute_disable:1; +}; + +/* Register Dump + * + * Input Args: + * indent - Left margin indent amount + * regs - register + * + * Output Args: + * stream - Output FILE stream + * + * Return: None + * + * Dumps the state of the registers given by regs, to the FILE stream + * given by steam. + */ +void regs_dump(FILE *stream, struct kvm_regs *regs, + uint8_t indent) +{ + fprintf(stream, "%*srax: 0x%.16llx rbx: 0x%.16llx " + "rcx: 0x%.16llx rdx: 0x%.16llx\n", + indent, "", + regs->rax, regs->rbx, regs->rcx, regs->rdx); + fprintf(stream, "%*srsi: 0x%.16llx rdi: 0x%.16llx " + "rsp: 0x%.16llx rbp: 0x%.16llx\n", + indent, "", + regs->rsi, regs->rdi, regs->rsp, regs->rbp); + fprintf(stream, "%*sr8: 0x%.16llx r9: 0x%.16llx " + "r10: 0x%.16llx r11: 0x%.16llx\n", + indent, "", + regs->r8, regs->r9, regs->r10, regs->r11); + fprintf(stream, "%*sr12: 0x%.16llx r13: 0x%.16llx " + "r14: 0x%.16llx r15: 0x%.16llx\n", + indent, "", + regs->r12, regs->r13, regs->r14, regs->r15); + fprintf(stream, "%*srip: 0x%.16llx rfl: 0x%.16llx\n", + indent, "", + regs->rip, regs->rflags); +} + +/* Segment Dump + * + * Input Args: + * indent - Left margin indent amount + * segment - KVM segment + * + * Output Args: + * stream - Output FILE stream + * + * Return: None + * + * Dumps the state of the KVM segment given by segment, to the FILE stream + * given by steam. + */ +static void segment_dump(FILE *stream, struct kvm_segment *segment, + uint8_t indent) +{ + fprintf(stream, "%*sbase: 0x%.16llx limit: 0x%.8x " + "selector: 0x%.4x type: 0x%.2x\n", + indent, "", segment->base, segment->limit, + segment->selector, segment->type); + fprintf(stream, "%*spresent: 0x%.2x dpl: 0x%.2x " + "db: 0x%.2x s: 0x%.2x l: 0x%.2x\n", + indent, "", segment->present, segment->dpl, + segment->db, segment->s, segment->l); + fprintf(stream, "%*sg: 0x%.2x avl: 0x%.2x " + "unusable: 0x%.2x padding: 0x%.2x\n", + indent, "", segment->g, segment->avl, + segment->unusable, segment->padding); +} + +/* dtable Dump + * + * Input Args: + * indent - Left margin indent amount + * dtable - KVM dtable + * + * Output Args: + * stream - Output FILE stream + * + * Return: None + * + * Dumps the state of the KVM dtable given by dtable, to the FILE stream + * given by steam. + */ +static void dtable_dump(FILE *stream, struct kvm_dtable *dtable, + uint8_t indent) +{ + fprintf(stream, "%*sbase: 0x%.16llx limit: 0x%.4x " + "padding: 0x%.4x 0x%.4x 0x%.4x\n", + indent, "", dtable->base, dtable->limit, + dtable->padding[0], dtable->padding[1], dtable->padding[2]); +} + +/* System Register Dump + * + * Input Args: + * indent - Left margin indent amount + * sregs - System registers + * + * Output Args: + * stream - Output FILE stream + * + * Return: None + * + * Dumps the state of the system registers given by sregs, to the FILE stream + * given by steam. + */ +void sregs_dump(FILE *stream, struct kvm_sregs *sregs, + uint8_t indent) +{ + unsigned int i; + + fprintf(stream, "%*scs:\n", indent, ""); + segment_dump(stream, &sregs->cs, indent + 2); + fprintf(stream, "%*sds:\n", indent, ""); + segment_dump(stream, &sregs->ds, indent + 2); + fprintf(stream, "%*ses:\n", indent, ""); + segment_dump(stream, &sregs->es, indent + 2); + fprintf(stream, "%*sfs:\n", indent, ""); + segment_dump(stream, &sregs->fs, indent + 2); + fprintf(stream, "%*sgs:\n", indent, ""); + segment_dump(stream, &sregs->gs, indent + 2); + fprintf(stream, "%*sss:\n", indent, ""); + segment_dump(stream, &sregs->ss, indent + 2); + fprintf(stream, "%*str:\n", indent, ""); + segment_dump(stream, &sregs->tr, indent + 2); + fprintf(stream, "%*sldt:\n", indent, ""); + segment_dump(stream, &sregs->ldt, indent + 2); + + fprintf(stream, "%*sgdt:\n", indent, ""); + dtable_dump(stream, &sregs->gdt, indent + 2); + fprintf(stream, "%*sidt:\n", indent, ""); + dtable_dump(stream, &sregs->idt, indent + 2); + + fprintf(stream, "%*scr0: 0x%.16llx cr2: 0x%.16llx " + "cr3: 0x%.16llx cr4: 0x%.16llx\n", + indent, "", + sregs->cr0, sregs->cr2, sregs->cr3, sregs->cr4); + fprintf(stream, "%*scr8: 0x%.16llx efer: 0x%.16llx " + "apic_base: 0x%.16llx\n", + indent, "", + sregs->cr8, sregs->efer, sregs->apic_base); + + fprintf(stream, "%*sinterrupt_bitmap:\n", indent, ""); + for (i = 0; i < (KVM_NR_INTERRUPTS + 63) / 64; i++) { + fprintf(stream, "%*s%.16llx\n", indent + 2, "", + sregs->interrupt_bitmap[i]); + } +} + +void virt_pgd_alloc(struct kvm_vm *vm, uint32_t pgd_memslot) +{ + int rc; + + TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " + "unknown or unsupported guest mode, mode: 0x%x", vm->mode); + + /* If needed, create page map l4 table. */ + if (!vm->pgd_created) { + vm_paddr_t paddr = vm_phy_page_alloc(vm, + KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot); + vm->pgd = paddr; + + /* Set pointer to pgd tables in all the VCPUs that + * have already been created. Future VCPUs will have + * the value set as each one is created. + */ + for (struct vcpu *vcpu = vm->vcpu_head; vcpu; + vcpu = vcpu->next) { + struct kvm_sregs sregs; + + /* Obtain the current system register settings */ + vcpu_sregs_get(vm, vcpu->id, &sregs); + + /* Set and store the pointer to the start of the + * pgd tables. + */ + sregs.cr3 = vm->pgd; + vcpu_sregs_set(vm, vcpu->id, &sregs); + } + + vm->pgd_created = true; + } +} + +/* VM Virtual Page Map + * + * Input Args: + * vm - Virtual Machine + * vaddr - VM Virtual Address + * paddr - VM Physical Address + * pgd_memslot - Memory region slot for new virtual translation tables + * + * Output Args: None + * + * Return: None + * + * Within the VM given by vm, creates a virtual translation for the page + * starting at vaddr to the page starting at paddr. + */ +void virt_pg_map(struct kvm_vm *vm, uint64_t vaddr, uint64_t paddr, + uint32_t pgd_memslot) +{ + uint16_t index[4]; + struct pageMapL4Entry *pml4e; + + TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " + "unknown or unsupported guest mode, mode: 0x%x", vm->mode); + + TEST_ASSERT((vaddr % vm->page_size) == 0, + "Virtual address not on page boundary,\n" + " vaddr: 0x%lx vm->page_size: 0x%x", + vaddr, vm->page_size); + TEST_ASSERT(sparsebit_is_set(vm->vpages_valid, + (vaddr >> vm->page_shift)), + "Invalid virtual address, vaddr: 0x%lx", + vaddr); + TEST_ASSERT((paddr % vm->page_size) == 0, + "Physical address not on page boundary,\n" + " paddr: 0x%lx vm->page_size: 0x%x", + paddr, vm->page_size); + TEST_ASSERT((paddr >> vm->page_shift) <= vm->max_gfn, + "Physical address beyond beyond maximum supported,\n" + " paddr: 0x%lx vm->max_gfn: 0x%lx vm->page_size: 0x%x", + paddr, vm->max_gfn, vm->page_size); + + index[0] = (vaddr >> 12) & 0x1ffu; + index[1] = (vaddr >> 21) & 0x1ffu; + index[2] = (vaddr >> 30) & 0x1ffu; + index[3] = (vaddr >> 39) & 0x1ffu; + + /* Allocate page directory pointer table if not present. */ + pml4e = addr_gpa2hva(vm, vm->pgd); + if (!pml4e[index[3]].present) { + pml4e[index[3]].address = vm_phy_page_alloc(vm, + KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot) + >> vm->page_shift; + pml4e[index[3]].writable = true; + pml4e[index[3]].present = true; + } + + /* Allocate page directory table if not present. */ + struct pageDirectoryPointerEntry *pdpe; + pdpe = addr_gpa2hva(vm, pml4e[index[3]].address * vm->page_size); + if (!pdpe[index[2]].present) { + pdpe[index[2]].address = vm_phy_page_alloc(vm, + KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot) + >> vm->page_shift; + pdpe[index[2]].writable = true; + pdpe[index[2]].present = true; + } + + /* Allocate page table if not present. */ + struct pageDirectoryEntry *pde; + pde = addr_gpa2hva(vm, pdpe[index[2]].address * vm->page_size); + if (!pde[index[1]].present) { + pde[index[1]].address = vm_phy_page_alloc(vm, + KVM_GUEST_PAGE_TABLE_MIN_PADDR, pgd_memslot) + >> vm->page_shift; + pde[index[1]].writable = true; + pde[index[1]].present = true; + } + + /* Fill in page table entry. */ + struct pageTableEntry *pte; + pte = addr_gpa2hva(vm, pde[index[1]].address * vm->page_size); + pte[index[0]].address = paddr >> vm->page_shift; + pte[index[0]].writable = true; + pte[index[0]].present = 1; +} + +/* Virtual Translation Tables Dump + * + * Input Args: + * vm - Virtual Machine + * indent - Left margin indent amount + * + * Output Args: + * stream - Output FILE stream + * + * Return: None + * + * Dumps to the FILE stream given by stream, the contents of all the + * virtual translation tables for the VM given by vm. + */ +void virt_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent) +{ + struct pageMapL4Entry *pml4e, *pml4e_start; + struct pageDirectoryPointerEntry *pdpe, *pdpe_start; + struct pageDirectoryEntry *pde, *pde_start; + struct pageTableEntry *pte, *pte_start; + + if (!vm->pgd_created) + return; + + fprintf(stream, "%*s " + " no\n", indent, ""); + fprintf(stream, "%*s index hvaddr gpaddr " + "addr w exec dirty\n", + indent, ""); + pml4e_start = (struct pageMapL4Entry *) addr_gpa2hva(vm, + vm->pgd); + for (uint16_t n1 = 0; n1 <= 0x1ffu; n1++) { + pml4e = &pml4e_start[n1]; + if (!pml4e->present) + continue; + fprintf(stream, "%*spml4e 0x%-3zx %p 0x%-12lx 0x%-10lx %u " + " %u\n", + indent, "", + pml4e - pml4e_start, pml4e, + addr_hva2gpa(vm, pml4e), (uint64_t) pml4e->address, + pml4e->writable, pml4e->execute_disable); + + pdpe_start = addr_gpa2hva(vm, pml4e->address + * vm->page_size); + for (uint16_t n2 = 0; n2 <= 0x1ffu; n2++) { + pdpe = &pdpe_start[n2]; + if (!pdpe->present) + continue; + fprintf(stream, "%*spdpe 0x%-3zx %p 0x%-12lx 0x%-10lx " + "%u %u\n", + indent, "", + pdpe - pdpe_start, pdpe, + addr_hva2gpa(vm, pdpe), + (uint64_t) pdpe->address, pdpe->writable, + pdpe->execute_disable); + + pde_start = addr_gpa2hva(vm, + pdpe->address * vm->page_size); + for (uint16_t n3 = 0; n3 <= 0x1ffu; n3++) { + pde = &pde_start[n3]; + if (!pde->present) + continue; + fprintf(stream, "%*spde 0x%-3zx %p " + "0x%-12lx 0x%-10lx %u %u\n", + indent, "", pde - pde_start, pde, + addr_hva2gpa(vm, pde), + (uint64_t) pde->address, pde->writable, + pde->execute_disable); + + pte_start = addr_gpa2hva(vm, + pde->address * vm->page_size); + for (uint16_t n4 = 0; n4 <= 0x1ffu; n4++) { + pte = &pte_start[n4]; + if (!pte->present) + continue; + fprintf(stream, "%*spte 0x%-3zx %p " + "0x%-12lx 0x%-10lx %u %u " + " %u 0x%-10lx\n", + indent, "", + pte - pte_start, pte, + addr_hva2gpa(vm, pte), + (uint64_t) pte->address, + pte->writable, + pte->execute_disable, + pte->dirty, + ((uint64_t) n1 << 27) + | ((uint64_t) n2 << 18) + | ((uint64_t) n3 << 9) + | ((uint64_t) n4)); + } + } + } + } +} + +/* Set Unusable Segment + * + * Input Args: None + * + * Output Args: + * segp - Pointer to segment register + * + * Return: None + * + * Sets the segment register pointed to by segp to an unusable state. + */ +static void kvm_seg_set_unusable(struct kvm_segment *segp) +{ + memset(segp, 0, sizeof(*segp)); + segp->unusable = true; +} + +/* Set Long Mode Flat Kernel Code Segment + * + * Input Args: + * selector - selector value + * + * Output Args: + * segp - Pointer to KVM segment + * + * Return: None + * + * Sets up the KVM segment pointed to by segp, to be a code segment + * with the selector value given by selector. + */ +static void kvm_seg_set_kernel_code_64bit(uint16_t selector, + struct kvm_segment *segp) +{ + memset(segp, 0, sizeof(*segp)); + segp->selector = selector; + segp->limit = 0xFFFFFFFFu; + segp->s = 0x1; /* kTypeCodeData */ + segp->type = 0x08 | 0x01 | 0x02; /* kFlagCode | kFlagCodeAccessed + * | kFlagCodeReadable + */ + segp->g = true; + segp->l = true; + segp->present = 1; +} + +/* Set Long Mode Flat Kernel Data Segment + * + * Input Args: + * selector - selector value + * + * Output Args: + * segp - Pointer to KVM segment + * + * Return: None + * + * Sets up the KVM segment pointed to by segp, to be a data segment + * with the selector value given by selector. + */ +static void kvm_seg_set_kernel_data_64bit(uint16_t selector, + struct kvm_segment *segp) +{ + memset(segp, 0, sizeof(*segp)); + segp->selector = selector; + segp->limit = 0xFFFFFFFFu; + segp->s = 0x1; /* kTypeCodeData */ + segp->type = 0x00 | 0x01 | 0x02; /* kFlagData | kFlagDataAccessed + * | kFlagDataWritable + */ + segp->g = true; + segp->present = true; +} + +/* Address Guest Virtual to Guest Physical + * + * Input Args: + * vm - Virtual Machine + * gpa - VM virtual address + * + * Output Args: None + * + * Return: + * Equivalent VM physical address + * + * Translates the VM virtual address given by gva to a VM physical + * address and then locates the memory region containing the VM + * physical address, within the VM given by vm. When found, the host + * virtual address providing the memory to the vm physical address is returned. + * A TEST_ASSERT failure occurs if no region containing translated + * VM virtual address exists. + */ +vm_paddr_t addr_gva2gpa(struct kvm_vm *vm, vm_vaddr_t gva) +{ + uint16_t index[4]; + struct pageMapL4Entry *pml4e; + struct pageDirectoryPointerEntry *pdpe; + struct pageDirectoryEntry *pde; + struct pageTableEntry *pte; + void *hva; + + TEST_ASSERT(vm->mode == VM_MODE_FLAT48PG, "Attempt to use " + "unknown or unsupported guest mode, mode: 0x%x", vm->mode); + + index[0] = (gva >> 12) & 0x1ffu; + index[1] = (gva >> 21) & 0x1ffu; + index[2] = (gva >> 30) & 0x1ffu; + index[3] = (gva >> 39) & 0x1ffu; + + if (!vm->pgd_created) + goto unmapped_gva; + pml4e = addr_gpa2hva(vm, vm->pgd); + if (!pml4e[index[3]].present) + goto unmapped_gva; + + pdpe = addr_gpa2hva(vm, pml4e[index[3]].address * vm->page_size); + if (!pdpe[index[2]].present) + goto unmapped_gva; + + pde = addr_gpa2hva(vm, pdpe[index[2]].address * vm->page_size); + if (!pde[index[1]].present) + goto unmapped_gva; + + pte = addr_gpa2hva(vm, pde[index[1]].address * vm->page_size); + if (!pte[index[0]].present) + goto unmapped_gva; + + return (pte[index[0]].address * vm->page_size) + (gva & 0xfffu); + +unmapped_gva: + TEST_ASSERT(false, "No mapping for vm virtual address, " + "gva: 0x%lx", gva); +} + +void vcpu_setup(struct kvm_vm *vm, int vcpuid) +{ + struct kvm_sregs sregs; + + /* Set mode specific system register values. */ + vcpu_sregs_get(vm, vcpuid, &sregs); + + switch (vm->mode) { + case VM_MODE_FLAT48PG: + sregs.cr0 = X86_CR0_PE | X86_CR0_NE | X86_CR0_PG; + sregs.cr4 |= X86_CR4_PAE; + sregs.efer |= (EFER_LME | EFER_LMA | EFER_NX); + + kvm_seg_set_unusable(&sregs.ldt); + kvm_seg_set_kernel_code_64bit(0x8, &sregs.cs); + kvm_seg_set_kernel_data_64bit(0x10, &sregs.ds); + kvm_seg_set_kernel_data_64bit(0x10, &sregs.es); + break; + + default: + TEST_ASSERT(false, "Unknown guest mode, mode: 0x%x", vm->mode); + } + vcpu_sregs_set(vm, vcpuid, &sregs); + + /* If virtual translation table have been setup, set system register + * to point to the tables. It's okay if they haven't been setup yet, + * in that the code that sets up the virtual translation tables, will + * go back through any VCPUs that have already been created and set + * their values. + */ + if (vm->pgd_created) { + struct kvm_sregs sregs; + + vcpu_sregs_get(vm, vcpuid, &sregs); + + sregs.cr3 = vm->pgd; + vcpu_sregs_set(vm, vcpuid, &sregs); + } +} +/* Adds a vCPU with reasonable defaults (i.e., a stack) + * + * Input Args: + * vcpuid - The id of the VCPU to add to the VM. + * guest_code - The vCPU's entry point + */ +void vm_vcpu_add_default(struct kvm_vm *vm, uint32_t vcpuid, void *guest_code) +{ + struct kvm_mp_state mp_state; + struct kvm_regs regs; + vm_vaddr_t stack_vaddr; + stack_vaddr = vm_vaddr_alloc(vm, DEFAULT_STACK_PGS * getpagesize(), + DEFAULT_GUEST_STACK_VADDR_MIN, 0, 0); + + /* Create VCPU */ + vm_vcpu_add(vm, vcpuid); + + /* Setup guest general purpose registers */ + vcpu_regs_get(vm, vcpuid, ®s); + regs.rflags = regs.rflags | 0x2; + regs.rsp = stack_vaddr + (DEFAULT_STACK_PGS * getpagesize()); + regs.rip = (unsigned long) guest_code; + vcpu_regs_set(vm, vcpuid, ®s); + + /* Setup the MP state */ + mp_state.mp_state = 0; + vcpu_set_mp_state(vm, vcpuid, &mp_state); +} + +/* VM VCPU CPUID Set + * + * Input Args: + * vm - Virtual Machine + * vcpuid - VCPU id + * cpuid - The CPUID values to set. + * + * Output Args: None + * + * Return: void + * + * Set the VCPU's CPUID. + */ +void vcpu_set_cpuid(struct kvm_vm *vm, + uint32_t vcpuid, struct kvm_cpuid2 *cpuid) +{ + struct vcpu *vcpu = vcpu_find(vm, vcpuid); + int rc; + + TEST_ASSERT(vcpu != NULL, "vcpu not found, vcpuid: %u", vcpuid); + + rc = ioctl(vcpu->fd, KVM_SET_CPUID2, cpuid); + TEST_ASSERT(rc == 0, "KVM_SET_CPUID2 failed, rc: %i errno: %i", + rc, errno); + +} +/* Create a VM with reasonable defaults + * + * Input Args: + * vcpuid - The id of the single VCPU to add to the VM. + * guest_code - The vCPU's entry point + * + * Output Args: None + * + * Return: + * Pointer to opaque structure that describes the created VM. + */ +struct kvm_vm *vm_create_default(uint32_t vcpuid, void *guest_code) +{ + struct kvm_vm *vm; + + /* Create VM */ + vm = vm_create(VM_MODE_FLAT48PG, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + + /* Setup IRQ Chip */ + vm_create_irqchip(vm); + + /* Add the first vCPU. */ + vm_vcpu_add_default(vm, vcpuid, guest_code); + + return vm; +} diff --git a/tools/testing/selftests/kvm/set_sregs_test.c b/tools/testing/selftests/kvm/set_sregs_test.c new file mode 100644 index 000000000000..090fd3f19352 --- /dev/null +++ b/tools/testing/selftests/kvm/set_sregs_test.c @@ -0,0 +1,54 @@ +/* + * KVM_SET_SREGS tests + * + * Copyright (C) 2018, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + * This is a regression test for the bug fixed by the following commit: + * d3802286fa0f ("kvm: x86: Disallow illegal IA32_APIC_BASE MSR values") + * + * That bug allowed a user-mode program that called the KVM_SET_SREGS + * ioctl to put a VCPU's local APIC into an invalid state. + * + */ +#define _GNU_SOURCE /* for program_invocation_short_name */ +#include +#include +#include +#include +#include + +#include "test_util.h" + +#include "kvm_util.h" +#include "x86.h" + +#define VCPU_ID 5 + +int main(int argc, char *argv[]) +{ + struct kvm_sregs sregs; + struct kvm_vm *vm; + int rc; + + /* Tell stdout not to buffer its content */ + setbuf(stdout, NULL); + + /* Create VM */ + vm = vm_create_default(VCPU_ID, NULL); + + vcpu_sregs_get(vm, VCPU_ID, &sregs); + sregs.apic_base = 1 << 10; + rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); + TEST_ASSERT(rc, "Set IA32_APIC_BASE to %llx (invalid)", + sregs.apic_base); + sregs.apic_base = 1 << 11; + rc = _vcpu_sregs_set(vm, VCPU_ID, &sregs); + TEST_ASSERT(!rc, "Couldn't set IA32_APIC_BASE to %llx (valid)", + sregs.apic_base); + + kvm_vm_free(vm); + + return 0; +} -- cgit v1.3-14-g43fede From 6089ae0bd5e15fc150adce5bc694e87e00513825 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Wed, 28 Mar 2018 09:45:34 +0200 Subject: kvm: selftests: add sync_regs_test This includes the infrastructure to map the test into the guest and run code from the test program inside a VM. Signed-off-by: Ken Hofsass Signed-off-by: Paolo Bonzini --- tools/testing/selftests/kvm/Makefile | 3 +- tools/testing/selftests/kvm/include/kvm_util.h | 3 + tools/testing/selftests/kvm/lib/elf.c | 197 +++++++++++++++++++++ tools/testing/selftests/kvm/lib/io.c | 158 +++++++++++++++++ tools/testing/selftests/kvm/lib/x86.c | 3 + tools/testing/selftests/kvm/sync_regs_test.c | 232 +++++++++++++++++++++++++ 6 files changed, 595 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/kvm/lib/elf.c create mode 100644 tools/testing/selftests/kvm/lib/io.c create mode 100644 tools/testing/selftests/kvm/sync_regs_test.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 6aade26e9ca2..dc44de904797 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -3,10 +3,11 @@ all: top_srcdir = ../../../../ UNAME_M := $(shell uname -m) -LIBKVM = lib/assert.c lib/kvm_util.c lib/sparsebit.c +LIBKVM = lib/assert.c lib/elf.c lib/io.c lib/kvm_util.c lib/sparsebit.c LIBKVM_x86_64 = lib/x86.c TEST_GEN_PROGS_x86_64 = set_sregs_test +TEST_GEN_PROGS_x86_64 += sync_regs_test TEST_GEN_PROGS += $(TEST_GEN_PROGS_$(UNAME_M)) LIBKVM += $(LIBKVM_$(UNAME_M)) diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index d2e3e23bfbd3..57974ad46373 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -57,6 +57,9 @@ void kvm_vm_free(struct kvm_vm *vmp); int kvm_memcmp_hva_gva(void *hva, struct kvm_vm *vm, const vm_vaddr_t gva, size_t len); +void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename, + uint32_t data_memslot, uint32_t pgd_memslot); + void vm_dump(FILE *stream, struct kvm_vm *vm, uint8_t indent); void vcpu_dump(FILE *stream, struct kvm_vm *vm, uint32_t vcpuid, uint8_t indent); diff --git a/tools/testing/selftests/kvm/lib/elf.c b/tools/testing/selftests/kvm/lib/elf.c new file mode 100644 index 000000000000..5eb857584aa3 --- /dev/null +++ b/tools/testing/selftests/kvm/lib/elf.c @@ -0,0 +1,197 @@ +/* + * tools/testing/selftests/kvm/lib/elf.c + * + * Copyright (C) 2018, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#include "test_util.h" + +#include +#include + +#include "kvm_util.h" +#include "kvm_util_internal.h" + +static void elfhdr_get(const char *filename, Elf64_Ehdr *hdrp) +{ + off_t offset_rv; + + /* Open the ELF file. */ + int fd; + fd = open(filename, O_RDONLY); + TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n" + " filename: %s\n" + " rv: %i errno: %i", filename, fd, errno); + + /* Read in and validate ELF Identification Record. + * The ELF Identification record is the first 16 (EI_NIDENT) bytes + * of the ELF header, which is at the beginning of the ELF file. + * For now it is only safe to read the first EI_NIDENT bytes. Once + * read and validated, the value of e_ehsize can be used to determine + * the real size of the ELF header. + */ + unsigned char ident[EI_NIDENT]; + test_read(fd, ident, sizeof(ident)); + TEST_ASSERT((ident[EI_MAG0] == ELFMAG0) && (ident[EI_MAG1] == ELFMAG1) + && (ident[EI_MAG2] == ELFMAG2) && (ident[EI_MAG3] == ELFMAG3), + "ELF MAGIC Mismatch,\n" + " filename: %s\n" + " ident[EI_MAG0 - EI_MAG3]: %02x %02x %02x %02x\n" + " Expected: %02x %02x %02x %02x", + filename, + ident[EI_MAG0], ident[EI_MAG1], ident[EI_MAG2], ident[EI_MAG3], + ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3); + TEST_ASSERT(ident[EI_CLASS] == ELFCLASS64, + "Current implementation only able to handle ELFCLASS64,\n" + " filename: %s\n" + " ident[EI_CLASS]: %02x\n" + " expected: %02x", + filename, + ident[EI_CLASS], ELFCLASS64); + TEST_ASSERT(((BYTE_ORDER == LITTLE_ENDIAN) + && (ident[EI_DATA] == ELFDATA2LSB)) + || ((BYTE_ORDER == BIG_ENDIAN) + && (ident[EI_DATA] == ELFDATA2MSB)), "Current " + "implementation only able to handle\n" + "cases where the host and ELF file endianness\n" + "is the same:\n" + " host BYTE_ORDER: %u\n" + " host LITTLE_ENDIAN: %u\n" + " host BIG_ENDIAN: %u\n" + " ident[EI_DATA]: %u\n" + " ELFDATA2LSB: %u\n" + " ELFDATA2MSB: %u", + BYTE_ORDER, LITTLE_ENDIAN, BIG_ENDIAN, + ident[EI_DATA], ELFDATA2LSB, ELFDATA2MSB); + TEST_ASSERT(ident[EI_VERSION] == EV_CURRENT, + "Current implementation only able to handle current " + "ELF version,\n" + " filename: %s\n" + " ident[EI_VERSION]: %02x\n" + " expected: %02x", + filename, ident[EI_VERSION], EV_CURRENT); + + /* Read in the ELF header. + * With the ELF Identification portion of the ELF header + * validated, especially that the value at EI_VERSION is + * as expected, it is now safe to read the entire ELF header. + */ + offset_rv = lseek(fd, 0, SEEK_SET); + TEST_ASSERT(offset_rv == 0, "Seek to ELF header failed,\n" + " rv: %zi expected: %i", offset_rv, 0); + test_read(fd, hdrp, sizeof(*hdrp)); + TEST_ASSERT(hdrp->e_phentsize == sizeof(Elf64_Phdr), + "Unexpected physical header size,\n" + " hdrp->e_phentsize: %x\n" + " expected: %zx", + hdrp->e_phentsize, sizeof(Elf64_Phdr)); + TEST_ASSERT(hdrp->e_shentsize == sizeof(Elf64_Shdr), + "Unexpected section header size,\n" + " hdrp->e_shentsize: %x\n" + " expected: %zx", + hdrp->e_shentsize, sizeof(Elf64_Shdr)); +} + +/* VM ELF Load + * + * Input Args: + * filename - Path to ELF file + * + * Output Args: None + * + * Input/Output Args: + * vm - Pointer to opaque type that describes the VM. + * + * Return: None, TEST_ASSERT failures for all error conditions + * + * Loads the program image of the ELF file specified by filename, + * into the virtual address space of the VM pointed to by vm. On entry + * the VM needs to not be using any of the virtual address space used + * by the image and it needs to have sufficient available physical pages, to + * back the virtual pages used to load the image. + */ +void kvm_vm_elf_load(struct kvm_vm *vm, const char *filename, + uint32_t data_memslot, uint32_t pgd_memslot) +{ + off_t offset, offset_rv; + Elf64_Ehdr hdr; + + /* Open the ELF file. */ + int fd; + fd = open(filename, O_RDONLY); + TEST_ASSERT(fd >= 0, "Failed to open ELF file,\n" + " filename: %s\n" + " rv: %i errno: %i", filename, fd, errno); + + /* Read in the ELF header. */ + elfhdr_get(filename, &hdr); + + /* For each program header. + * The following ELF header members specify the location + * and size of the program headers: + * + * e_phoff - File offset to start of program headers + * e_phentsize - Size of each program header + * e_phnum - Number of program header entries + */ + for (unsigned int n1 = 0; n1 < hdr.e_phnum; n1++) { + /* Seek to the beginning of the program header. */ + offset = hdr.e_phoff + (n1 * hdr.e_phentsize); + offset_rv = lseek(fd, offset, SEEK_SET); + TEST_ASSERT(offset_rv == offset, + "Failed to seek to begining of program header %u,\n" + " filename: %s\n" + " rv: %jd errno: %i", + n1, filename, (intmax_t) offset_rv, errno); + + /* Read in the program header. */ + Elf64_Phdr phdr; + test_read(fd, &phdr, sizeof(phdr)); + + /* Skip if this header doesn't describe a loadable segment. */ + if (phdr.p_type != PT_LOAD) + continue; + + /* Allocate memory for this segment within the VM. */ + TEST_ASSERT(phdr.p_memsz > 0, "Unexpected loadable segment " + "memsize of 0,\n" + " phdr index: %u p_memsz: 0x%" PRIx64, + n1, (uint64_t) phdr.p_memsz); + vm_vaddr_t seg_vstart = phdr.p_vaddr; + seg_vstart &= ~(vm_vaddr_t)(vm->page_size - 1); + vm_vaddr_t seg_vend = phdr.p_vaddr + phdr.p_memsz - 1; + seg_vend |= vm->page_size - 1; + size_t seg_size = seg_vend - seg_vstart + 1; + + vm_vaddr_t vaddr = vm_vaddr_alloc(vm, seg_size, seg_vstart, + data_memslot, pgd_memslot); + TEST_ASSERT(vaddr == seg_vstart, "Unable to allocate " + "virtual memory for segment at requested min addr,\n" + " segment idx: %u\n" + " seg_vstart: 0x%lx\n" + " vaddr: 0x%lx", + n1, seg_vstart, vaddr); + memset(addr_gva2hva(vm, vaddr), 0, seg_size); + /* TODO(lhuemill): Set permissions of each memory segment + * based on the least-significant 3 bits of phdr.p_flags. + */ + + /* Load portion of initial state that is contained within + * the ELF file. + */ + if (phdr.p_filesz) { + offset_rv = lseek(fd, phdr.p_offset, SEEK_SET); + TEST_ASSERT(offset_rv == phdr.p_offset, + "Seek to program segment offset failed,\n" + " program header idx: %u errno: %i\n" + " offset_rv: 0x%jx\n" + " expected: 0x%jx\n", + n1, errno, (intmax_t) offset_rv, + (intmax_t) phdr.p_offset); + test_read(fd, addr_gva2hva(vm, phdr.p_vaddr), + phdr.p_filesz); + } + } +} diff --git a/tools/testing/selftests/kvm/lib/io.c b/tools/testing/selftests/kvm/lib/io.c new file mode 100644 index 000000000000..cff869ffe6ee --- /dev/null +++ b/tools/testing/selftests/kvm/lib/io.c @@ -0,0 +1,158 @@ +/* + * tools/testing/selftests/kvm/lib/io.c + * + * Copyright (C) 2018, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + */ + +#include "test_util.h" + +/* Test Write + * + * A wrapper for write(2), that automatically handles the following + * special conditions: + * + * + Interrupted system call (EINTR) + * + Write of less than requested amount + * + Non-block return (EAGAIN) + * + * For each of the above, an additional write is performed to automatically + * continue writing the requested data. + * There are also many cases where write(2) can return an unexpected + * error (e.g. EIO). Such errors cause a TEST_ASSERT failure. + * + * Note, for function signature compatibility with write(2), this function + * returns the number of bytes written, but that value will always be equal + * to the number of requested bytes. All other conditions in this and + * future enhancements to this function either automatically issue another + * write(2) or cause a TEST_ASSERT failure. + * + * Args: + * fd - Opened file descriptor to file to be written. + * count - Number of bytes to write. + * + * Output: + * buf - Starting address of data to be written. + * + * Return: + * On success, number of bytes written. + * On failure, a TEST_ASSERT failure is caused. + */ +ssize_t test_write(int fd, const void *buf, size_t count) +{ + ssize_t rc; + ssize_t num_written = 0; + size_t num_left = count; + const char *ptr = buf; + + /* Note: Count of zero is allowed (see "RETURN VALUE" portion of + * write(2) manpage for details. + */ + TEST_ASSERT(count >= 0, "Unexpected count, count: %li", count); + + do { + rc = write(fd, ptr, num_left); + + switch (rc) { + case -1: + TEST_ASSERT(errno == EAGAIN || errno == EINTR, + "Unexpected write failure,\n" + " rc: %zi errno: %i", rc, errno); + continue; + + case 0: + TEST_ASSERT(false, "Unexpected EOF,\n" + " rc: %zi num_written: %zi num_left: %zu", + rc, num_written, num_left); + break; + + default: + TEST_ASSERT(rc >= 0, "Unexpected ret from write,\n" + " rc: %zi errno: %i", rc, errno); + num_written += rc; + num_left -= rc; + ptr += rc; + break; + } + } while (num_written < count); + + return num_written; +} + +/* Test Read + * + * A wrapper for read(2), that automatically handles the following + * special conditions: + * + * + Interrupted system call (EINTR) + * + Read of less than requested amount + * + Non-block return (EAGAIN) + * + * For each of the above, an additional read is performed to automatically + * continue reading the requested data. + * There are also many cases where read(2) can return an unexpected + * error (e.g. EIO). Such errors cause a TEST_ASSERT failure. Note, + * it is expected that the file opened by fd at the current file position + * contains at least the number of requested bytes to be read. A TEST_ASSERT + * failure is produced if an End-Of-File condition occurs, before all the + * data is read. It is the callers responsibility to assure that sufficient + * data exists. + * + * Note, for function signature compatibility with read(2), this function + * returns the number of bytes read, but that value will always be equal + * to the number of requested bytes. All other conditions in this and + * future enhancements to this function either automatically issue another + * read(2) or cause a TEST_ASSERT failure. + * + * Args: + * fd - Opened file descriptor to file to be read. + * count - Number of bytes to read. + * + * Output: + * buf - Starting address of where to write the bytes read. + * + * Return: + * On success, number of bytes read. + * On failure, a TEST_ASSERT failure is caused. + */ +ssize_t test_read(int fd, void *buf, size_t count) +{ + ssize_t rc; + ssize_t num_read = 0; + size_t num_left = count; + char *ptr = buf; + + /* Note: Count of zero is allowed (see "If count is zero" portion of + * read(2) manpage for details. + */ + TEST_ASSERT(count >= 0, "Unexpected count, count: %li", count); + + do { + rc = read(fd, ptr, num_left); + + switch (rc) { + case -1: + TEST_ASSERT(errno == EAGAIN || errno == EINTR, + "Unexpected read failure,\n" + " rc: %zi errno: %i", rc, errno); + break; + + case 0: + TEST_ASSERT(false, "Unexpected EOF,\n" + " rc: %zi num_read: %zi num_left: %zu", + rc, num_read, num_left); + break; + + default: + TEST_ASSERT(rc > 0, "Unexpected ret from read,\n" + " rc: %zi errno: %i", rc, errno); + num_read += rc; + num_left -= rc; + ptr += rc; + break; + } + } while (num_read < count); + + return num_read; +} diff --git a/tools/testing/selftests/kvm/lib/x86.c b/tools/testing/selftests/kvm/lib/x86.c index 12df46280b23..2f17675f4275 100644 --- a/tools/testing/selftests/kvm/lib/x86.c +++ b/tools/testing/selftests/kvm/lib/x86.c @@ -687,6 +687,9 @@ struct kvm_vm *vm_create_default(uint32_t vcpuid, void *guest_code) /* Create VM */ vm = vm_create(VM_MODE_FLAT48PG, DEFAULT_GUEST_PHY_PAGES, O_RDWR); + /* Setup guest code */ + kvm_vm_elf_load(vm, program_invocation_name, 0, 0); + /* Setup IRQ Chip */ vm_create_irqchip(vm); diff --git a/tools/testing/selftests/kvm/sync_regs_test.c b/tools/testing/selftests/kvm/sync_regs_test.c new file mode 100644 index 000000000000..428e9473f5e2 --- /dev/null +++ b/tools/testing/selftests/kvm/sync_regs_test.c @@ -0,0 +1,232 @@ +/* + * Test for x86 KVM_CAP_SYNC_REGS + * + * Copyright (C) 2018, Google LLC. + * + * This work is licensed under the terms of the GNU GPL, version 2. + * + * Verifies expected behavior of x86 KVM_CAP_SYNC_REGS functionality, + * including requesting an invalid register set, updates to/from values + * in kvm_run.s.regs when kvm_valid_regs and kvm_dirty_regs are toggled. + */ + +#define _GNU_SOURCE /* for program_invocation_short_name */ +#include +#include +#include +#include +#include + +#include "test_util.h" +#include "kvm_util.h" +#include "x86.h" + +#define VCPU_ID 5 +#define PORT_HOST_SYNC 0x1000 + +static void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1) +{ + __asm__ __volatile__("in %[port], %%al" + : + : [port]"d"(port), "D"(arg0), "S"(arg1) + : "rax"); +} + +#define exit_to_l0(_port, _arg0, _arg1) \ + __exit_to_l0(_port, (uint64_t) (_arg0), (uint64_t) (_arg1)) + +#define GUEST_ASSERT(_condition) do { \ + if (!(_condition)) \ + exit_to_l0(PORT_ABORT, "Failed guest assert: " #_condition, 0);\ +} while (0) + +void guest_code(void) +{ + for (;;) { + exit_to_l0(PORT_HOST_SYNC, "hello", 0); + asm volatile ("inc %r11"); + } +} + +static void compare_regs(struct kvm_regs *left, struct kvm_regs *right) +{ +#define REG_COMPARE(reg) \ + TEST_ASSERT(left->reg == right->reg, \ + "Register " #reg \ + " values did not match: 0x%llx, 0x%llx\n", \ + left->reg, right->reg) + REG_COMPARE(rax); + REG_COMPARE(rbx); + REG_COMPARE(rcx); + REG_COMPARE(rdx); + REG_COMPARE(rsi); + REG_COMPARE(rdi); + REG_COMPARE(rsp); + REG_COMPARE(rbp); + REG_COMPARE(r8); + REG_COMPARE(r9); + REG_COMPARE(r10); + REG_COMPARE(r11); + REG_COMPARE(r12); + REG_COMPARE(r13); + REG_COMPARE(r14); + REG_COMPARE(r15); + REG_COMPARE(rip); + REG_COMPARE(rflags); +#undef REG_COMPARE +} + +static void compare_sregs(struct kvm_sregs *left, struct kvm_sregs *right) +{ +} + +static void compare_vcpu_events(struct kvm_vcpu_events *left, + struct kvm_vcpu_events *right) +{ +} + +int main(int argc, char *argv[]) +{ + struct kvm_vm *vm; + struct kvm_run *run; + struct kvm_regs regs; + struct kvm_sregs sregs; + struct kvm_vcpu_events events; + int rv, cap; + + /* Tell stdout not to buffer its content */ + setbuf(stdout, NULL); + + cap = kvm_check_cap(KVM_CAP_SYNC_REGS); + TEST_ASSERT((unsigned long)cap == KVM_SYNC_X86_VALID_FIELDS, + "KVM_CAP_SYNC_REGS (0x%x) != KVM_SYNC_X86_VALID_FIELDS (0x%lx)\n", + cap, KVM_SYNC_X86_VALID_FIELDS); + + /* Create VM */ + vm = vm_create_default(VCPU_ID, guest_code); + + run = vcpu_state(vm, VCPU_ID); + + /* Request reading invalid register set from VCPU. */ + run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS << 1; + rv = _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(rv < 0 && errno == EINVAL, + "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n", + rv); + vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0; + + /* Request setting invalid register set into VCPU. */ + run->kvm_dirty_regs = KVM_SYNC_X86_VALID_FIELDS << 1; + rv = _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(rv < 0 && errno == EINVAL, + "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n", + rv); + vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0; + + /* Request and verify all valid register sets. */ + /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */ + run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS; + rv = _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + + vcpu_regs_get(vm, VCPU_ID, ®s); + compare_regs(®s, &run->s.regs.regs); + + vcpu_sregs_get(vm, VCPU_ID, &sregs); + compare_sregs(&sregs, &run->s.regs.sregs); + + vcpu_events_get(vm, VCPU_ID, &events); + compare_vcpu_events(&events, &run->s.regs.events); + + /* Set and verify various register values. */ + run->s.regs.regs.r11 = 0xBAD1DEA; + run->s.regs.sregs.apic_base = 1 << 11; + /* TODO run->s.regs.events.XYZ = ABC; */ + + run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS; + run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS; + rv = _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + TEST_ASSERT(run->s.regs.regs.r11 == 0xBAD1DEA + 1, + "r11 sync regs value incorrect 0x%llx.", + run->s.regs.regs.r11); + TEST_ASSERT(run->s.regs.sregs.apic_base == 1 << 11, + "apic_base sync regs value incorrect 0x%llx.", + run->s.regs.sregs.apic_base); + + vcpu_regs_get(vm, VCPU_ID, ®s); + compare_regs(®s, &run->s.regs.regs); + + vcpu_sregs_get(vm, VCPU_ID, &sregs); + compare_sregs(&sregs, &run->s.regs.sregs); + + vcpu_events_get(vm, VCPU_ID, &events); + compare_vcpu_events(&events, &run->s.regs.events); + + /* Clear kvm_dirty_regs bits, verify new s.regs values are + * overwritten with existing guest values. + */ + run->kvm_valid_regs = KVM_SYNC_X86_VALID_FIELDS; + run->kvm_dirty_regs = 0; + run->s.regs.regs.r11 = 0xDEADBEEF; + rv = _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + TEST_ASSERT(run->s.regs.regs.r11 != 0xDEADBEEF, + "r11 sync regs value incorrect 0x%llx.", + run->s.regs.regs.r11); + + /* Clear kvm_valid_regs bits and kvm_dirty_bits. + * Verify s.regs values are not overwritten with existing guest values + * and that guest values are not overwritten with kvm_sync_regs values. + */ + run->kvm_valid_regs = 0; + run->kvm_dirty_regs = 0; + run->s.regs.regs.r11 = 0xAAAA; + regs.r11 = 0xBAC0; + vcpu_regs_set(vm, VCPU_ID, ®s); + rv = _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + TEST_ASSERT(run->s.regs.regs.r11 == 0xAAAA, + "r11 sync regs value incorrect 0x%llx.", + run->s.regs.regs.r11); + vcpu_regs_get(vm, VCPU_ID, ®s); + TEST_ASSERT(regs.r11 == 0xBAC0 + 1, + "r11 guest value incorrect 0x%llx.", + regs.r11); + + /* Clear kvm_valid_regs bits. Verify s.regs values are not overwritten + * with existing guest values but that guest values are overwritten + * with kvm_sync_regs values. + */ + run->kvm_valid_regs = 0; + run->kvm_dirty_regs = KVM_SYNC_X86_VALID_FIELDS; + run->s.regs.regs.r11 = 0xBBBB; + rv = _vcpu_run(vm, VCPU_ID); + TEST_ASSERT(run->exit_reason == KVM_EXIT_IO, + "Unexpected exit reason: %u (%s),\n", + run->exit_reason, + exit_reason_str(run->exit_reason)); + TEST_ASSERT(run->s.regs.regs.r11 == 0xBBBB, + "r11 sync regs value incorrect 0x%llx.", + run->s.regs.regs.r11); + vcpu_regs_get(vm, VCPU_ID, ®s); + TEST_ASSERT(regs.r11 == 0xBBBB + 1, + "r11 guest value incorrect 0x%llx.", + regs.r11); + + kvm_vm_free(vm); + + return 0; +} -- cgit v1.3-14-g43fede From 4cf260fc409c73f6e40b3e8061a0cb925703d7ee Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 8 Feb 2018 14:24:04 -0700 Subject: libnvdimm, testing: Add emulation for smart injection commands Add support for the smart injection command in the nvdimm unit test framework. This allows for directly injecting to smart fields and flags that are supported in the injection command. If the injected values are past the threshold, then an acpi notification is also triggered. Cc: Dan Williams Signed-off-by: Vishal Verma Signed-off-by: Dan Williams --- tools/testing/nvdimm/test/nfit.c | 38 ++++++++++++++++++++++++++++++++++- tools/testing/nvdimm/test/nfit_test.h | 16 +++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index d785235ba04e..e83c24625fe4 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -711,7 +711,9 @@ static void smart_notify(struct device *bus_dev, >= thresh->media_temperature) || ((thresh->alarm_control & ND_INTEL_SMART_CTEMP_TRIP) && smart->ctrl_temperature - >= thresh->ctrl_temperature)) { + >= thresh->ctrl_temperature) + || (smart->health != ND_INTEL_SMART_NON_CRITICAL_HEALTH) + || (smart->shutdown_state != 0)) { device_lock(bus_dev); __acpi_nvdimm_notify(dimm_dev, 0x81); device_unlock(bus_dev); @@ -737,6 +739,32 @@ static int nfit_test_cmd_smart_set_threshold( return 0; } +static int nfit_test_cmd_smart_inject( + struct nd_intel_smart_inject *inj, + unsigned int buf_len, + struct nd_intel_smart_threshold *thresh, + struct nd_intel_smart *smart, + struct device *bus_dev, struct device *dimm_dev) +{ + if (buf_len != sizeof(*inj)) + return -EINVAL; + + if (inj->mtemp_enable) + smart->media_temperature = inj->media_temperature; + if (inj->spare_enable) + smart->spares = inj->spares; + if (inj->fatal_enable) + smart->health = ND_INTEL_SMART_FATAL_HEALTH; + if (inj->unsafe_shutdown_enable) { + smart->shutdown_state = 1; + smart->shutdown_count++; + } + inj->status = 0; + smart_notify(bus_dev, dimm_dev, smart, thresh); + + return 0; +} + static void uc_error_notify(struct work_struct *work) { struct nfit_test *t = container_of(work, typeof(*t), work); @@ -937,6 +965,13 @@ static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, t->dcr_idx], &t->smart[i - t->dcr_idx], &t->pdev.dev, t->dimm_dev[i]); + case ND_INTEL_SMART_INJECT: + return nfit_test_cmd_smart_inject(buf, + buf_len, + &t->smart_threshold[i - + t->dcr_idx], + &t->smart[i - t->dcr_idx], + &t->pdev.dev, t->dimm_dev[i]); default: return -ENOTTY; } @@ -2066,6 +2101,7 @@ static void nfit_test0_setup(struct nfit_test *t) set_bit(ND_INTEL_SMART, &acpi_desc->dimm_cmd_force_en); set_bit(ND_INTEL_SMART_THRESHOLD, &acpi_desc->dimm_cmd_force_en); set_bit(ND_INTEL_SMART_SET_THRESHOLD, &acpi_desc->dimm_cmd_force_en); + set_bit(ND_INTEL_SMART_INJECT, &acpi_desc->dimm_cmd_force_en); set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_cmd_force_en); set_bit(ND_CMD_ARS_START, &acpi_desc->bus_cmd_force_en); set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_cmd_force_en); diff --git a/tools/testing/nvdimm/test/nfit_test.h b/tools/testing/nvdimm/test/nfit_test.h index 428344519cdf..33752e06ff8d 100644 --- a/tools/testing/nvdimm/test/nfit_test.h +++ b/tools/testing/nvdimm/test/nfit_test.h @@ -93,6 +93,7 @@ struct nd_cmd_ars_err_inj_stat { #define ND_INTEL_FW_FINISH_UPDATE 15 #define ND_INTEL_FW_FINISH_QUERY 16 #define ND_INTEL_SMART_SET_THRESHOLD 17 +#define ND_INTEL_SMART_INJECT 18 #define ND_INTEL_SMART_HEALTH_VALID (1 << 0) #define ND_INTEL_SMART_SPARES_VALID (1 << 1) @@ -111,6 +112,10 @@ struct nd_cmd_ars_err_inj_stat { #define ND_INTEL_SMART_NON_CRITICAL_HEALTH (1 << 0) #define ND_INTEL_SMART_CRITICAL_HEALTH (1 << 1) #define ND_INTEL_SMART_FATAL_HEALTH (1 << 2) +#define ND_INTEL_SMART_INJECT_MTEMP (1 << 0) +#define ND_INTEL_SMART_INJECT_SPARE (1 << 1) +#define ND_INTEL_SMART_INJECT_FATAL (1 << 2) +#define ND_INTEL_SMART_INJECT_SHUTDOWN (1 << 3) struct nd_intel_smart { __u32 status; @@ -158,6 +163,17 @@ struct nd_intel_smart_set_threshold { __u32 status; } __packed; +struct nd_intel_smart_inject { + __u64 flags; + __u8 mtemp_enable; + __u16 media_temperature; + __u8 spare_enable; + __u8 spares; + __u8 fatal_enable; + __u8 unsafe_shutdown_enable; + __u32 status; +} __packed; + #define INTEL_FW_STORAGE_SIZE 0x100000 #define INTEL_FW_MAX_SEND_LEN 0xFFEC #define INTEL_FW_QUERY_INTERVAL 250000 -- cgit v1.3-14-g43fede From f6adcca02ca26577692a1f2ee892c134b076b339 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 8 Feb 2018 14:24:05 -0700 Subject: libnvdimm, testing: update the default smart ctrl_temperature The default value for smart ctrl_temperature was the same as the threshold for ctrl_temperature. As a result, any arbitrary smart injection to the nfit_test dimm could cause this alarm to trigger and cause an acpi notification. Drop the default value to below the threshold, so that unrelated injections don't trigger notifications. Cc: Dan Williams Signed-off-by: Vishal Verma Signed-off-by: Dan Williams --- tools/testing/nvdimm/test/nfit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index e83c24625fe4..cb166be4918d 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -1259,7 +1259,7 @@ static void smart_init(struct nfit_test *t) | ND_INTEL_SMART_MTEMP_VALID, .health = ND_INTEL_SMART_NON_CRITICAL_HEALTH, .media_temperature = 23 * 16, - .ctrl_temperature = 30 * 16, + .ctrl_temperature = 25 * 16, .pmic_temperature = 40 * 16, .spares = 75, .alarm_flags = ND_INTEL_SMART_SPARE_TRIP -- cgit v1.3-14-g43fede From 0f0db065999cf1793a7a9b595a9ba86935f139d4 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Tue, 17 Feb 2015 20:33:43 -0500 Subject: ktest: Add standalone config-bisect.pl program Started working on a stand alone program that can do a config bisect. It is based on the config bisect code of ktest.pl. Instead of needing all the infrastructure of ktest.pl, all that is required for config-bisect.pl is two config files. One that works, and one that does not. The goal is to pass in the two files, and it will create a new "good" and a new "bad" config file based on input from the user. After several iterations (calls to this program), it will eventually end with a minimum config value that allows one config to work and the other config to break. The program uses a technique that takes the good config and then makes half of the configs that differ from the bad config just like the bad config. The code will use make oldconfig to make sure the configs that are set are not all converted back due to incorrect dependencies on other configs set in the bad config but not in the new test config. This is still a work in progress, but as it was written while I was working at Red Hat, I want this code to be submitted as such. Signed-off-by: Steven Rostedt (Red Hat) --- tools/testing/ktest/config-bisect.pl | 763 +++++++++++++++++++++++++++++++++++ 1 file changed, 763 insertions(+) create mode 100755 tools/testing/ktest/config-bisect.pl (limited to 'tools/testing') diff --git a/tools/testing/ktest/config-bisect.pl b/tools/testing/ktest/config-bisect.pl new file mode 100755 index 000000000000..37cd796efa2b --- /dev/null +++ b/tools/testing/ktest/config-bisect.pl @@ -0,0 +1,763 @@ +#!/usr/bin/perl -w +# +# Copyright 2015 - Steven Rostedt, Red Hat Inc. +# Copyright 2017 - Steven Rostedt, VMware, Inc. +# +# Licensed under the terms of the GNU GPL License version 2 +# + +# usage: +# config-bisect.pl [options] good-config bad-config [good|bad] +# + +# Compares a good config to a bad config, then takes half of the diffs +# and produces a config that is somewhere between the good config and +# the bad config. That is, the resulting config will start with the +# good config and will try to make half of the differences of between +# the good and bad configs match the bad config. It tries because of +# dependencies between the two configs it may not be able to change +# exactly half of the configs that are different between the two config +# files. + +# Here's a normal way to use it: +# +# $ cd /path/to/linux/kernel +# $ config-bisect.pl /path/to/good/config /path/to/bad/config + +# This will now pull in good config (blowing away .config in that directory +# so do not make that be one of the good or bad configs), and then +# build the config with "make oldconfig" to make sure it matches the +# current kernel. It will then store the configs in that result for +# the good config. It does the same for the bad config as well. +# The algorithm will run, merging half of the differences between +# the two configs and building them with "make oldconfig" to make sure +# the result changes (dependencies may reset changes the tool had made). +# It then copies the result of its good config to /path/to/good/config.tmp +# and the bad config to /path/to/bad/config.tmp (just appends ".tmp" to the +# files passed in). And the ".config" that you should test will be in +# directory + +# After the first run, determine if the result is good or bad then +# run the same command appending the result + +# For good results: +# $ config-bisect.pl /path/to/good/config /path/to/bad/config good + +# For bad results: +# $ config-bisect.pl /path/to/good/config /path/to/bad/config bad + +# Do not change the good-config or bad-config, config-bisect.pl will +# copy the good-config to a temp file with the same name as good-config +# but with a ".tmp" after it. It will do the same with the bad-config. + +# If "good" or "bad" is not stated at the end, it will copy the good and +# bad configs to the .tmp versions. If a .tmp version already exists, it will +# warn before writing over them. If the last config is labeled "good", then +# it will copy it to the good .tmp version. If the last config is labeled +# "bad", it will copy it to the bad .tmp version. It will continue this until +# it can not merge the two any more without the result being equal to either +# the good or bad .tmp configs. + +my $start = 0; +my $val = ""; + +my $pwd = `pwd`; +chomp $pwd; +my $tree = $pwd; +my $build; + +my $output_config; + +sub usage { + print << "EOF" + +usage: config-bisect.pl [-l linux-tree][-b build-dir] good-config bad-config [good|bad] + -l [optional] define location of linux-tree (default is current directory) + -b [optional] define location to build (O=build-dir) (default is linux-tree) + good-config the config that is considered good + bad-config the config that does not work + "good" add this if the last run produced a good config + "bad" add this if the last run produced a bad config + If "good" or "bad" is not specified, then it is the start of a new bisect + + Note, each run will create copy of good and bad configs with ".tmp" appended. + +EOF +; + + exit(-1); +} + +sub doprint { + print @_; +} + +sub dodie { + doprint "CRITICAL FAILURE... ", @_, "\n"; + + die @_, "\n"; +} + +sub expand_path { + my ($file) = @_; + + if ($file =~ m,^/,) { + return $file; + } + return "$pwd/$file"; +} + +sub read_prompt { + my ($cancel, $prompt) = @_; + + my $ans; + + for (;;) { + if ($cancel) { + print "$prompt [y/n/C] "; + } else { + print "$prompt [y/N] "; + } + $ans = ; + chomp $ans; + if ($ans =~ /^\s*$/) { + if ($cancel) { + $ans = "c"; + } else { + $ans = "n"; + } + } + last if ($ans =~ /^y$/i || $ans =~ /^n$/i); + if ($cancel) { + last if ($ans =~ /^c$/i); + print "Please answer either 'y', 'n' or 'c'.\n"; + } else { + print "Please answer either 'y' or 'n'.\n"; + } + } + if ($ans =~ /^c/i) { + exit; + } + if ($ans !~ /^y$/i) { + return 0; + } + return 1; +} + +sub read_yn { + my ($prompt) = @_; + + return read_prompt 0, $prompt; +} + +sub read_ync { + my ($prompt) = @_; + + return read_prompt 1, $prompt; +} + +sub run_command { + my ($command, $redirect) = @_; + my $start_time; + my $end_time; + my $dord = 0; + my $pid; + + $start_time = time; + + doprint("$command ... "); + + $pid = open(CMD, "$command 2>&1 |") or + dodie "unable to exec $command"; + + if (defined($redirect)) { + open (RD, ">$redirect") or + dodie "failed to write to redirect $redirect"; + $dord = 1; + } + + while () { + print RD if ($dord); + } + + waitpid($pid, 0); + my $failed = $?; + + close(CMD); + close(RD) if ($dord); + + $end_time = time; + my $delta = $end_time - $start_time; + + if ($delta == 1) { + doprint "[1 second] "; + } else { + doprint "[$delta seconds] "; + } + + if ($failed) { + doprint "FAILED!\n"; + } else { + doprint "SUCCESS\n"; + } + + return !$failed; +} + +###### CONFIG BISECT ###### + +# config_ignore holds the configs that were set (or unset) for +# a good config and we will ignore these configs for the rest +# of a config bisect. These configs stay as they were. +my %config_ignore; + +# config_set holds what all configs were set as. +my %config_set; + +# config_off holds the set of configs that the bad config had disabled. +# We need to record them and set them in the .config when running +# olddefconfig, because olddefconfig keeps the defaults. +my %config_off; + +# config_off_tmp holds a set of configs to turn off for now +my @config_off_tmp; + +# config_list is the set of configs that are being tested +my %config_list; +my %null_config; + +my %dependency; + +my $make; + +sub make_oldconfig { + + if (!run_command "$make olddefconfig") { + # Perhaps olddefconfig doesn't exist in this version of the kernel + # try oldnoconfig + doprint "olddefconfig failed, trying make oldnoconfig\n"; + if (!run_command "$make oldnoconfig") { + doprint "oldnoconfig failed, trying yes '' | make oldconfig\n"; + # try a yes '' | oldconfig + run_command "yes '' | $make oldconfig" or + dodie "failed make config oldconfig"; + } + } +} + +sub assign_configs { + my ($hash, $config) = @_; + + doprint "Reading configs from $config\n"; + + open (IN, $config) + or dodie "Failed to read $config"; + + while () { + chomp; + if (/^((CONFIG\S*)=.*)/) { + ${$hash}{$2} = $1; + } elsif (/^(# (CONFIG\S*) is not set)/) { + ${$hash}{$2} = $1; + } + } + + close(IN); +} + +sub process_config_ignore { + my ($config) = @_; + + assign_configs \%config_ignore, $config; +} + +sub get_dependencies { + my ($config) = @_; + + my $arr = $dependency{$config}; + if (!defined($arr)) { + return (); + } + + my @deps = @{$arr}; + + foreach my $dep (@{$arr}) { + print "ADD DEP $dep\n"; + @deps = (@deps, get_dependencies $dep); + } + + return @deps; +} + +sub save_config { + my ($pc, $file) = @_; + + my %configs = %{$pc}; + + doprint "Saving configs into $file\n"; + + open(OUT, ">$file") or dodie "Can not write to $file"; + + foreach my $config (keys %configs) { + print OUT "$configs{$config}\n"; + } + close(OUT); +} + +sub create_config { + my ($name, $pc) = @_; + + doprint "Creating old config from $name configs\n"; + + save_config $pc, $output_config; + + make_oldconfig; +} + +# compare two config hashes, and return configs with different vals. +# It returns B's config values, but you can use A to see what A was. +sub diff_config_vals { + my ($pa, $pb) = @_; + + # crappy Perl way to pass in hashes. + my %a = %{$pa}; + my %b = %{$pb}; + + my %ret; + + foreach my $item (keys %a) { + if (defined($b{$item}) && $b{$item} ne $a{$item}) { + $ret{$item} = $b{$item}; + } + } + + return %ret; +} + +# compare two config hashes and return the configs in B but not A +sub diff_configs { + my ($pa, $pb) = @_; + + my %ret; + + # crappy Perl way to pass in hashes. + my %a = %{$pa}; + my %b = %{$pb}; + + foreach my $item (keys %b) { + if (!defined($a{$item})) { + $ret{$item} = $b{$item}; + } + } + + return %ret; +} + +# return if two configs are equal or not +# 0 is equal +1 b has something a does not +# +1 if a and b have a different item. +# -1 if a has something b does not +sub compare_configs { + my ($pa, $pb) = @_; + + my %ret; + + # crappy Perl way to pass in hashes. + my %a = %{$pa}; + my %b = %{$pb}; + + foreach my $item (keys %b) { + if (!defined($a{$item})) { + return 1; + } + if ($a{$item} ne $b{$item}) { + return 1; + } + } + + foreach my $item (keys %a) { + if (!defined($b{$item})) { + return -1; + } + } + + return 0; +} + +sub process_failed { + my ($config) = @_; + + doprint "\n\n***************************************\n"; + doprint "Found bad config: $config\n"; + doprint "***************************************\n\n"; +} + +sub process_new_config { + my ($tc, $nc, $gc, $bc) = @_; + + my %tmp_config = %{$tc}; + my %good_configs = %{$gc}; + my %bad_configs = %{$bc}; + + my %new_configs; + + my $runtest = 1; + my $ret; + + create_config "tmp_configs", \%tmp_config; + assign_configs \%new_configs, $output_config; + + $ret = compare_configs \%new_configs, \%bad_configs; + if (!$ret) { + doprint "New config equals bad config, try next test\n"; + $runtest = 0; + } + + if ($runtest) { + $ret = compare_configs \%new_configs, \%good_configs; + if (!$ret) { + doprint "New config equals good config, try next test\n"; + $runtest = 0; + } + } + + %{$nc} = %new_configs; + + return $runtest; +} + +sub convert_config { + my ($config) = @_; + + if ($config =~ /^# (.*) is not set/) { + $config = "$1=n"; + } + + $config =~ s/^CONFIG_//; + return $config; +} + +sub print_config { + my ($sym, $config) = @_; + + $config = convert_config $config; + doprint "$sym$config\n"; +} + +sub print_config_compare { + my ($good_config, $bad_config) = @_; + + $good_config = convert_config $good_config; + $bad_config = convert_config $bad_config; + + my $good_value = $good_config; + my $bad_value = $bad_config; + $good_value =~ s/(.*)=//; + my $config = $1; + + $bad_value =~ s/.*=//; + + doprint " $config $good_value -> $bad_value\n"; +} + +# Pass in: +# $phalf: half of the configs names you want to add +# $oconfigs: The orginial configs to start with +# $sconfigs: The source to update $oconfigs with (from $phalf) +# $which: The name of which half that is updating (top / bottom) +# $type: The name of the source type (good / bad) +sub make_half { + my ($phalf, $oconfigs, $sconfigs, $which, $type) = @_; + + my @half = @{$phalf}; + my %orig_configs = %{$oconfigs}; + my %source_configs = %{$sconfigs}; + + my %tmp_config = %orig_configs; + + doprint "Settings bisect with $which half of $type configs:\n"; + foreach my $item (@half) { + doprint "Updating $item to $source_configs{$item}\n"; + $tmp_config{$item} = $source_configs{$item}; + } + + return %tmp_config; +} + +sub run_config_bisect { + my ($pgood, $pbad) = @_; + + my %good_configs = %{$pgood}; + my %bad_configs = %{$pbad}; + + my %diff_configs = diff_config_vals \%good_configs, \%bad_configs; + my %b_configs = diff_configs \%good_configs, \%bad_configs; + my %g_configs = diff_configs \%bad_configs, \%good_configs; + + # diff_arr is what is in both good and bad but are different (y->n) + my @diff_arr = keys %diff_configs; + my $len_diff = $#diff_arr + 1; + + # b_arr is what is in bad but not in good (has depends) + my @b_arr = keys %b_configs; + my $len_b = $#b_arr + 1; + + # g_arr is what is in good but not in bad + my @g_arr = keys %g_configs; + my $len_g = $#g_arr + 1; + + my $runtest = 0; + my %new_configs; + my $ret; + + # Look at the configs that are different between good and bad. + # This does not include those that depend on other configs + # (configs depending on other configs that are not set would + # not show up even as a "# CONFIG_FOO is not set" + + + doprint "# of configs to check: $len_diff\n"; + doprint "# of configs showing only in good: $len_g\n"; + doprint "# of configs showing only in bad: $len_b\n"; + + if ($len_diff > 0) { + # Now test for different values + + doprint "Configs left to check:\n"; + doprint " Good Config\t\t\tBad Config\n"; + doprint " -----------\t\t\t----------\n"; + foreach my $item (@diff_arr) { + doprint " $good_configs{$item}\t$bad_configs{$item}\n"; + } + + my $half = int($#diff_arr / 2); + my @tophalf = @diff_arr[0 .. $half]; + + doprint "Set tmp config to be good config with some bad config values\n"; + + my %tmp_config = make_half \@tophalf, \%good_configs, + \%bad_configs, "top", "bad"; + + $runtest = process_new_config \%tmp_config, \%new_configs, + \%good_configs, \%bad_configs; + + if (!$runtest) { + doprint "Set tmp config to be bad config with some good config values\n"; + + my %tmp_config = make_half \@tophalf, \%bad_configs, + \%good_configs, "top", "good"; + + $runtest = process_new_config \%tmp_config, \%new_configs, + \%good_configs, \%bad_configs; + } + } + + if (!$runtest && $len_diff > 0) { + # do the same thing, but this time with bottom half + + my $half = int($#diff_arr / 2); + my @bottomhalf = @diff_arr[$half+1 .. $#diff_arr]; + + doprint "Set tmp config to be good config with some bad config values\n"; + + my %tmp_config = make_half \@bottomhalf, \%good_configs, + \%bad_configs, "bottom", "bad"; + + $runtest = process_new_config \%tmp_config, \%new_configs, + \%good_configs, \%bad_configs; + + if (!$runtest) { + doprint "Set tmp config to be bad config with some good config values\n"; + + my %tmp_config = make_half \@bottomhalf, \%bad_configs, + \%good_configs, "bottom", "good"; + + $runtest = process_new_config \%tmp_config, \%new_configs, + \%good_configs, \%bad_configs; + } + } + + if ($runtest) { + make_oldconfig; + doprint "READY TO TEST .config IN $build\n"; + return 0; + } + + doprint "\n%%%%%%%% FAILED TO FIND SINGLE BAD CONFIG %%%%%%%%\n"; + doprint "Hmm, can't make any more changes without making good == bad?\n"; + doprint "Difference between good (+) and bad (-)\n"; + + foreach my $item (keys %bad_configs) { + if (!defined($good_configs{$item})) { + print_config "-", $bad_configs{$item}; + } + } + + foreach my $item (keys %good_configs) { + next if (!defined($bad_configs{$item})); + if ($good_configs{$item} ne $bad_configs{$item}) { + print_config_compare $good_configs{$item}, $bad_configs{$item}; + } + } + + foreach my $item (keys %good_configs) { + if (!defined($bad_configs{$item})) { + print_config "+", $good_configs{$item}; + } + } + return -1; +} + +sub config_bisect { + my ($good_config, $bad_config) = @_; + my $ret; + + my %good_configs; + my %bad_configs; + my %tmp_configs; + + doprint "Run good configs through make oldconfig\n"; + assign_configs \%tmp_configs, $good_config; + create_config "$good_config", \%tmp_configs; + assign_configs \%good_configs, $output_config; + + doprint "Run bad configs through make oldconfig\n"; + assign_configs \%tmp_configs, $bad_config; + create_config "$bad_config", \%tmp_configs; + assign_configs \%bad_configs, $output_config; + + save_config \%good_configs, $good_config; + save_config \%bad_configs, $bad_config; + + return run_config_bisect \%good_configs, \%bad_configs; +} + +while ($#ARGV >= 0) { + if ($ARGV[0] !~ m/^-/) { + last; + } + my $opt = shift @ARGV; + + if ($opt eq "-b") { + $val = shift @ARGV; + if (!defined($val)) { + die "-b requires value\n"; + } + $build = $val; + } + + elsif ($opt eq "-l") { + $val = shift @ARGV; + if (!defined($val)) { + die "-l requires value\n"; + } + $tree = $val; + } + + elsif ($opt eq "-h") { + usage; + } + + else { + die "Unknow option $opt\n"; + } +} + +$build = $tree if (!defined($build)); + +$tree = expand_path $tree; +$build = expand_path $build; + +if ( ! -d $tree ) { + die "$tree not a directory\n"; +} + +if ( ! -d $build ) { + die "$build not a directory\n"; +} + +usage if $#ARGV < 1; + +if ($#ARGV == 1) { + $start = 1; +} elsif ($#ARGV == 2) { + $val = $ARGV[2]; + if ($val ne "good" && $val ne "bad") { + die "Unknown command '$val', bust be either \"good\" or \"bad\"\n"; + } +} else { + usage; +} + +my $good_start = expand_path $ARGV[0]; +my $bad_start = expand_path $ARGV[1]; + +my $good = "$good_start.tmp"; +my $bad = "$bad_start.tmp"; + +$make = "make"; + +if ($build ne $tree) { + $make = "make O=$build" +} + +$output_config = "$build/.config"; + +if ($start) { + if ( ! -f $good_start ) { + die "$good_start not found\n"; + } + if ( ! -f $bad_start ) { + die "$bad_start not found\n"; + } + if ( -f $good || -f $bad ) { + my $p = ""; + + if ( -f $good ) { + $p = "$good exists\n"; + } + + if ( -f $bad ) { + $p = "$p$bad exists\n"; + } + + if (!read_yn "${p}Overwrite and start new bisect anyway?") { + exit (-1); + } + } + run_command "cp $good_start $good" or die "failed to copy to $good\n"; + run_command "cp $bad_start $bad" or die "faield to copy to $bad\n"; +} else { + if ( ! -f $good ) { + die "Can not find file $good\n"; + } + if ( ! -f $bad ) { + die "Can not find file $bad\n"; + } + if ($val eq "good") { + run_command "cp $output_config $good" or die "failed to copy $config to $good\n"; + } elsif ($val eq "bad") { + run_command "cp $output_config $bad" or die "failed to copy $config to $bad\n"; + } +} + +chdir $tree || die "can't change directory to $tree"; + +my $ret = config_bisect $good, $bad; + +if (!$ret) { + exit(0); +} + +if ($ret > 0) { + doprint "Cleaning temp files\n"; + run_command "rm $good"; + run_command "rm $bad"; + exit(1); +} else { + doprint "See good and bad configs for details:\n"; + doprint "good: $good\n"; + doprint "bad: $bad\n"; + doprint "%%%%%%%% FAILED TO FIND SINGLE BAD CONFIG %%%%%%%%\n"; +} +exit(2); -- cgit v1.3-14-g43fede From a9adc261e978b9214fd505030c24e75b07dcf52f Mon Sep 17 00:00:00 2001 From: Scott Wood Date: Sun, 16 Jul 2017 19:16:30 -0500 Subject: ktest: Use config-bisect.pl in ktest.pl Reduce code duplication and take advantage of bisection logic improvements by calling config-bisect.pl. The output of make oldconfig is now copied directly to the desired file, rather than doing assign_configs+save_config, in order to preserve the ordering so that diffing the configs at the end will provide useful output. Link: http://lkml.kernel.org/r/20170717001630.10518-8-swood@redhat.com Signed-off-by: Scott Wood [ Modified to use with new version of config-bisect.pl ] Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 264 +++++++------------------------------------ 1 file changed, 42 insertions(+), 222 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index f597f9b4e8d5..ad00ce699749 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -3092,76 +3092,6 @@ sub create_config { make_oldconfig; } -# compare two config hashes, and return configs with different vals. -# It returns B's config values, but you can use A to see what A was. -sub diff_config_vals { - my ($pa, $pb) = @_; - - # crappy Perl way to pass in hashes. - my %a = %{$pa}; - my %b = %{$pb}; - - my %ret; - - foreach my $item (keys %a) { - if (defined($b{$item}) && $b{$item} ne $a{$item}) { - $ret{$item} = $b{$item}; - } - } - - return %ret; -} - -# compare two config hashes and return the configs in B but not A -sub diff_configs { - my ($pa, $pb) = @_; - - my %ret; - - # crappy Perl way to pass in hashes. - my %a = %{$pa}; - my %b = %{$pb}; - - foreach my $item (keys %b) { - if (!defined($a{$item})) { - $ret{$item} = $b{$item}; - } - } - - return %ret; -} - -# return if two configs are equal or not -# 0 is equal +1 b has something a does not -# +1 if a and b have a different item. -# -1 if a has something b does not -sub compare_configs { - my ($pa, $pb) = @_; - - my %ret; - - # crappy Perl way to pass in hashes. - my %a = %{$pa}; - my %b = %{$pb}; - - foreach my $item (keys %b) { - if (!defined($a{$item})) { - return 1; - } - if ($a{$item} ne $b{$item}) { - return 1; - } - } - - foreach my $item (keys %a) { - if (!defined($b{$item})) { - return -1; - } - } - - return 0; -} - sub run_config_bisect_test { my ($type) = @_; @@ -3174,166 +3104,49 @@ sub run_config_bisect_test { return $ret; } -sub process_failed { - my ($config) = @_; +sub config_bisect_end { + my ($good, $bad) = @_; doprint "\n\n***************************************\n"; - doprint "Found bad config: $config\n"; + doprint "No more config bisecting possible.\n"; + doprint `diff -u $good $bad`; doprint "***************************************\n\n"; } -# used for config bisecting -my $good_config; -my $bad_config; - -sub process_new_config { - my ($tc, $nc, $gc, $bc) = @_; - - my %tmp_config = %{$tc}; - my %good_configs = %{$gc}; - my %bad_configs = %{$bc}; - - my %new_configs; - - my $runtest = 1; - my $ret; - - create_config "tmp_configs", \%tmp_config; - assign_configs \%new_configs, $output_config; - - $ret = compare_configs \%new_configs, \%bad_configs; - if (!$ret) { - doprint "New config equals bad config, try next test\n"; - $runtest = 0; - } - - if ($runtest) { - $ret = compare_configs \%new_configs, \%good_configs; - if (!$ret) { - doprint "New config equals good config, try next test\n"; - $runtest = 0; - } - } - - %{$nc} = %new_configs; - - return $runtest; -} - sub run_config_bisect { - my ($pgood, $pbad) = @_; - - my $type = $config_bisect_type; - - my %good_configs = %{$pgood}; - my %bad_configs = %{$pbad}; - - my %diff_configs = diff_config_vals \%good_configs, \%bad_configs; - my %b_configs = diff_configs \%good_configs, \%bad_configs; - my %g_configs = diff_configs \%bad_configs, \%good_configs; - - my @diff_arr = keys %diff_configs; - my $len_diff = $#diff_arr + 1; - - my @b_arr = keys %b_configs; - my $len_b = $#b_arr + 1; - - my @g_arr = keys %g_configs; - my $len_g = $#g_arr + 1; - - my $runtest = 1; - my %new_configs; + my ($good, $bad, $last_result) = @_; + my $cmd; my $ret; - # First, lets get it down to a single subset. - # Is the problem with a difference in values? - # Is the problem with a missing config? - # Is the problem with a config that breaks things? - - # Enable all of one set and see if we get a new bad - # or good config. - - # first set the good config to the bad values. - - doprint "d=$len_diff g=$len_g b=$len_b\n"; - - # first lets enable things in bad config that are enabled in good config - - if ($len_diff > 0) { - if ($len_b > 0 || $len_g > 0) { - my %tmp_config = %bad_configs; - - doprint "Set tmp config to be bad config with good config values\n"; - foreach my $item (@diff_arr) { - $tmp_config{$item} = $good_configs{$item}; - } - - $runtest = process_new_config \%tmp_config, \%new_configs, - \%good_configs, \%bad_configs; - } - } - - if (!$runtest && $len_diff > 0) { - - if ($len_diff == 1) { - process_failed $diff_arr[0]; - return 1; - } - my %tmp_config = %bad_configs; - - my $half = int($#diff_arr / 2); - my @tophalf = @diff_arr[0 .. $half]; - - doprint "Settings bisect with top half:\n"; - doprint "Set tmp config to be bad config with some good config values\n"; - foreach my $item (@tophalf) { - $tmp_config{$item} = $good_configs{$item}; - } - - $runtest = process_new_config \%tmp_config, \%new_configs, - \%good_configs, \%bad_configs; - - if (!$runtest) { - my %tmp_config = %bad_configs; - - doprint "Try bottom half\n"; - - my @bottomhalf = @diff_arr[$half+1 .. $#diff_arr]; - - foreach my $item (@bottomhalf) { - $tmp_config{$item} = $good_configs{$item}; - } + run_command "$builddir/tools/testing/ktest/config-bisect.pl -b $outputdir $good $bad $last_result"; - $runtest = process_new_config \%tmp_config, \%new_configs, - \%good_configs, \%bad_configs; - } + # config-bisect returns: + # 0 if there is more to bisect + # 1 for finding a good config + # 2 if it can not find any more configs + # -1 (255) on error + if ($run_command_status) { + return $run_command_status; } - if ($runtest) { - $ret = run_config_bisect_test $type; - if ($ret) { - doprint "NEW GOOD CONFIG\n"; - %good_configs = %new_configs; - run_command "mv $good_config ${good_config}.last"; - save_config \%good_configs, $good_config; - %{$pgood} = %good_configs; - } else { - doprint "NEW BAD CONFIG\n"; - %bad_configs = %new_configs; - run_command "mv $bad_config ${bad_config}.last"; - save_config \%bad_configs, $bad_config; - %{$pbad} = %bad_configs; - } - return 0; + $ret = run_config_bisect_test $config_bisect_type; + if ($ret) { + doprint "NEW GOOD CONFIG\n"; + # Return 3 for good config + return 3; + } else { + doprint "NEW BAD CONFIG\n"; + # Return 4 for bad config + return 4; } - - fail "Hmm, need to do a mix match?\n"; - return -1; } sub config_bisect { my ($i) = @_; + my $good_config; + my $bad_config; + my $type = $config_bisect_type; my $ret; @@ -3364,18 +3177,14 @@ sub config_bisect { doprint "Run good configs through make oldconfig\n"; assign_configs \%tmp_configs, $good_config; create_config "$good_config", \%tmp_configs; - assign_configs \%good_configs, $output_config; + $good_config = "$tmpdir/good_config"; + system("cp $output_config $good_config") == 0 or dodie "cp good config"; doprint "Run bad configs through make oldconfig\n"; assign_configs \%tmp_configs, $bad_config; create_config "$bad_config", \%tmp_configs; - assign_configs \%bad_configs, $output_config; - - $good_config = "$tmpdir/good_config"; $bad_config = "$tmpdir/bad_config"; - - save_config \%good_configs, $good_config; - save_config \%bad_configs, $bad_config; + system("cp $output_config $bad_config") == 0 or dodie "cp bad config"; if (defined($config_bisect_check) && $config_bisect_check ne "0") { if ($config_bisect_check ne "good") { @@ -3398,10 +3207,21 @@ sub config_bisect { } } + my $last_run = ""; + do { - $ret = run_config_bisect \%good_configs, \%bad_configs; + $ret = run_config_bisect $good_config, $bad_config, $last_run; + if ($ret == 3) { + $last_run = "good"; + } elsif ($ret == 4) { + $last_run = "bad"; + } print_times; - } while (!$ret); + } while ($ret == 3 || $ret == 4); + + if ($ret == 2) { + config_bisect_end "$good_config.tmp", "$bad_config.tmp"; + } return $ret if ($ret < 0); -- cgit v1.3-14-g43fede From b337f9790a0c8f0f01abf9fe3e1f48894b773899 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Thu, 22 Mar 2018 16:28:18 -0400 Subject: ktest.pl: Allow for the config-bisect.pl output to display to console When commands are run in ktest, they are only displayed in the ktest log file, but that is not sufficient for outputting the display for config bisects. The result of a config bisect is not shown. Add a way to display the output of "run_command" which is the subroutine used by ktest to execute commands. Use this feature to display the output of config-bisect.pl executions to see the progress as well as the result. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index ad00ce699749..79c2f99629de 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1692,6 +1692,7 @@ sub run_command { my $end_time; my $dolog = 0; my $dord = 0; + my $dostdout = 0; my $pid; $command =~ s/\$SSH_USER/$ssh_user/g; @@ -1710,9 +1711,15 @@ sub run_command { } if (defined($redirect)) { - open (RD, ">$redirect") or - dodie "failed to write to redirect $redirect"; - $dord = 1; + if ($redirect eq 1) { + $dostdout = 1; + # Have the output of the command on its own line + doprint "\n"; + } else { + open (RD, ">$redirect") or + dodie "failed to write to redirect $redirect"; + $dord = 1; + } } my $hit_timeout = 0; @@ -1734,6 +1741,7 @@ sub run_command { } print LOG $line if ($dolog); print RD $line if ($dord); + print $line if ($dostdout); } waitpid($pid, 0); @@ -3118,7 +3126,7 @@ sub run_config_bisect { my $cmd; my $ret; - run_command "$builddir/tools/testing/ktest/config-bisect.pl -b $outputdir $good $bad $last_result"; + run_command "$builddir/tools/testing/ktest/config-bisect.pl -b $outputdir $good $bad $last_result", 1; # config-bisect returns: # 0 if there is more to bisect -- cgit v1.3-14-g43fede From b2b07ea282721b6c7bed21e95e2c00dd95cb8520 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Thu, 22 Mar 2018 16:36:34 -0400 Subject: ktest.pl: Use diffconfig if available for failed config bisects Check to see if diffconfig is available and use that to diff the configs instead of using 'diff -u', as diffconfig produces much better output of kernel config files. It checks the source directory for the executable. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 79c2f99629de..27505fef2dab 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -3114,10 +3114,14 @@ sub run_config_bisect_test { sub config_bisect_end { my ($good, $bad) = @_; + my $diffexec = "diff -u"; + if (-f "$builddir/scripts/diffconfig") { + $diffexec = "$builddir/scripts/diffconfig"; + } doprint "\n\n***************************************\n"; doprint "No more config bisecting possible.\n"; - doprint `diff -u $good $bad`; + run_command "$diffexec $good $bad", 1; doprint "***************************************\n\n"; } -- cgit v1.3-14-g43fede From 133087f0623e927dfdf439a1b6a4e819a7a5f3ea Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Wed, 4 Apr 2018 15:42:08 -0400 Subject: ktest.pl: Have ktest.pl pass -r to config-bisect.pl to reset bisect If config-bisect.pl sees that a config_bisect has already been started, it will ask on the command line if it should bisect or not. This will mess up running config_bisect from ktest.pl. Have ktest.pl pass in '-r' to config-bisect.pl and have config-bisect.pl recognize that to reset without asking. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/config-bisect.pl | 21 ++++++++++++++------- tools/testing/ktest/ktest.pl | 6 +++++- 2 files changed, 19 insertions(+), 8 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/config-bisect.pl b/tools/testing/ktest/config-bisect.pl index 37cd796efa2b..b28feea7c363 100755 --- a/tools/testing/ktest/config-bisect.pl +++ b/tools/testing/ktest/config-bisect.pl @@ -52,11 +52,11 @@ # If "good" or "bad" is not stated at the end, it will copy the good and # bad configs to the .tmp versions. If a .tmp version already exists, it will -# warn before writing over them. If the last config is labeled "good", then -# it will copy it to the good .tmp version. If the last config is labeled -# "bad", it will copy it to the bad .tmp version. It will continue this until -# it can not merge the two any more without the result being equal to either -# the good or bad .tmp configs. +# warn before writing over them (-r will not warn, and just write over them). +# If the last config is labeled "good", then it will copy it to the good .tmp +# version. If the last config is labeled "bad", it will copy it to the bad +# .tmp version. It will continue this until it can not merge the two any more +# without the result being equal to either the good or bad .tmp configs. my $start = 0; my $val = ""; @@ -67,6 +67,7 @@ my $tree = $pwd; my $build; my $output_config; +my $reset_bisect; sub usage { print << "EOF" @@ -654,6 +655,10 @@ while ($#ARGV >= 0) { $tree = $val; } + elsif ($opt eq "-r") { + $reset_bisect = 1; + } + elsif ($opt eq "-h") { usage; } @@ -721,8 +726,10 @@ if ($start) { $p = "$p$bad exists\n"; } - if (!read_yn "${p}Overwrite and start new bisect anyway?") { - exit (-1); + if (!defined($reset_bisect)) { + if (!read_yn "${p}Overwrite and start new bisect anyway?") { + exit (-1); + } } } run_command "cp $good_start $good" or die "failed to copy to $good\n"; diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 27505fef2dab..fe6a7bb7d7d9 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -3127,10 +3127,14 @@ sub config_bisect_end { sub run_config_bisect { my ($good, $bad, $last_result) = @_; + my $reset = ""; my $cmd; my $ret; - run_command "$builddir/tools/testing/ktest/config-bisect.pl -b $outputdir $good $bad $last_result", 1; + if (!length($last_result)) { + $reset = "-r"; + } + run_command "$builddir/tools/testing/ktest/config-bisect.pl $reset -b $outputdir $good $bad $last_result", 1; # config-bisect returns: # 0 if there is more to bisect -- cgit v1.3-14-g43fede From 40667fb5fda0483e5c617d133968b17f6854cb9b Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Thu, 5 Apr 2018 12:14:39 -0400 Subject: ktest.pl: Make finding config-bisect.pl dynamic Just looking for config-bisect.pl in the source tree can be risky, especially, if the source tree being tested doesn't have config-bisect.pl in place. Instead, allow the user to set where to find config-bisect.pl with a new option CONFIG_BISECT_EXEC. If this option is not set, by default, ktest.pl will look for config-bisect.pl in the following locations: `pwd`/config-bisect.pl # where ktest.pl was called from `dirname /path/to/ktest.pl`/config-bisect.pl # where ktest.pl exists ${BUILD_DIR}/tools/testing/ktest/config-bisect.pl # where config-bisect.pl exists in the source tree. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 27 ++++++++++++++++++++++++++- tools/testing/ktest/sample.conf | 10 ++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index fe6a7bb7d7d9..e04422d8f844 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -10,6 +10,7 @@ use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); use File::Path qw(mkpath); use File::Copy qw(cp); use FileHandle; +use FindBin; my $VERSION = "0.2"; @@ -165,6 +166,7 @@ my $store_successes; my $test_name; my $timeout; my $connect_timeout; +my $config_bisect_exec; my $booted_timeout; my $detect_triplefault; my $console; @@ -206,6 +208,9 @@ my $install_time; my $reboot_time; my $test_time; +my $pwd; +my $dirname = $FindBin::Bin; + # set when a test is something other that just building or install # which would require more options. my $buildonly = 1; @@ -299,6 +304,7 @@ my %option_map = ( "TEST_NAME" => \$test_name, "TIMEOUT" => \$timeout, "CONNECT_TIMEOUT" => \$connect_timeout, + "CONFIG_BISECT_EXEC" => \$config_bisect_exec, "BOOTED_TIMEOUT" => \$booted_timeout, "CONSOLE" => \$console, "CLOSE_CONSOLE_SIGNAL" => \$close_console_signal, @@ -340,6 +346,7 @@ my %used_options; # default variables that can be used chomp ($variable{"PWD"} = `pwd`); +$pwd = $variable{"PWD"}; $config_help{"MACHINE"} = << "EOF" The machine hostname that you will test. @@ -3134,7 +3141,7 @@ sub run_config_bisect { if (!length($last_result)) { $reset = "-r"; } - run_command "$builddir/tools/testing/ktest/config-bisect.pl $reset -b $outputdir $good $bad $last_result", 1; + run_command "$config_bisect_exec $reset -b $outputdir $good $bad $last_result", 1; # config-bisect returns: # 0 if there is more to bisect @@ -3182,6 +3189,24 @@ sub config_bisect { $good_config = $output_config; } + if (!defined($config_bisect_exec)) { + # First check the location that ktest.pl ran + my @locations = ( "$pwd/config-bisect.pl", + "$dirname/config-bisect.pl", + "$builddir/tools/testing/ktest/config-bisect.pl", + undef ); + foreach my $loc (@locations) { + doprint "loc = $loc\n"; + $config_bisect_exec = $loc; + last if (defined($config_bisect_exec && -x $config_bisect_exec)); + } + if (!defined($config_bisect_exec)) { + fail "Could not find an executable config-bisect.pl\n", + " Set CONFIG_BISECT_EXEC to point to config-bisect.pl"; + return 1; + } + } + # we don't want min configs to cause issues here. doprint "Disabling 'MIN_CONFIG' for this test\n"; undef $minconfig; diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 695983a72465..f5b58addb1d1 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -1179,6 +1179,16 @@ # Set it to "good" to test only the good config and set it # to "bad" to only test the bad config. # +# CONFIG_BISECT_EXEC (optional) +# The config bisect is a separate program that comes with ktest.pl. +# By befault, it will look for: +# `pwd`/config-bisect.pl # the location ktest.pl was executed from. +# If it does not find it there, it will look for: +# `dirname `/config-bisect.pl # The directory that holds ktest.pl +# If it does not find it there, it will look for: +# ${BUILD_DIR}/tools/testing/ktest/config-bisect.pl +# Setting CONFIG_BISECT_EXEC will override where it looks. +# # Example: # TEST_START # TEST_TYPE = config_bisect -- cgit v1.3-14-g43fede From 5a57299a1f084bbe7e3e9cafb06999793c4a40fb Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Thu, 5 Apr 2018 14:51:42 -0400 Subject: ktest.pl: Detect if a config-bisect was interrupted If a config-bisect was interrupted, then allow the user to continue, or restart a new config-bisect. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index e04422d8f844..d4b22b5c425b 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -3215,6 +3215,20 @@ sub config_bisect { my %bad_configs; my %tmp_configs; + if (-f "$tmpdir/good_config.tmp" || -f "$tmpdir/bad_config.tmp") { + if (read_yn "Interrupted config-bisect. Continue (n - will start new)?") { + if (-f "$tmpdir/good_config.tmp") { + $good_config = "$tmpdir/good_config.tmp"; + } else { + $good_config = "$tmpdir/good_config"; + } + if (-f "$tmpdir/bad_config.tmp") { + $bad_config = "$tmpdir/bad_config.tmp"; + } else { + $bad_config = "$tmpdir/bad_config"; + } + } + } doprint "Run good configs through make oldconfig\n"; assign_configs \%tmp_configs, $good_config; create_config "$good_config", \%tmp_configs; -- cgit v1.3-14-g43fede From 2ceb2d85b6697e2a3485047d1c908a4908069411 Mon Sep 17 00:00:00 2001 From: Tim Tianyang Chen Date: Mon, 26 Mar 2018 13:08:01 -0700 Subject: Ktest: Add email support Users can define optional variables to get email notifications. Ktest can send emails when the script: * was started * failed with fatal errors and called dodie() * completed all testing Users have to setup the mailer provided in config prior to using this script. Supported mailers: mailx, mail, sendmail mailer specific routines are _sendmail_send(), _mailx_send() Link: http://lkml.kernel.org/r/1522094884-22718-2-git-send-email-tianyang.chen@oracle.com Suggested-by: Dhaval Giani Signed-off-by: Tim Tianyang Chen Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 61 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index d4b22b5c425b..bb43f8631c95 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -23,6 +23,11 @@ my %evals; #default opts my %default = ( + "MAILER" => "sendmail", # default mailer + "EMAIL_ON_ERROR" => 1, + "EMAIL_WHEN_FINISHED" => 1, + "EMAIL_WHEN_CANCELED" => 0, + "EMAIL_WHEN_STARTED" => 0, "NUM_TESTS" => 1, "TEST_TYPE" => "build", "BUILD_TYPE" => "randconfig", @@ -211,6 +216,15 @@ my $test_time; my $pwd; my $dirname = $FindBin::Bin; +my $mailto; +my $mailer; +my $email_on_error; +my $email_when_finished; +my $email_when_started; +my $email_when_canceled; + +my $script_start_time = localtime(); + # set when a test is something other that just building or install # which would require more options. my $buildonly = 1; @@ -236,6 +250,12 @@ my $no_reboot = 1; my $reboot_success = 0; my %option_map = ( + "MAILTO" => \$mailto, + "MAILER" => \$mailer, + "EMAIL_ON_ERROR" => \$email_on_error, + "EMAIL_WHEN_FINISHED" => \$email_when_finished, + "EMAIL_WHEN_STARTED" => \$email_when_started, + "EMAIL_WHEN_CANCELED" => \$email_when_canceled, "MACHINE" => \$machine, "SSH_USER" => \$ssh_user, "TMP_DIR" => \$tmpdir, @@ -1430,6 +1450,11 @@ sub dodie { print " See $opt{LOG_FILE} for more info.\n"; } + if ($email_on_error) { + send_email("KTEST: critical failure for your [$test_type] test", + "Your test started at $script_start_time has failed with:\n@_\n"); + } + if ($monitor_cnt) { # restore terminal settings system("stty $stty_orig"); @@ -4099,6 +4124,26 @@ sub set_test_option { return eval_option($name, $option, $i); } +sub _mailx_send { + my ($subject, $message) = @_; + system("$mailer -s \'$subject\' $mailto <<< \'$message\'"); +} + +sub _sendmail_send { + my ($subject, $message) = @_; + system("echo -e \"Subject: $subject\n\n$message\" | sendmail -t $mailto"); +} + +sub send_email { + if (defined($mailto) && defined($mailer)) { + if ($mailer eq "mail" || $mailer eq "mailx"){ _mailx_send(@_);} + elsif ($mailer eq "sendmail" ) { _sendmail_send(@_);} + else { doprint "\nYour mailer: $mailer is not supported.\n" } + } else { + print "No email sent: email or mailer not specified in config.\n" + } +} + # First we need to do is the builds for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { @@ -4139,9 +4184,15 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $start_minconfig_defined = 1; # The first test may override the PRE_KTEST option - if (defined($pre_ktest) && $i == 1) { - doprint "\n"; - run_command $pre_ktest; + if ($i == 1) { + if (defined($pre_ktest)) { + doprint "\n"; + run_command $pre_ktest; + } + if ($email_when_started) { + send_email("KTEST: Your [$test_type] test was started", + "Your test was started on $script_start_time"); + } } # Any test can override the POST_KTEST option @@ -4305,4 +4356,8 @@ if ($opt{"POWEROFF_ON_SUCCESS"}) { doprint "\n $successes of $opt{NUM_TESTS} tests were successful\n\n"; +if ($email_when_finished) { + send_email("KTEST: Your [$test_type] test has finished!", + "$successes of $opt{NUM_TESTS} tests started at $script_start_time were successful!"); +} exit 0; -- cgit v1.3-14-g43fede From 92db453e7eeb44efd43e977fa5ab417274834a9a Mon Sep 17 00:00:00 2001 From: Tim Tianyang Chen Date: Mon, 26 Mar 2018 13:08:02 -0700 Subject: Ktest: Add SigInt handling User can cancel tests and specify handler's behavior using option 'EMAIL_WHEN_CANCELED'. Link: http://lkml.kernel.org/r/1522094884-22718-3-git-send-email-tianyang.chen@oracle.com Suggested-by: Dhaval Giani Signed-off-by: Tim Tianyang Chen Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index bb43f8631c95..1646af526089 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -4144,6 +4144,16 @@ sub send_email { } } +sub cancel_test { + if ($email_when_canceled) { + send_email("KTEST: Your [$test_type] test was cancelled", + "Your test started at $script_start_time was cancelled: sig int"); + } + die "\nCaught Sig Int, test interrupted: $!\n" +} + +$SIG{INT} = qw(cancel_test); + # First we need to do is the builds for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { -- cgit v1.3-14-g43fede From df46fce692a649559d64da2826d355b4f28fc526 Mon Sep 17 00:00:00 2001 From: Tim Tianyang Chen Date: Mon, 26 Mar 2018 13:08:03 -0700 Subject: Ktest: Use dodie for critical falures Users should get emails when the script dies because of a critical failure. Critical failures are defined as any errors that could abnormally terminate the script. In order to add email support, this patch converts all die() to dodie() except: * when '-v' is used as an option to get the version of the script. * in Sig-Int handeler because it's not a fatal error to cancel the script. * errors happen during parsing config Link: http://lkml.kernel.org/r/1522094884-22718-4-git-send-email-tianyang.chen@oracle.com Suggested-by: Dhaval Giani Signed-off-by: Tim Tianyang Chen Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 54 ++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 27 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 1646af526089..30a4c053f98b 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1506,7 +1506,7 @@ sub exec_console { close($pts); exec $console or - die "Can't open console $console"; + dodie "Can't open console $console"; } sub open_console { @@ -1657,7 +1657,7 @@ sub save_logs { if (!-d $dir) { mkpath($dir) or - die "can't create $dir"; + dodie "can't create $dir"; } my %files = ( @@ -1670,7 +1670,7 @@ sub save_logs { while (my ($name, $source) = each(%files)) { if (-f "$source") { cp "$source", "$dir/$name" or - die "failed to copy $source"; + dodie "failed to copy $source"; } } @@ -1852,7 +1852,7 @@ sub get_grub2_index { $ssh_grub =~ s,\$SSH_COMMAND,cat $grub_file,g; open(IN, "$ssh_grub |") - or die "unable to get $grub_file"; + or dodie "unable to get $grub_file"; my $found = 0; @@ -1867,7 +1867,7 @@ sub get_grub2_index { } close(IN); - die "Could not find '$grub_menu' in $grub_file on $machine" + dodie "Could not find '$grub_menu' in $grub_file on $machine" if (!$found); doprint "$grub_number\n"; $last_grub_menu = $grub_menu; @@ -1895,7 +1895,7 @@ sub get_grub_index { $ssh_grub =~ s,\$SSH_COMMAND,cat /boot/grub/menu.lst,g; open(IN, "$ssh_grub |") - or die "unable to get menu.lst"; + or dodie "unable to get menu.lst"; my $found = 0; @@ -1910,7 +1910,7 @@ sub get_grub_index { } close(IN); - die "Could not find '$grub_menu' in /boot/grub/menu on $machine" + dodie "Could not find '$grub_menu' in /boot/grub/menu on $machine" if (!$found); doprint "$grub_number\n"; $last_grub_menu = $grub_menu; @@ -2023,7 +2023,7 @@ sub monitor { my $full_line = ""; open(DMESG, "> $dmesg") or - die "unable to write to $dmesg"; + dodie "unable to write to $dmesg"; reboot_to; @@ -2902,7 +2902,7 @@ sub run_bisect { sub update_bisect_replay { my $tmp_log = "$tmpdir/ktest_bisect_log"; run_command "git bisect log > $tmp_log" or - die "can't create bisect log"; + dodie "can't create bisect log"; return $tmp_log; } @@ -2911,9 +2911,9 @@ sub bisect { my $result; - die "BISECT_GOOD[$i] not defined\n" if (!defined($bisect_good)); - die "BISECT_BAD[$i] not defined\n" if (!defined($bisect_bad)); - die "BISECT_TYPE[$i] not defined\n" if (!defined($bisect_type)); + dodie "BISECT_GOOD[$i] not defined\n" if (!defined($bisect_good)); + dodie "BISECT_BAD[$i] not defined\n" if (!defined($bisect_bad)); + dodie "BISECT_TYPE[$i] not defined\n" if (!defined($bisect_type)); my $good = $bisect_good; my $bad = $bisect_bad; @@ -2976,7 +2976,7 @@ sub bisect { if ($check ne "good") { doprint "TESTING BISECT BAD [$bad]\n"; run_command "git checkout $bad" or - die "Failed to checkout $bad"; + dodie "Failed to checkout $bad"; $result = run_bisect $type; @@ -2988,7 +2988,7 @@ sub bisect { if ($check ne "bad") { doprint "TESTING BISECT GOOD [$good]\n"; run_command "git checkout $good" or - die "Failed to checkout $good"; + dodie "Failed to checkout $good"; $result = run_bisect $type; @@ -2999,7 +2999,7 @@ sub bisect { # checkout where we started run_command "git checkout $head" or - die "Failed to checkout $head"; + dodie "Failed to checkout $head"; } run_command "git bisect start$start_files" or @@ -3316,9 +3316,9 @@ sub patchcheck_reboot { sub patchcheck { my ($i) = @_; - die "PATCHCHECK_START[$i] not defined\n" + dodie "PATCHCHECK_START[$i] not defined\n" if (!defined($patchcheck_start)); - die "PATCHCHECK_TYPE[$i] not defined\n" + dodie "PATCHCHECK_TYPE[$i] not defined\n" if (!defined($patchcheck_type)); my $start = $patchcheck_start; @@ -3332,7 +3332,7 @@ sub patchcheck { if (defined($patchcheck_end)) { $end = $patchcheck_end; } elsif ($cherry) { - die "PATCHCHECK_END must be defined with PATCHCHECK_CHERRY\n"; + dodie "PATCHCHECK_END must be defined with PATCHCHECK_CHERRY\n"; } # Get the true sha1's since we can use things like HEAD~3 @@ -3396,7 +3396,7 @@ sub patchcheck { doprint "\nProcessing commit \"$item\"\n\n"; run_command "git checkout $sha1" or - die "Failed to checkout $sha1"; + dodie "Failed to checkout $sha1"; # only clean on the first and last patch if ($item eq $list[0] || @@ -3487,7 +3487,7 @@ sub read_kconfig { } open(KIN, "$kconfig") - or die "Can't open $kconfig"; + or dodie "Can't open $kconfig"; while () { chomp; @@ -3648,7 +3648,7 @@ sub get_depends { $dep =~ s/^[^$valid]*[$valid]+//; } else { - die "this should never happen"; + dodie "this should never happen"; } } @@ -3909,7 +3909,7 @@ sub make_min_config { # update new ignore configs if (defined($ignore_config)) { open (OUT, ">$temp_config") - or die "Can't write to $temp_config"; + or dodie "Can't write to $temp_config"; foreach my $config (keys %save_configs) { print OUT "$save_configs{$config}\n"; } @@ -3937,7 +3937,7 @@ sub make_min_config { # Save off all the current mandatory configs open (OUT, ">$temp_config") - or die "Can't write to $temp_config"; + or dodie "Can't write to $temp_config"; foreach my $config (keys %keep_configs) { print OUT "$keep_configs{$config}\n"; } @@ -4177,11 +4177,11 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { $outputdir = set_test_option("OUTPUT_DIR", $i); $builddir = set_test_option("BUILD_DIR", $i); - chdir $builddir || die "can't change directory to $builddir"; + chdir $builddir || dodie "can't change directory to $builddir"; if (!-d $outputdir) { mkpath($outputdir) or - die "can't create $outputdir"; + dodie "can't create $outputdir"; } $make = "$makecmd O=$outputdir"; @@ -4218,7 +4218,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { if (!-d $tmpdir) { mkpath($tmpdir) or - die "can't create $tmpdir"; + dodie "can't create $tmpdir"; } $ENV{"SSH_USER"} = $ssh_user; @@ -4291,7 +4291,7 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) { if (defined($checkout)) { run_command "git checkout $checkout" or - die "failed to checkout $checkout"; + dodie "failed to checkout $checkout"; } $no_reboot = 0; -- cgit v1.3-14-g43fede From eaaa1e283ada2e8808f9074829c27857adb35bdb Mon Sep 17 00:00:00 2001 From: Tim Tianyang Chen Date: Mon, 26 Mar 2018 13:08:04 -0700 Subject: Ktest: add email options to sample.config A block of email options is added under the optional config section. Link: http://lkml.kernel.org/r/1522094884-22718-5-git-send-email-tianyang.chen@oracle.com Suggested-by: Dhaval Giani Signed-off-by: Tim Tianyang Chen Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/sample.conf | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index f5b58addb1d1..d1a2626aaa0a 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -401,6 +401,28 @@ #### Optional Config Options (all have defaults) #### +# Email options for receiving notifications. Users must setup +# the specified mailer prior to using this feature. +# +# (default undefined) +#MAILTO = +# +# Supported mailers: sendmail, mail, mailx +# (default sendmail) +#MAILER = sendmail +# +# Errors are defined as those would terminate the script +# (default 1) +#EMAIL_ON_ERROR = 1 +# (default 1) +#EMAIL_WHEN_FINISHED = 1 +# (default 0) +#EMAIL_WHEN_STARTED = 1 +# +# Users can cancel the test by Ctrl^C +# (default 0) +#EMAIL_WHEN_CANCELED = 1 + # Start a test setup. If you leave this off, all options # will be default and the test will run once. # This is a label and not really an option (it takes no value). -- cgit v1.3-14-g43fede From f5ef48855733360c850be82221ce7454294a1580 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Fri, 6 Apr 2018 15:49:43 -0400 Subject: ktest.pl: No need to print no mailer is specified when mailto is not If the user doesn't want to send mail, then don't bother them with output that says they didn't specify a mailer. That can be annoying. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 30a4c053f98b..07d0a47816e4 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -4135,12 +4135,14 @@ sub _sendmail_send { } sub send_email { - if (defined($mailto) && defined($mailer)) { + if (defined($mailto)) { + if (!defined($mailer)) { + doprint "No email sent: email or mailer not specified in config.\n"; + return; + } if ($mailer eq "mail" || $mailer eq "mailx"){ _mailx_send(@_);} elsif ($mailer eq "sendmail" ) { _sendmail_send(@_);} else { doprint "\nYour mailer: $mailer is not supported.\n" } - } else { - print "No email sent: email or mailer not specified in config.\n" } } -- cgit v1.3-14-g43fede From be1546b87f3b60f107b8f8dfef0e268cc12792f1 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Fri, 6 Apr 2018 16:38:56 -0400 Subject: ktest.pl: Add MAIL_PATH option to define where to find the mailer The option MAIL_PATH lets the user decide how to find the mailer they are using. For example, sendmail is usually located in /usr/sbin but is not always in the path of non admin users. Have ktest look through the user's PATH environment variable (adding /usr/sbin) as well, but if that's not good enough, allow the user to define where to find the mailer. Signed-off-by: Steven Rostedt (VMware) squash to mail exec Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 36 +++++++++++++++++++++++++++++++----- tools/testing/ktest/sample.conf | 4 ++++ 2 files changed, 35 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 07d0a47816e4..637545bd9e98 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -23,7 +23,7 @@ my %evals; #default opts my %default = ( - "MAILER" => "sendmail", # default mailer + "MAILER" => "sendmail", # default mailer "EMAIL_ON_ERROR" => 1, "EMAIL_WHEN_FINISHED" => 1, "EMAIL_WHEN_CANCELED" => 0, @@ -218,6 +218,7 @@ my $dirname = $FindBin::Bin; my $mailto; my $mailer; +my $mail_path; my $email_on_error; my $email_when_finished; my $email_when_started; @@ -250,8 +251,9 @@ my $no_reboot = 1; my $reboot_success = 0; my %option_map = ( - "MAILTO" => \$mailto, - "MAILER" => \$mailer, + "MAILTO" => \$mailto, + "MAILER" => \$mailer, + "MAIL_PATH" => \$mail_path, "EMAIL_ON_ERROR" => \$email_on_error, "EMAIL_WHEN_FINISHED" => \$email_when_finished, "EMAIL_WHEN_STARTED" => \$email_when_started, @@ -4126,12 +4128,29 @@ sub set_test_option { sub _mailx_send { my ($subject, $message) = @_; - system("$mailer -s \'$subject\' $mailto <<< \'$message\'"); + system("$mail_path/$mailer -s \'$subject\' $mailto <<< \'$message\'"); } sub _sendmail_send { my ($subject, $message) = @_; - system("echo -e \"Subject: $subject\n\n$message\" | sendmail -t $mailto"); + system("echo -e \"Subject: $subject\n\n$message\" | $mail_path/sendmail -t $mailto"); +} + +sub find_mailer { + my ($mailer) = @_; + + my @paths = split /:/, $ENV{PATH}; + + # sendmail is usually in /usr/sbin + $paths[$#paths + 1] = "/usr/sbin"; + + foreach my $path (@paths) { + if (-x "$path/$mailer") { + return $path; + } + } + + return undef; } sub send_email { @@ -4140,6 +4159,13 @@ sub send_email { doprint "No email sent: email or mailer not specified in config.\n"; return; } + if (!defined($mail_path)) { + # find the mailer + $mail_path = find_mailer $mailer; + if (!defined($mail_path)) { + die "\nCan not find $mailer in PATH\n"; + } + } if ($mailer eq "mail" || $mailer eq "mailx"){ _mailx_send(@_);} elsif ($mailer eq "sendmail" ) { _sendmail_send(@_);} else { doprint "\nYour mailer: $mailer is not supported.\n" } diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index d1a2626aaa0a..86e7cffc45c0 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -411,6 +411,10 @@ # (default sendmail) #MAILER = sendmail # +# The executable to run +# (default: for sendmail "/usr/sbin/sendmail", otherwise equals ${MAILER}) +#MAIL_EXEC = /usr/sbin/sendmail +# # Errors are defined as those would terminate the script # (default 1) #EMAIL_ON_ERROR = 1 -- cgit v1.3-14-g43fede From 8604b0c4bc9a39f8fa0301bbb15146bcda2a44f7 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Fri, 6 Apr 2018 16:42:34 -0400 Subject: ktest.pl: Kill test if mailer is not supported If the user specifies a MAILTO, but the MAILER is not supported, then kill the test. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 637545bd9e98..3400a23e6a41 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -4168,7 +4168,7 @@ sub send_email { } if ($mailer eq "mail" || $mailer eq "mailx"){ _mailx_send(@_);} elsif ($mailer eq "sendmail" ) { _sendmail_send(@_);} - else { doprint "\nYour mailer: $mailer is not supported.\n" } + else { die "\nYour mailer: $mailer is not supported.\n" } } } -- cgit v1.3-14-g43fede From 255769a17b86838eb724da5501eba6a31b0ed1ba Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Fri, 6 Apr 2018 17:16:39 -0400 Subject: ktest.pl: Allow dodie be recursive If dodie cause a function that itself will call dodie, then be able to handle that. This will allow dodie functions to call run_command, which could possibly call dodie. If dodie is called again, simply ignore it. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index 3400a23e6a41..ac6750bb5942 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1433,7 +1433,14 @@ sub do_not_reboot { ($test_type eq "config_bisect" && $opt{"CONFIG_BISECT_TYPE[$i]"} eq "build"); } +my $in_die = 0; + sub dodie { + + # avoid recusion + return if ($in_die); + $in_die = 1; + doprint "CRITICAL FAILURE... ", @_, "\n"; my $i = $iteration; -- cgit v1.3-14-g43fede From 59f89eb1e3ddccdef9a154dd667facfc15bceab1 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Fri, 6 Apr 2018 17:46:27 -0400 Subject: ktest.pl: Use run_command to execute sending mail Instead of open coding system() call, use run_command which will log the sending of email as well. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index ac6750bb5942..f487f91ccf03 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -4135,12 +4135,12 @@ sub set_test_option { sub _mailx_send { my ($subject, $message) = @_; - system("$mail_path/$mailer -s \'$subject\' $mailto <<< \'$message\'"); + run_command "$mail_path/$mailer -s \'$subject\' $mailto <<< \'$message\'"; } sub _sendmail_send { my ($subject, $message) = @_; - system("echo -e \"Subject: $subject\n\n$message\" | $mail_path/sendmail -t $mailto"); + run_command "echo \'Subject: $subject\n\n$message\' | $mail_path/sendmail -t $mailto"; } sub find_mailer { -- cgit v1.3-14-g43fede From c2d84ddb338c829e3ee9d1af6a55325998fcdb82 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (VMware)" Date: Sat, 7 Apr 2018 20:11:19 -0400 Subject: ktest.pl: Add MAIL_COMMAND option to define how to send email Allow the user to override the default way to send email. This will allow the user to add their own mailer and format for sending email. Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 54 ++++++++++++++++++++++++++--------------- tools/testing/ktest/sample.conf | 12 +++++++++ 2 files changed, 46 insertions(+), 20 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index f487f91ccf03..a14fc309d140 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -219,6 +219,7 @@ my $dirname = $FindBin::Bin; my $mailto; my $mailer; my $mail_path; +my $mail_command; my $email_on_error; my $email_when_finished; my $email_when_started; @@ -254,6 +255,7 @@ my %option_map = ( "MAILTO" => \$mailto, "MAILER" => \$mailer, "MAIL_PATH" => \$mail_path, + "MAIL_COMMAND" => \$mail_command, "EMAIL_ON_ERROR" => \$email_on_error, "EMAIL_WHEN_FINISHED" => \$email_when_finished, "EMAIL_WHEN_STARTED" => \$email_when_started, @@ -4133,16 +4135,6 @@ sub set_test_option { return eval_option($name, $option, $i); } -sub _mailx_send { - my ($subject, $message) = @_; - run_command "$mail_path/$mailer -s \'$subject\' $mailto <<< \'$message\'"; -} - -sub _sendmail_send { - my ($subject, $message) = @_; - run_command "echo \'Subject: $subject\n\n$message\' | $mail_path/sendmail -t $mailto"; -} - sub find_mailer { my ($mailer) = @_; @@ -4160,22 +4152,44 @@ sub find_mailer { return undef; } +sub do_send_mail { + my ($subject, $message) = @_; + + if (!defined($mail_path)) { + # find the mailer + $mail_path = find_mailer $mailer; + if (!defined($mail_path)) { + die "\nCan not find $mailer in PATH\n"; + } + } + + if (!defined($mail_command)) { + if ($mailer eq "mail" || $mailer eq "mailx") { + $mail_command = "\$MAIL_PATH/\$MAILER -s \'\$SUBJECT\' \$MAILTO <<< \'\$MESSAGE\'"; + } elsif ($mailer eq "sendmail" ) { + $mail_command = "echo \'Subject: \$SUBJECT\n\n\$MESSAGE\' | \$MAIL_PATH/\$MAILER -t \$MAILTO"; + } else { + die "\nYour mailer: $mailer is not supported.\n"; + } + } + + $mail_command =~ s/\$MAILER/$mailer/g; + $mail_command =~ s/\$MAIL_PATH/$mail_path/g; + $mail_command =~ s/\$MAILTO/$mailto/g; + $mail_command =~ s/\$SUBJECT/$subject/g; + $mail_command =~ s/\$MESSAGE/$message/g; + + run_command $mail_command; +} + sub send_email { + if (defined($mailto)) { if (!defined($mailer)) { doprint "No email sent: email or mailer not specified in config.\n"; return; } - if (!defined($mail_path)) { - # find the mailer - $mail_path = find_mailer $mailer; - if (!defined($mail_path)) { - die "\nCan not find $mailer in PATH\n"; - } - } - if ($mailer eq "mail" || $mailer eq "mailx"){ _mailx_send(@_);} - elsif ($mailer eq "sendmail" ) { _sendmail_send(@_);} - else { die "\nYour mailer: $mailer is not supported.\n" } + do_send_mail @_; } } diff --git a/tools/testing/ktest/sample.conf b/tools/testing/ktest/sample.conf index 86e7cffc45c0..6ca6ca0ce695 100644 --- a/tools/testing/ktest/sample.conf +++ b/tools/testing/ktest/sample.conf @@ -415,6 +415,18 @@ # (default: for sendmail "/usr/sbin/sendmail", otherwise equals ${MAILER}) #MAIL_EXEC = /usr/sbin/sendmail # +# The command used to send mail, which uses the above options +# can be modified. By default if the mailer is "sendmail" then +# MAIL_COMMAND = echo \'Subject: $SUBJECT\n\n$MESSAGE\' | $MAIL_PATH/$MAILER -t $MAILTO +# For mail or mailx: +# MAIL_COMMAND = "$MAIL_PATH/$MAILER -s \'$SUBJECT\' $MAILTO <<< \'$MESSAGE\' +# ktest.pl will do the substitution for MAIL_PATH, MAILER, MAILTO at the time +# it sends the mail if "$FOO" format is used. If "${FOO}" format is used, +# then the substitutions will occur at the time the config file is read. +# But note, MAIL_PATH and MAILER require being set by the config file if +# ${MAIL_PATH} or ${MAILER} are used, but not if $MAIL_PATH or $MAILER are. +#MAIL_COMMAND = echo \'Subject: $SUBJECT\n\n$MESSAGE\' | $MAIL_PATH/$MAILER -t $MAILTO +# # Errors are defined as those would terminate the script # (default 1) #EMAIL_ON_ERROR = 1 -- cgit v1.3-14-g43fede From 6cd110a91f52197e3392809cd43466bfe2c524d0 Mon Sep 17 00:00:00 2001 From: Satoru Takeuchi Date: Fri, 22 Sep 2017 13:38:19 +0900 Subject: ktest: Take submenu into account for grub2 menus grub-reboot selects the submenu's first menuentry (title is "1>0") rather than ktest's menuentry (title is "2") by mistake. === $ sudo cat /boot/grub/grub.cfg | grep -E "^menuentry|^submenu" ... menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option '...' { ... submenu 'Advanced options for Ubuntu' $menuentry_id_option '...' { ... menuentry 'ktest' { ... === Correct it by taking submenu entries into account in get_grub2_index(). Link: http://lkml.kernel.org/r/87poaje4as.wl-satoru.takeuchi@gmail.com Signed-off-by: Satoru Takeuchi Signed-off-by: Steven Rostedt (VMware) --- tools/testing/ktest/ktest.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/testing') diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl index a14fc309d140..777388cc8221 100755 --- a/tools/testing/ktest/ktest.pl +++ b/tools/testing/ktest/ktest.pl @@ -1872,7 +1872,7 @@ sub get_grub2_index { $grub_number++; $found = 1; last; - } elsif (/^menuentry\s/) { + } elsif (/^menuentry\s|^submenu\s/) { $grub_number++; } } -- cgit v1.3-14-g43fede From 9cd65655585523adecd65b750e1537cdea84718e Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 10 Apr 2018 16:31:45 -0700 Subject: proc: test /proc/self/wchan This patch starts testing /proc. Many more tests to come (I promise). Read from /proc/self/wchan should always return "0" as current is in TASK_RUNNING state while reading /proc/self/wchan. Link: http://lkml.kernel.org/r/20180226212006.GA742@avx2 Signed-off-by: Alexey Dobriyan Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/proc/.gitignore | 1 + tools/testing/selftests/proc/Makefile | 6 ++++++ tools/testing/selftests/proc/config | 1 + tools/testing/selftests/proc/proc-self-wchan.c | 25 +++++++++++++++++++++++++ 5 files changed, 34 insertions(+) create mode 100644 tools/testing/selftests/proc/.gitignore create mode 100644 tools/testing/selftests/proc/Makefile create mode 100644 tools/testing/selftests/proc/config create mode 100644 tools/testing/selftests/proc/proc-self-wchan.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 2fc410bc4f33..32aafa92074c 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -25,6 +25,7 @@ TARGETS += mqueue TARGETS += net TARGETS += nsfs TARGETS += powerpc +TARGETS += proc TARGETS += pstore TARGETS += ptrace TARGETS += seccomp diff --git a/tools/testing/selftests/proc/.gitignore b/tools/testing/selftests/proc/.gitignore new file mode 100644 index 000000000000..4c851db80bd5 --- /dev/null +++ b/tools/testing/selftests/proc/.gitignore @@ -0,0 +1 @@ +/proc-self-wchan diff --git a/tools/testing/selftests/proc/Makefile b/tools/testing/selftests/proc/Makefile new file mode 100644 index 000000000000..592603a5d675 --- /dev/null +++ b/tools/testing/selftests/proc/Makefile @@ -0,0 +1,6 @@ +CFLAGS += -Wall -O2 + +TEST_GEN_PROGS := +TEST_GEN_PROGS += proc-self-wchan + +include ../lib.mk diff --git a/tools/testing/selftests/proc/config b/tools/testing/selftests/proc/config new file mode 100644 index 000000000000..68fbd2b35884 --- /dev/null +++ b/tools/testing/selftests/proc/config @@ -0,0 +1 @@ +CONFIG_PROC_FS=y diff --git a/tools/testing/selftests/proc/proc-self-wchan.c b/tools/testing/selftests/proc/proc-self-wchan.c new file mode 100644 index 000000000000..b8d8728a6869 --- /dev/null +++ b/tools/testing/selftests/proc/proc-self-wchan.c @@ -0,0 +1,25 @@ +#include +#include +#include +#include +#include + +int main(void) +{ + char buf[64]; + int fd; + + fd = open("/proc/self/wchan", O_RDONLY); + if (fd == -1) { + if (errno == ENOENT) + return 2; + return 1; + } + + buf[0] = '\0'; + if (read(fd, buf, sizeof(buf)) != 1) + return 1; + if (buf[0] != '0') + return 1; + return 0; +} -- cgit v1.3-14-g43fede From c4219edf1de2af44fd98903f72f6e1ceb7f3c701 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 10 Apr 2018 16:31:48 -0700 Subject: proc: test /proc/self/syscall Read from /proc/self/syscall should yield read system call and correct args in the output as current is reading /proc/self/syscall. Link: http://lkml.kernel.org/r/20180226212145.GB742@avx2 Signed-off-by: Alexey Dobriyan Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/proc/.gitignore | 3 +- tools/testing/selftests/proc/Makefile | 1 + tools/testing/selftests/proc/proc-self-syscall.c | 45 ++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/proc/proc-self-syscall.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/proc/.gitignore b/tools/testing/selftests/proc/.gitignore index 4c851db80bd5..c648b27af2e7 100644 --- a/tools/testing/selftests/proc/.gitignore +++ b/tools/testing/selftests/proc/.gitignore @@ -1 +1,2 @@ -/proc-self-wchan +/proc-self-mem +/proc-self-syscall diff --git a/tools/testing/selftests/proc/Makefile b/tools/testing/selftests/proc/Makefile index 592603a5d675..ad20520910e2 100644 --- a/tools/testing/selftests/proc/Makefile +++ b/tools/testing/selftests/proc/Makefile @@ -1,6 +1,7 @@ CFLAGS += -Wall -O2 TEST_GEN_PROGS := +TEST_GEN_PROGS += proc-self-syscall TEST_GEN_PROGS += proc-self-wchan include ../lib.mk diff --git a/tools/testing/selftests/proc/proc-self-syscall.c b/tools/testing/selftests/proc/proc-self-syscall.c new file mode 100644 index 000000000000..05eb6f91f1e9 --- /dev/null +++ b/tools/testing/selftests/proc/proc-self-syscall.c @@ -0,0 +1,45 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline ssize_t sys_read(int fd, void *buf, size_t len) +{ + return syscall(SYS_read, fd, buf, len); +} + +int main(void) +{ + char buf1[64]; + char buf2[64]; + int fd; + ssize_t rv; + + fd = open("/proc/self/syscall", O_RDONLY); + if (fd == -1) { + if (errno == ENOENT) + return 2; + return 1; + } + + /* Do direct system call as libc can wrap anything. */ + snprintf(buf1, sizeof(buf1), "%ld 0x%lx 0x%lx 0x%lx", + (long)SYS_read, (long)fd, (long)buf2, (long)sizeof(buf2)); + + memset(buf2, 0, sizeof(buf2)); + rv = sys_read(fd, buf2, sizeof(buf2)); + if (rv < 0) + return 1; + if (rv < strlen(buf1)) + return 1; + if (strncmp(buf1, buf2, strlen(buf1)) != 0) + return 1; + + return 0; +} -- cgit v1.3-14-g43fede From 35318db566e18ee3ada7e2d62192e5e87b1b5e4b Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 10 Apr 2018 16:41:14 -0700 Subject: proc: fix /proc/*/map_files lookup some more I totally forgot that _parse_integer() accepts arbitrary amount of leading zeroes leading to the following lookups: OK # readlink /proc/1/map_files/56427ecba000-56427eddc000 /lib/systemd/systemd bogus # readlink /proc/1/map_files/00000000000056427ecba000-56427eddc000 /lib/systemd/systemd # readlink /proc/1/map_files/56427ecba000-00000000000056427eddc000 /lib/systemd/systemd Link: http://lkml.kernel.org/r/20180303215130.GA23480@avx2 Signed-off-by: Alexey Dobriyan Reviewed-by: Cyrill Gorcunov Reviewed-by: Andrew Morton Cc: Pavel Emelyanov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 4 + tools/testing/selftests/proc/.gitignore | 4 +- tools/testing/selftests/proc/Makefile | 2 + .../selftests/proc/proc-self-map-files-001.c | 82 +++++++++++++++++++++ .../selftests/proc/proc-self-map-files-002.c | 85 ++++++++++++++++++++++ 5 files changed, 176 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/proc/proc-self-map-files-001.c create mode 100644 tools/testing/selftests/proc/proc-self-map-files-002.c (limited to 'tools/testing') diff --git a/fs/proc/base.c b/fs/proc/base.c index e9e7652b77da..d413a138dc30 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1913,6 +1913,8 @@ static int dname_to_vma_addr(struct dentry *dentry, unsigned long long sval, eval; unsigned int len; + if (str[0] == '0' && str[1] != '-') + return -EINVAL; len = _parse_integer(str, 16, &sval); if (len & KSTRTOX_OVERFLOW) return -EINVAL; @@ -1924,6 +1926,8 @@ static int dname_to_vma_addr(struct dentry *dentry, return -EINVAL; str++; + if (str[0] == '0' && str[1]) + return -EINVAL; len = _parse_integer(str, 16, &eval); if (len & KSTRTOX_OVERFLOW) return -EINVAL; diff --git a/tools/testing/selftests/proc/.gitignore b/tools/testing/selftests/proc/.gitignore index c648b27af2e7..e3ceb19ae99a 100644 --- a/tools/testing/selftests/proc/.gitignore +++ b/tools/testing/selftests/proc/.gitignore @@ -1,2 +1,4 @@ -/proc-self-mem +/proc-self-map-files-001 +/proc-self-map-files-002 /proc-self-syscall +/proc-self-wchan diff --git a/tools/testing/selftests/proc/Makefile b/tools/testing/selftests/proc/Makefile index ad20520910e2..1a0ce32a9786 100644 --- a/tools/testing/selftests/proc/Makefile +++ b/tools/testing/selftests/proc/Makefile @@ -1,6 +1,8 @@ CFLAGS += -Wall -O2 TEST_GEN_PROGS := +TEST_GEN_PROGS += proc-self-map-files-001 +TEST_GEN_PROGS += proc-self-map-files-002 TEST_GEN_PROGS += proc-self-syscall TEST_GEN_PROGS += proc-self-wchan diff --git a/tools/testing/selftests/proc/proc-self-map-files-001.c b/tools/testing/selftests/proc/proc-self-map-files-001.c new file mode 100644 index 000000000000..af1d0a6af810 --- /dev/null +++ b/tools/testing/selftests/proc/proc-self-map-files-001.c @@ -0,0 +1,82 @@ +/* + * Copyright _ 2018 Alexey Dobriyan + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* Test readlink /proc/self/map_files/... */ +#include +#include +#include +#include +#include +#include +#include +#include + +static void pass(const char *fmt, unsigned long a, unsigned long b) +{ + char name[64]; + char buf[64]; + + snprintf(name, sizeof(name), fmt, a, b); + if (readlink(name, buf, sizeof(buf)) == -1) + exit(1); +} + +static void fail(const char *fmt, unsigned long a, unsigned long b) +{ + char name[64]; + char buf[64]; + + snprintf(name, sizeof(name), fmt, a, b); + if (readlink(name, buf, sizeof(buf)) == -1 && errno == ENOENT) + return; + exit(1); +} + +int main(void) +{ + const unsigned int PAGE_SIZE = sysconf(_SC_PAGESIZE); + void *p; + int fd; + unsigned long a, b; + + fd = open("/dev/zero", O_RDONLY); + if (fd == -1) + return 1; + + p = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE|MAP_FILE, fd, 0); + if (p == MAP_FAILED) + return 1; + + a = (unsigned long)p; + b = (unsigned long)p + PAGE_SIZE; + + pass("/proc/self/map_files/%lx-%lx", a, b); + fail("/proc/self/map_files/ %lx-%lx", a, b); + fail("/proc/self/map_files/%lx -%lx", a, b); + fail("/proc/self/map_files/%lx- %lx", a, b); + fail("/proc/self/map_files/%lx-%lx ", a, b); + fail("/proc/self/map_files/0%lx-%lx", a, b); + fail("/proc/self/map_files/%lx-0%lx", a, b); + if (sizeof(long) == 4) { + fail("/proc/self/map_files/100000000%lx-%lx", a, b); + fail("/proc/self/map_files/%lx-100000000%lx", a, b); + } else if (sizeof(long) == 8) { + fail("/proc/self/map_files/10000000000000000%lx-%lx", a, b); + fail("/proc/self/map_files/%lx-10000000000000000%lx", a, b); + } else + return 1; + + return 0; +} diff --git a/tools/testing/selftests/proc/proc-self-map-files-002.c b/tools/testing/selftests/proc/proc-self-map-files-002.c new file mode 100644 index 000000000000..aebf4be56111 --- /dev/null +++ b/tools/testing/selftests/proc/proc-self-map-files-002.c @@ -0,0 +1,85 @@ +/* + * Copyright _ 2018 Alexey Dobriyan + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* Test readlink /proc/self/map_files/... with address 0. */ +#include +#include +#include +#include +#include +#include +#include +#include + +static void pass(const char *fmt, unsigned long a, unsigned long b) +{ + char name[64]; + char buf[64]; + + snprintf(name, sizeof(name), fmt, a, b); + if (readlink(name, buf, sizeof(buf)) == -1) + exit(1); +} + +static void fail(const char *fmt, unsigned long a, unsigned long b) +{ + char name[64]; + char buf[64]; + + snprintf(name, sizeof(name), fmt, a, b); + if (readlink(name, buf, sizeof(buf)) == -1 && errno == ENOENT) + return; + exit(1); +} + +int main(void) +{ + const unsigned int PAGE_SIZE = sysconf(_SC_PAGESIZE); + void *p; + int fd; + unsigned long a, b; + + fd = open("/dev/zero", O_RDONLY); + if (fd == -1) + return 1; + + p = mmap(NULL, PAGE_SIZE, PROT_NONE, MAP_PRIVATE|MAP_FILE|MAP_FIXED, fd, 0); + if (p == MAP_FAILED) { + if (errno == EPERM) + return 2; + return 1; + } + + a = (unsigned long)p; + b = (unsigned long)p + PAGE_SIZE; + + pass("/proc/self/map_files/%lx-%lx", a, b); + fail("/proc/self/map_files/ %lx-%lx", a, b); + fail("/proc/self/map_files/%lx -%lx", a, b); + fail("/proc/self/map_files/%lx- %lx", a, b); + fail("/proc/self/map_files/%lx-%lx ", a, b); + fail("/proc/self/map_files/0%lx-%lx", a, b); + fail("/proc/self/map_files/%lx-0%lx", a, b); + if (sizeof(long) == 4) { + fail("/proc/self/map_files/100000000%lx-%lx", a, b); + fail("/proc/self/map_files/%lx-100000000%lx", a, b); + } else if (sizeof(long) == 8) { + fail("/proc/self/map_files/10000000000000000%lx-%lx", a, b); + fail("/proc/self/map_files/%lx-10000000000000000%lx", a, b); + } else + return 1; + + return 0; +} -- cgit v1.3-14-g43fede From 5de3d401b79486b9323e1be30e3a34c2437b8800 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 10 Apr 2018 16:42:23 -0700 Subject: proc: add selftest for last field of /proc/loadavg Test fork counter formerly known as ->last_pid, the only part of /proc/loadavg which can be tested. Testing in init pid namespace is not reliable because of background activity. Link: http://lkml.kernel.org/r/20180311152241.GA26247@avx2 Signed-off-by: Alexey Dobriyan Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/proc/.gitignore | 1 + tools/testing/selftests/proc/Makefile | 1 + tools/testing/selftests/proc/proc-loadavg-001.c | 83 +++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 tools/testing/selftests/proc/proc-loadavg-001.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/proc/.gitignore b/tools/testing/selftests/proc/.gitignore index e3ceb19ae99a..78c40f5aa706 100644 --- a/tools/testing/selftests/proc/.gitignore +++ b/tools/testing/selftests/proc/.gitignore @@ -1,3 +1,4 @@ +/proc-loadavg-001 /proc-self-map-files-001 /proc-self-map-files-002 /proc-self-syscall diff --git a/tools/testing/selftests/proc/Makefile b/tools/testing/selftests/proc/Makefile index 1a0ce32a9786..d7f70583005d 100644 --- a/tools/testing/selftests/proc/Makefile +++ b/tools/testing/selftests/proc/Makefile @@ -1,6 +1,7 @@ CFLAGS += -Wall -O2 TEST_GEN_PROGS := +TEST_GEN_PROGS += proc-loadavg-001 TEST_GEN_PROGS += proc-self-map-files-001 TEST_GEN_PROGS += proc-self-map-files-002 TEST_GEN_PROGS += proc-self-syscall diff --git a/tools/testing/selftests/proc/proc-loadavg-001.c b/tools/testing/selftests/proc/proc-loadavg-001.c new file mode 100644 index 000000000000..e38ad6d94d4b --- /dev/null +++ b/tools/testing/selftests/proc/proc-loadavg-001.c @@ -0,0 +1,83 @@ +/* + * Copyright _ 2018 Alexey Dobriyan + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +/* Test that /proc/loadavg correctly reports last pid in pid namespace. */ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +int main(void) +{ + pid_t pid; + int wstatus; + + if (unshare(CLONE_NEWPID) == -1) { + if (errno == ENOSYS || errno == EPERM) + return 2; + return 1; + } + + pid = fork(); + if (pid == -1) + return 1; + if (pid == 0) { + char buf[128], *p; + int fd; + ssize_t rv; + + fd = open("/proc/loadavg" , O_RDONLY); + if (fd == -1) + return 1; + rv = read(fd, buf, sizeof(buf)); + if (rv < 3) + return 1; + p = buf + rv; + + /* pid 1 */ + if (!(p[-3] == ' ' && p[-2] == '1' && p[-1] == '\n')) + return 1; + + pid = fork(); + if (pid == -1) + return 1; + if (pid == 0) + return 0; + if (waitpid(pid, NULL, 0) == -1) + return 1; + + lseek(fd, 0, SEEK_SET); + rv = read(fd, buf, sizeof(buf)); + if (rv < 3) + return 1; + p = buf + rv; + + /* pid 2 */ + if (!(p[-3] == ' ' && p[-2] == '2' && p[-1] == '\n')) + return 1; + + return 0; + } + + if (waitpid(pid, &wstatus, 0) == -1) + return 1; + if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0) + return 0; + return 1; +} -- cgit v1.3-14-g43fede From 05c3f29283af9e3da0ab7414f666cb37f530950a Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 10 Apr 2018 16:46:19 -0700 Subject: proc: selftests: shotgun testing of read/readdir/readlink/write Perform reads with nearly everything in /proc, and some writing as well. Hopefully memleak checkers and KASAN will find something. [adobriyan@gmail.com: /proc/kmsg can and will block if read under root] Link: http://lkml.kernel.org/r/20180316232147.GA20146@avx2 Signed-off-by: Alexey Dobriyan [adobriyan@gmail.com: /proc/sysrq-trigger lives on the ground floor] Link: http://lkml.kernel.org/r/20180317164911.GA3445@avx2 Link: http://lkml.kernel.org/r/20180315201251.GA12396@avx2 Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/proc/.gitignore | 1 + tools/testing/selftests/proc/Makefile | 1 + tools/testing/selftests/proc/read.c | 147 ++++++++++++++++++++++++++++++++ 3 files changed, 149 insertions(+) create mode 100644 tools/testing/selftests/proc/read.c (limited to 'tools/testing') diff --git a/tools/testing/selftests/proc/.gitignore b/tools/testing/selftests/proc/.gitignore index 78c40f5aa706..5627df81ade9 100644 --- a/tools/testing/selftests/proc/.gitignore +++ b/tools/testing/selftests/proc/.gitignore @@ -3,3 +3,4 @@ /proc-self-map-files-002 /proc-self-syscall /proc-self-wchan +/read diff --git a/tools/testing/selftests/proc/Makefile b/tools/testing/selftests/proc/Makefile index d7f70583005d..312a3989820c 100644 --- a/tools/testing/selftests/proc/Makefile +++ b/tools/testing/selftests/proc/Makefile @@ -6,5 +6,6 @@ TEST_GEN_PROGS += proc-self-map-files-001 TEST_GEN_PROGS += proc-self-map-files-002 TEST_GEN_PROGS += proc-self-syscall TEST_GEN_PROGS += proc-self-wchan +TEST_GEN_PROGS += read include ../lib.mk diff --git a/tools/testing/selftests/proc/read.c b/tools/testing/selftests/proc/read.c new file mode 100644 index 000000000000..12e397f78592 --- /dev/null +++ b/tools/testing/selftests/proc/read.c @@ -0,0 +1,147 @@ +/* + * Copyright _ 2018 Alexey Dobriyan + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +// Test +// 1) read of every file in /proc +// 2) readlink of every symlink in /proc +// 3) recursively (1) + (2) for every directory in /proc +// 4) write to /proc/*/clear_refs and /proc/*/task/*/clear_refs +// 5) write to /proc/sysrq-trigger +#undef NDEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline bool streq(const char *s1, const char *s2) +{ + return strcmp(s1, s2) == 0; +} + +static struct dirent *xreaddir(DIR *d) +{ + struct dirent *de; + + errno = 0; + de = readdir(d); + if (!de && errno != 0) { + exit(1); + } + return de; +} + +static void f_reg(DIR *d, const char *filename) +{ + char buf[4096]; + int fd; + ssize_t rv; + + /* read from /proc/kmsg can block */ + fd = openat(dirfd(d), filename, O_RDONLY|O_NONBLOCK); + if (fd == -1) + return; + rv = read(fd, buf, sizeof(buf)); + assert((0 <= rv && rv <= sizeof(buf)) || rv == -1); + close(fd); +} + +static void f_reg_write(DIR *d, const char *filename, const char *buf, size_t len) +{ + int fd; + ssize_t rv; + + fd = openat(dirfd(d), filename, O_WRONLY); + if (fd == -1) + return; + rv = write(fd, buf, len); + assert((0 <= rv && rv <= len) || rv == -1); + close(fd); +} + +static void f_lnk(DIR *d, const char *filename) +{ + char buf[4096]; + ssize_t rv; + + rv = readlinkat(dirfd(d), filename, buf, sizeof(buf)); + assert((0 <= rv && rv <= sizeof(buf)) || rv == -1); +} + +static void f(DIR *d, unsigned int level) +{ + struct dirent *de; + + de = xreaddir(d); + assert(de->d_type == DT_DIR); + assert(streq(de->d_name, ".")); + + de = xreaddir(d); + assert(de->d_type == DT_DIR); + assert(streq(de->d_name, "..")); + + while ((de = xreaddir(d))) { + assert(!streq(de->d_name, ".")); + assert(!streq(de->d_name, "..")); + + switch (de->d_type) { + DIR *dd; + int fd; + + case DT_REG: + if (level == 0 && streq(de->d_name, "sysrq-trigger")) { + f_reg_write(d, de->d_name, "h", 1); + } else if (level == 1 && streq(de->d_name, "clear_refs")) { + f_reg_write(d, de->d_name, "1", 1); + } else if (level == 3 && streq(de->d_name, "clear_refs")) { + f_reg_write(d, de->d_name, "1", 1); + } else { + f_reg(d, de->d_name); + } + break; + case DT_DIR: + fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY); + if (fd == -1) + continue; + dd = fdopendir(fd); + if (!dd) + continue; + f(dd, level + 1); + closedir(dd); + break; + case DT_LNK: + f_lnk(d, de->d_name); + break; + default: + assert(0); + } + } +} + +int main(void) +{ + DIR *d; + + d = opendir("/proc"); + if (!d) + return 2; + f(d, 0); + return 0; +} -- cgit v1.3-14-g43fede From 1f5bd0547654ada423b184e22f320d76c0fac49e Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Tue, 10 Apr 2018 16:43:28 -0700 Subject: proc: selftests: test /proc/uptime The only tests I could come up with for /proc/uptime are: - test that values increase monotonically for 1 second, - bounce around CPUs and test the same thing. Avoid glibc like plague for affinity given patches like this: https://marc.info/?l=linux-kernel&m=152130031912594&w=4 Link: http://lkml.kernel.org/r/20180317165235.GB3445@avx2 Signed-off-by: Alexey Dobriyan Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/proc/.gitignore | 2 + tools/testing/selftests/proc/Makefile | 2 + tools/testing/selftests/proc/proc-uptime-001.c | 45 +++++++++++++++ tools/testing/selftests/proc/proc-uptime-002.c | 79 ++++++++++++++++++++++++++ tools/testing/selftests/proc/proc-uptime.h | 74 ++++++++++++++++++++++++ 5 files changed, 202 insertions(+) create mode 100644 tools/testing/selftests/proc/proc-uptime-001.c create mode 100644 tools/testing/selftests/proc/proc-uptime-002.c create mode 100644 tools/testing/selftests/proc/proc-uptime.h (limited to 'tools/testing') diff --git a/tools/testing/selftests/proc/.gitignore b/tools/testing/selftests/proc/.gitignore index 5627df81ade9..6c16f77c722c 100644 --- a/tools/testing/selftests/proc/.gitignore +++ b/tools/testing/selftests/proc/.gitignore @@ -3,4 +3,6 @@ /proc-self-map-files-002 /proc-self-syscall /proc-self-wchan +/proc-uptime-001 +/proc-uptime-002 /read diff --git a/tools/testing/selftests/proc/Makefile b/tools/testing/selftests/proc/Makefile index 312a3989820c..dbb87e56264c 100644 --- a/tools/testing/selftests/proc/Makefile +++ b/tools/testing/selftests/proc/Makefile @@ -6,6 +6,8 @@ TEST_GEN_PROGS += proc-self-map-files-001 TEST_GEN_PROGS += proc-self-map-files-002 TEST_GEN_PROGS += proc-self-syscall TEST_GEN_PROGS += proc-self-wchan +TEST_GEN_PROGS += proc-uptime-001 +TEST_GEN_PROGS += proc-uptime-002 TEST_GEN_PROGS += read include ../lib.mk diff --git a/tools/testing/selftests/proc/proc-uptime-001.c b/tools/testing/selftests/proc/proc-uptime-001.c new file mode 100644 index 000000000000..303f26092306 --- /dev/null +++ b/tools/testing/selftests/proc/proc-uptime-001.c @@ -0,0 +1,45 @@ +/* + * Copyright _ 2018 Alexey Dobriyan + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +// Test that values in /proc/uptime increment monotonically. +#undef NDEBUG +#include +#include +#include +#include +#include + +#include "proc-uptime.h" + +int main(void) +{ + uint64_t start, u0, u1, i0, i1; + int fd; + + fd = open("/proc/uptime", O_RDONLY); + assert(fd >= 0); + + proc_uptime(fd, &u0, &i0); + start = u0; + do { + proc_uptime(fd, &u1, &i1); + assert(u1 >= u0); + assert(i1 >= i0); + u0 = u1; + i0 = i1; + } while (u1 - start < 100); + + return 0; +} diff --git a/tools/testing/selftests/proc/proc-uptime-002.c b/tools/testing/selftests/proc/proc-uptime-002.c new file mode 100644 index 000000000000..0cb79e1f1674 --- /dev/null +++ b/tools/testing/selftests/proc/proc-uptime-002.c @@ -0,0 +1,79 @@ +/* + * Copyright _ 2018 Alexey Dobriyan + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +// Test that values in /proc/uptime increment monotonically +// while shifting across CPUs. +#define _GNU_SOURCE +#undef NDEBUG +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "proc-uptime.h" + +static inline int sys_sched_getaffinity(pid_t pid, unsigned int len, unsigned long *m) +{ + return syscall(SYS_sched_getaffinity, pid, len, m); +} + +static inline int sys_sched_setaffinity(pid_t pid, unsigned int len, unsigned long *m) +{ + return syscall(SYS_sched_setaffinity, pid, len, m); +} + +int main(void) +{ + unsigned int len; + unsigned long *m; + unsigned int cpu; + uint64_t u0, u1, i0, i1; + int fd; + + /* find out "nr_cpu_ids" */ + m = NULL; + len = 0; + do { + len += sizeof(unsigned long); + free(m); + m = malloc(len); + } while (sys_sched_getaffinity(0, len, m) == -EINVAL); + + fd = open("/proc/uptime", O_RDONLY); + assert(fd >= 0); + + proc_uptime(fd, &u0, &i0); + for (cpu = 0; cpu < len * 8; cpu++) { + memset(m, 0, len); + m[cpu / (8 * sizeof(unsigned long))] |= 1UL << (cpu % (8 * sizeof(unsigned long))); + + /* CPU might not exist, ignore error */ + sys_sched_setaffinity(0, len, m); + + proc_uptime(fd, &u1, &i1); + assert(u1 >= u0); + assert(i1 >= i0); + u0 = u1; + i0 = i1; + } + + return 0; +} diff --git a/tools/testing/selftests/proc/proc-uptime.h b/tools/testing/selftests/proc/proc-uptime.h new file mode 100644 index 000000000000..d584419f50a7 --- /dev/null +++ b/tools/testing/selftests/proc/proc-uptime.h @@ -0,0 +1,74 @@ +/* + * Copyright _ 2018 Alexey Dobriyan + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#undef NDEBUG +#include +#include +#include +#include +#include + +static unsigned long long xstrtoull(const char *p, char **end) +{ + if (*p == '0') { + *end = (char *)p + 1; + return 0; + } else if ('1' <= *p && *p <= '9') { + unsigned long long val; + + errno = 0; + val = strtoull(p, end, 10); + assert(errno == 0); + return val; + } else + assert(0); +} + +static void proc_uptime(int fd, uint64_t *uptime, uint64_t *idle) +{ + uint64_t val1, val2; + char buf[64], *p; + ssize_t rv; + + /* save "p < end" checks */ + memset(buf, 0, sizeof(buf)); + rv = pread(fd, buf, sizeof(buf), 0); + assert(0 <= rv && rv <= sizeof(buf)); + buf[sizeof(buf) - 1] = '\0'; + + p = buf; + + val1 = xstrtoull(p, &p); + assert(p[0] == '.'); + assert('0' <= p[1] && p[1] <= '9'); + assert('0' <= p[2] && p[2] <= '9'); + assert(p[3] == ' '); + + val2 = (p[1] - '0') * 10 + p[2] - '0'; + *uptime = val1 * 100 + val2; + + p += 4; + + val1 = xstrtoull(p, &p); + assert(p[0] == '.'); + assert('0' <= p[1] && p[1] <= '9'); + assert('0' <= p[2] && p[2] <= '9'); + assert(p[3] == '\n'); + + val2 = (p[1] - '0') * 10 + p[2] - '0'; + *idle = val1 * 100 + val2; + + assert(p + 4 == buf + rv); +} -- cgit v1.3-14-g43fede From fa290cda102c096f5ca394277d65d3dbd689930b Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 10 Apr 2018 16:36:28 -0700 Subject: radix tree: use GFP_ZONEMASK bits of gfp_t for flags Patch series "XArray", v9. (First part thereof). This patchset is, I believe, appropriate for merging for 4.17. It contains the XArray implementation, to eventually replace the radix tree, and converts the page cache to use it. This conversion keeps the radix tree and XArray data structures in sync at all times. That allows us to convert the page cache one function at a time and should allow for easier bisection. Other than renaming some elements of the structures, the data structures are fundamentally unchanged; a radix tree walk and an XArray walk will touch the same number of cachelines. I have changes planned to the XArray data structure, but those will happen in future patches. Improvements the XArray has over the radix tree: - The radix tree provides operations like other trees do; 'insert' and 'delete'. But what most users really want is an automatically resizing array, and so it makes more sense to give users an API that is like an array -- 'load' and 'store'. We still have an 'insert' operation for users that really want that semantic. - The XArray considers locking as part of its API. This simplifies a lot of users who formerly had to manage their own locking just for the radix tree. It also improves code generation as we can now tell RCU that we're holding a lock and it doesn't need to generate as much fencing code. The other advantage is that tree nodes can be moved (not yet implemented). - GFP flags are now parameters to calls which may need to allocate memory. The radix tree forced users to decide what the allocation flags would be at creation time. It's much clearer to specify them at allocation time. - Memory is not preloaded; we don't tie up dozens of pages on the off chance that the slab allocator fails. Instead, we drop the lock, allocate a new node and retry the operation. We have to convert all the radix tree, IDA and IDR preload users before we can realise this benefit, but I have not yet found a user which cannot be converted. - The XArray provides a cmpxchg operation. The radix tree forces users to roll their own (and at least four have). - Iterators take a 'max' parameter. That simplifies many users and will reduce the amount of iteration done. - Iteration can proceed backwards. We only have one user for this, but since it's called as part of the pagefault readahead algorithm, that seemed worth mentioning. - RCU-protected pointers are not exposed as part of the API. There are some fun bugs where the page cache forgets to use rcu_dereference() in the current codebase. - Value entries gain an extra bit compared to radix tree exceptional entries. That gives us the extra bit we need to put huge page swap entries in the page cache. - Some iterators now take a 'filter' argument instead of having separate iterators for tagged/untagged iterations. The page cache is improved by this: - Shorter, easier to read code - More efficient iterations - Reduction in size of struct address_space - Fewer walks from the top of the data structure; the XArray API encourages staying at the leaf node and conducting operations there. This patch (of 8): None of these bits may be used for slab allocations, so we can use them as radix tree flags as long as we mask them off before passing them to the slab allocator. Move the IDR flag from the high bits to the GFP_ZONEMASK bits. Link: http://lkml.kernel.org/r/20180313132639.17387-3-willy@infradead.org Signed-off-by: Matthew Wilcox Acked-by: Jeff Layton Cc: Darrick J. Wong Cc: Dave Chinner Cc: Ryusuke Konishi Cc: Will Deacon Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/idr.h | 3 ++- include/linux/radix-tree.h | 7 ++++--- lib/radix-tree.c | 3 ++- tools/testing/radix-tree/linux/gfp.h | 1 + 4 files changed, 9 insertions(+), 5 deletions(-) (limited to 'tools/testing') diff --git a/include/linux/idr.h b/include/linux/idr.h index 7d6a6313f0ab..913c335054f0 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -29,7 +29,8 @@ struct idr { #define IDR_FREE 0 /* Set the IDR flag and the IDR_FREE tag */ -#define IDR_RT_MARKER ((__force gfp_t)(3 << __GFP_BITS_SHIFT)) +#define IDR_RT_MARKER (ROOT_IS_IDR | (__force gfp_t) \ + (1 << (ROOT_TAG_SHIFT + IDR_FREE))) #define IDR_INIT_BASE(base) { \ .idr_rt = RADIX_TREE_INIT(IDR_RT_MARKER), \ diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index fc55ff31eca7..6c4e2e716dac 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h @@ -104,9 +104,10 @@ struct radix_tree_node { unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; }; -/* The top bits of gfp_mask are used to store the root tags and the IDR flag */ -#define ROOT_IS_IDR ((__force gfp_t)(1 << __GFP_BITS_SHIFT)) -#define ROOT_TAG_SHIFT (__GFP_BITS_SHIFT + 1) +/* The IDR tag is stored in the low bits of the GFP flags */ +#define ROOT_IS_IDR ((__force gfp_t)4) +/* The top bits of gfp_mask are used to store the root tags */ +#define ROOT_TAG_SHIFT (__GFP_BITS_SHIFT) struct radix_tree_root { gfp_t gfp_mask; diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 8e00138d593f..da9e10c827df 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -146,7 +146,7 @@ static unsigned int radix_tree_descend(const struct radix_tree_node *parent, static inline gfp_t root_gfp_mask(const struct radix_tree_root *root) { - return root->gfp_mask & __GFP_BITS_MASK; + return root->gfp_mask & (__GFP_BITS_MASK & ~GFP_ZONEMASK); } static inline void tag_set(struct radix_tree_node *node, unsigned int tag, @@ -2285,6 +2285,7 @@ void __init radix_tree_init(void) int ret; BUILD_BUG_ON(RADIX_TREE_MAX_TAGS + __GFP_BITS_SHIFT > 32); + BUILD_BUG_ON(ROOT_IS_IDR & ~GFP_ZONEMASK); radix_tree_node_cachep = kmem_cache_create("radix_tree_node", sizeof(struct radix_tree_node), 0, SLAB_PANIC | SLAB_RECLAIM_ACCOUNT, diff --git a/tools/testing/radix-tree/linux/gfp.h b/tools/testing/radix-tree/linux/gfp.h index e3201ccf54c3..32159c08a52e 100644 --- a/tools/testing/radix-tree/linux/gfp.h +++ b/tools/testing/radix-tree/linux/gfp.h @@ -19,6 +19,7 @@ #define __GFP_RECLAIM (__GFP_DIRECT_RECLAIM|__GFP_KSWAPD_RECLAIM) +#define GFP_ZONEMASK 0x0fu #define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM) #define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) #define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM) -- cgit v1.3-14-g43fede From ee9294d6ddbd418807ae49f4ab4e6441c9da2a18 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Thu, 12 Apr 2018 23:31:17 +0300 Subject: proc: fixup copyright sign Add copyright in two files before they get autorubberstamped. Signed-off-by: Alexey Dobriyan Signed-off-by: Linus Torvalds --- tools/testing/selftests/proc/proc-loadavg-001.c | 2 +- tools/testing/selftests/proc/proc-self-map-files-001.c | 2 +- tools/testing/selftests/proc/proc-self-map-files-002.c | 2 +- tools/testing/selftests/proc/proc-self-syscall.c | 15 +++++++++++++++ tools/testing/selftests/proc/proc-self-wchan.c | 15 +++++++++++++++ tools/testing/selftests/proc/proc-uptime-001.c | 2 +- tools/testing/selftests/proc/proc-uptime-002.c | 2 +- tools/testing/selftests/proc/proc-uptime.h | 2 +- tools/testing/selftests/proc/read.c | 2 +- 9 files changed, 37 insertions(+), 7 deletions(-) (limited to 'tools/testing') diff --git a/tools/testing/selftests/proc/proc-loadavg-001.c b/tools/testing/selftests/proc/proc-loadavg-001.c index e38ad6d94d4b..fcff7047000d 100644 --- a/tools/testing/selftests/proc/proc-loadavg-001.c +++ b/tools/testing/selftests/proc/proc-loadavg-001.c @@ -1,5 +1,5 @@ /* - * Copyright _ 2018 Alexey Dobriyan + * Copyright © 2018 Alexey Dobriyan * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tools/testing/selftests/proc/proc-self-map-files-001.c b/tools/testing/selftests/proc/proc-self-map-files-001.c index af1d0a6af810..4209c64283d6 100644 --- a/tools/testing/selftests/proc/proc-self-map-files-001.c +++ b/tools/testing/selftests/proc/proc-self-map-files-001.c @@ -1,5 +1,5 @@ /* - * Copyright _ 2018 Alexey Dobriyan + * Copyright © 2018 Alexey Dobriyan * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tools/testing/selftests/proc/proc-self-map-files-002.c b/tools/testing/selftests/proc/proc-self-map-files-002.c index aebf4be56111..6f1f4a6e1ecb 100644 --- a/tools/testing/selftests/proc/proc-self-map-files-002.c +++ b/tools/testing/selftests/proc/proc-self-map-files-002.c @@ -1,5 +1,5 @@ /* - * Copyright _ 2018 Alexey Dobriyan + * Copyright © 2018 Alexey Dobriyan * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tools/testing/selftests/proc/proc-self-syscall.c b/tools/testing/selftests/proc/proc-self-syscall.c index 05eb6f91f1e9..5ab5f4810e43 100644 --- a/tools/testing/selftests/proc/proc-self-syscall.c +++ b/tools/testing/selftests/proc/proc-self-syscall.c @@ -1,3 +1,18 @@ +/* + * Copyright © 2018 Alexey Dobriyan + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #define _GNU_SOURCE #include #include diff --git a/tools/testing/selftests/proc/proc-self-wchan.c b/tools/testing/selftests/proc/proc-self-wchan.c index b8d8728a6869..a38b2fbaa7ad 100644 --- a/tools/testing/selftests/proc/proc-self-wchan.c +++ b/tools/testing/selftests/proc/proc-self-wchan.c @@ -1,3 +1,18 @@ +/* + * Copyright © 2018 Alexey Dobriyan + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ #include #include #include diff --git a/tools/testing/selftests/proc/proc-uptime-001.c b/tools/testing/selftests/proc/proc-uptime-001.c index 303f26092306..781f7a50fc3f 100644 --- a/tools/testing/selftests/proc/proc-uptime-001.c +++ b/tools/testing/selftests/proc/proc-uptime-001.c @@ -1,5 +1,5 @@ /* - * Copyright _ 2018 Alexey Dobriyan + * Copyright © 2018 Alexey Dobriyan * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tools/testing/selftests/proc/proc-uptime-002.c b/tools/testing/selftests/proc/proc-uptime-002.c index 0cb79e1f1674..30e2b7849089 100644 --- a/tools/testing/selftests/proc/proc-uptime-002.c +++ b/tools/testing/selftests/proc/proc-uptime-002.c @@ -1,5 +1,5 @@ /* - * Copyright _ 2018 Alexey Dobriyan + * Copyright © 2018 Alexey Dobriyan * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tools/testing/selftests/proc/proc-uptime.h b/tools/testing/selftests/proc/proc-uptime.h index d584419f50a7..0e464b50e9d9 100644 --- a/tools/testing/selftests/proc/proc-uptime.h +++ b/tools/testing/selftests/proc/proc-uptime.h @@ -1,5 +1,5 @@ /* - * Copyright _ 2018 Alexey Dobriyan + * Copyright © 2018 Alexey Dobriyan * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/tools/testing/selftests/proc/read.c b/tools/testing/selftests/proc/read.c index 12e397f78592..1e73c2232097 100644 --- a/tools/testing/selftests/proc/read.c +++ b/tools/testing/selftests/proc/read.c @@ -1,5 +1,5 @@ /* - * Copyright _ 2018 Alexey Dobriyan + * Copyright © 2018 Alexey Dobriyan * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above -- cgit v1.3-14-g43fede