mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 19:21:31 -04:00
linux-kselftest-4.9-rc1-update
This update consists of:
- Fixes and improvements to existing tests
- Moving code from Documentation to selftests, samples, and tools.
Moves dnotify_test, prctl, ptp, vDSO, ia64, watchdog, and networking
tests from Documentation to selftests.
Moves mic/mpssd, misc-devices/mei, timers, watchdog, auxdisplay, and
blackfin examples from Documentation to samples.
Moves accounting, laptops/dslm, and pcmcia/crc32hash tools from
Documentation to tools.
Deletes BUILD_DOCSRC and its dependencies.
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAABAgAGBQJX/6zUAAoJEAsCRMQNDUMczIEP/0kH+yjJ3El4GYIokspR1/UU
++sy4XMzrD1UPy90v+ftcg4ss5R80r0v7EZ59k1UjDJSZ6WATHHGoZKCS2Dy3xcq
i+0vm7Bawh7YWrXD3TunwaL97lwb2DdVTSxRXuU4Hfv+oVynUfh/+ZlCH6RCM2nm
ZJE5PDYiq4nTVSRqFB2FyRE6yay5dPvpQ2ArwnSEw+ku4C+ZdGTGCWzS+aZBwZM/
ykePkGLVRXz9FsWTCmipJzYu0Z/M4xEGlfXQZiiLG2HicbJNP6AqJImbQrANm+TW
RFigYpofdhr9XG5TKTLIudaRt9qB6BE0mYEApZXH8U7NrHElfO9BBMEwzajl0V/2
q/r5iej/CJult3zsfkhdHo7GLXpOaDLyoXiUI6UTgL0XOdWLAWTqDYx4JJz9sXxp
B9dwKJeP5HLipk6FMkAHgJM90JKQFd/nLDKxeWexbMu/b/yQ2C9AR7NpdQ+c1X7I
8W8UNEi/fnK75+r4t3NfeD2/5boq/jwujSKEMDQm/3R8L8EFYYb/TRoujFn89Na3
wbZLV3hBL+KQ5lRyIx7X8RKyVJv1nlo9Wh57ItJed6zvGp5EmsI8w+DER2RfbO2c
HR2JPDKSxmU8O2WBfDW5QoiPQH8Lssd147Ir0UFE7mwBXgWWsmxJxDpufizAXwyJ
qnELJ9X3UFIdydtoObLr
=60kH
-----END PGP SIGNATURE-----
Merge tag 'linux-kselftest-4.9-rc1-update' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest
Pull kselftest updates from Shuah Khan:
"This update consists of:
- Fixes and improvements to existing tests
- Moving code from Documentation to selftests, samples, and tools:
* Moves dnotify_test, prctl, ptp, vDSO, ia64, watchdog, and
networking tests from Documentation to selftests.
* Moves mic/mpssd, misc-devices/mei, timers, watchdog, auxdisplay,
and blackfin examples from Documentation to samples.
* Moves accounting, laptops/dslm, and pcmcia/crc32hash tools from
Documentation to tools.
* Deletes BUILD_DOCSRC and its dependencies"
* tag 'linux-kselftest-4.9-rc1-update' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: (21 commits)
selftests/futex: Check ANSI terminal color support
Doc: update 00-INDEX files to reflect the runnable code move
samples: move blackfin gptimers-example from Documentation
tools: move pcmcia crc32hash tool from Documentation
tools: move laptops dslm tool from Documentation
tools: move accounting tool from Documentation
samples: move auxdisplay example code from Documentation
samples: move watchdog example code from Documentation
samples: move timers example code from Documentation
samples: move misc-devices/mei example code from Documentation
samples: move mic/mpssd example code from Documentation
selftests: Move networking/timestamping from Documentation
selftests: move watchdog tests from Documentation/watchdog
selftests: move ia64 tests from Documentation/ia64
selftests: move vDSO tests from Documentation/vDSO
selftests: move ptp tests from Documentation/ptp
selftests: move prctl tests from Documentation/prctl
selftests: move dnotify_test from Documentation/filesystems
selftests/timers: Add missing error code assignment before test
selftests/zram: replace ZRAM_LZ4_COMPRESS
...
This commit is contained in:
commit
5d89d9f502
105 changed files with 202 additions and 186 deletions
|
|
@ -46,7 +46,8 @@ IRQ.txt
|
|||
Intel-IOMMU.txt
|
||||
- basic info on the Intel IOMMU virtualization support.
|
||||
Makefile
|
||||
- some files in Documentation dir are actually sample code to build
|
||||
- This file does nothing. Removing it breaks make htmldocs and
|
||||
make distclean.
|
||||
ManagementStyle
|
||||
- how to (attempt to) manage kernel hackers.
|
||||
RCU/
|
||||
|
|
|
|||
|
|
@ -1,3 +1 @@
|
|||
subdir-y := accounting auxdisplay blackfin \
|
||||
filesystems filesystems ia64 laptops mic misc-devices \
|
||||
networking pcmcia prctl ptp timers vDSO watchdog
|
||||
subdir-y :=
|
||||
|
|
|
|||
1
Documentation/accounting/.gitignore
vendored
1
Documentation/accounting/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
getdelays
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-y := getdelays
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
||||
HOSTCFLAGS_getdelays.o += -I$(objtree)/usr/include
|
||||
|
|
@ -54,9 +54,9 @@ are sent to userspace without requiring a command. If it is the last exiting
|
|||
task of a thread group, the per-tgid statistics are also sent. More details
|
||||
are given in the taskstats interface description.
|
||||
|
||||
The getdelays.c userspace utility in this directory allows simple commands to
|
||||
be run and the corresponding delay statistics to be displayed. It also serves
|
||||
as an example of using the taskstats interface.
|
||||
The getdelays.c userspace utility in tools/accounting directory allows simple
|
||||
commands to be run and the corresponding delay statistics to be displayed. It
|
||||
also serves as an example of using the taskstats interface.
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
|
|
|||
|
|
@ -1,550 +0,0 @@
|
|||
/* getdelays.c
|
||||
*
|
||||
* Utility to get per-pid and per-tgid delay accounting statistics
|
||||
* Also illustrates usage of the taskstats interface
|
||||
*
|
||||
* Copyright (C) Shailabh Nagar, IBM Corp. 2005
|
||||
* Copyright (C) Balbir Singh, IBM Corp. 2006
|
||||
* Copyright (c) Jay Lan, SGI. 2006
|
||||
*
|
||||
* Compile with
|
||||
* gcc -I/usr/src/linux/include getdelays.c -o getdelays
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <linux/genetlink.h>
|
||||
#include <linux/taskstats.h>
|
||||
#include <linux/cgroupstats.h>
|
||||
|
||||
/*
|
||||
* Generic macros for dealing with netlink sockets. Might be duplicated
|
||||
* elsewhere. It is recommended that commercial grade applications use
|
||||
* libnl or libnetlink and use the interfaces provided by the library
|
||||
*/
|
||||
#define GENLMSG_DATA(glh) ((void *)(NLMSG_DATA(glh) + GENL_HDRLEN))
|
||||
#define GENLMSG_PAYLOAD(glh) (NLMSG_PAYLOAD(glh, 0) - GENL_HDRLEN)
|
||||
#define NLA_DATA(na) ((void *)((char*)(na) + NLA_HDRLEN))
|
||||
#define NLA_PAYLOAD(len) (len - NLA_HDRLEN)
|
||||
|
||||
#define err(code, fmt, arg...) \
|
||||
do { \
|
||||
fprintf(stderr, fmt, ##arg); \
|
||||
exit(code); \
|
||||
} while (0)
|
||||
|
||||
int done;
|
||||
int rcvbufsz;
|
||||
char name[100];
|
||||
int dbg;
|
||||
int print_delays;
|
||||
int print_io_accounting;
|
||||
int print_task_context_switch_counts;
|
||||
|
||||
#define PRINTF(fmt, arg...) { \
|
||||
if (dbg) { \
|
||||
printf(fmt, ##arg); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Maximum size of response requested or message sent */
|
||||
#define MAX_MSG_SIZE 1024
|
||||
/* Maximum number of cpus expected to be specified in a cpumask */
|
||||
#define MAX_CPUS 32
|
||||
|
||||
struct msgtemplate {
|
||||
struct nlmsghdr n;
|
||||
struct genlmsghdr g;
|
||||
char buf[MAX_MSG_SIZE];
|
||||
};
|
||||
|
||||
char cpumask[100+6*MAX_CPUS];
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fprintf(stderr, "getdelays [-dilv] [-w logfile] [-r bufsize] "
|
||||
"[-m cpumask] [-t tgid] [-p pid]\n");
|
||||
fprintf(stderr, " -d: print delayacct stats\n");
|
||||
fprintf(stderr, " -i: print IO accounting (works only with -p)\n");
|
||||
fprintf(stderr, " -l: listen forever\n");
|
||||
fprintf(stderr, " -v: debug on\n");
|
||||
fprintf(stderr, " -C: container path\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a raw netlink socket and bind
|
||||
*/
|
||||
static int create_nl_socket(int protocol)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_nl local;
|
||||
|
||||
fd = socket(AF_NETLINK, SOCK_RAW, protocol);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
if (rcvbufsz)
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
|
||||
&rcvbufsz, sizeof(rcvbufsz)) < 0) {
|
||||
fprintf(stderr, "Unable to set socket rcv buf size to %d\n",
|
||||
rcvbufsz);
|
||||
goto error;
|
||||
}
|
||||
|
||||
memset(&local, 0, sizeof(local));
|
||||
local.nl_family = AF_NETLINK;
|
||||
|
||||
if (bind(fd, (struct sockaddr *) &local, sizeof(local)) < 0)
|
||||
goto error;
|
||||
|
||||
return fd;
|
||||
error:
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
|
||||
__u8 genl_cmd, __u16 nla_type,
|
||||
void *nla_data, int nla_len)
|
||||
{
|
||||
struct nlattr *na;
|
||||
struct sockaddr_nl nladdr;
|
||||
int r, buflen;
|
||||
char *buf;
|
||||
|
||||
struct msgtemplate msg;
|
||||
|
||||
msg.n.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
|
||||
msg.n.nlmsg_type = nlmsg_type;
|
||||
msg.n.nlmsg_flags = NLM_F_REQUEST;
|
||||
msg.n.nlmsg_seq = 0;
|
||||
msg.n.nlmsg_pid = nlmsg_pid;
|
||||
msg.g.cmd = genl_cmd;
|
||||
msg.g.version = 0x1;
|
||||
na = (struct nlattr *) GENLMSG_DATA(&msg);
|
||||
na->nla_type = nla_type;
|
||||
na->nla_len = nla_len + 1 + NLA_HDRLEN;
|
||||
memcpy(NLA_DATA(na), nla_data, nla_len);
|
||||
msg.n.nlmsg_len += NLMSG_ALIGN(na->nla_len);
|
||||
|
||||
buf = (char *) &msg;
|
||||
buflen = msg.n.nlmsg_len ;
|
||||
memset(&nladdr, 0, sizeof(nladdr));
|
||||
nladdr.nl_family = AF_NETLINK;
|
||||
while ((r = sendto(sd, buf, buflen, 0, (struct sockaddr *) &nladdr,
|
||||
sizeof(nladdr))) < buflen) {
|
||||
if (r > 0) {
|
||||
buf += r;
|
||||
buflen -= r;
|
||||
} else if (errno != EAGAIN)
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Probe the controller in genetlink to find the family id
|
||||
* for the TASKSTATS family
|
||||
*/
|
||||
static int get_family_id(int sd)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct genlmsghdr g;
|
||||
char buf[256];
|
||||
} ans;
|
||||
|
||||
int id = 0, rc;
|
||||
struct nlattr *na;
|
||||
int rep_len;
|
||||
|
||||
strcpy(name, TASKSTATS_GENL_NAME);
|
||||
rc = send_cmd(sd, GENL_ID_CTRL, getpid(), CTRL_CMD_GETFAMILY,
|
||||
CTRL_ATTR_FAMILY_NAME, (void *)name,
|
||||
strlen(TASKSTATS_GENL_NAME)+1);
|
||||
if (rc < 0)
|
||||
return 0; /* sendto() failure? */
|
||||
|
||||
rep_len = recv(sd, &ans, sizeof(ans), 0);
|
||||
if (ans.n.nlmsg_type == NLMSG_ERROR ||
|
||||
(rep_len < 0) || !NLMSG_OK((&ans.n), rep_len))
|
||||
return 0;
|
||||
|
||||
na = (struct nlattr *) GENLMSG_DATA(&ans);
|
||||
na = (struct nlattr *) ((char *) na + NLA_ALIGN(na->nla_len));
|
||||
if (na->nla_type == CTRL_ATTR_FAMILY_ID) {
|
||||
id = *(__u16 *) NLA_DATA(na);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
#define average_ms(t, c) (t / 1000000ULL / (c ? c : 1))
|
||||
|
||||
static void print_delayacct(struct taskstats *t)
|
||||
{
|
||||
printf("\n\nCPU %15s%15s%15s%15s%15s\n"
|
||||
" %15llu%15llu%15llu%15llu%15.3fms\n"
|
||||
"IO %15s%15s%15s\n"
|
||||
" %15llu%15llu%15llums\n"
|
||||
"SWAP %15s%15s%15s\n"
|
||||
" %15llu%15llu%15llums\n"
|
||||
"RECLAIM %12s%15s%15s\n"
|
||||
" %15llu%15llu%15llums\n",
|
||||
"count", "real total", "virtual total",
|
||||
"delay total", "delay average",
|
||||
(unsigned long long)t->cpu_count,
|
||||
(unsigned long long)t->cpu_run_real_total,
|
||||
(unsigned long long)t->cpu_run_virtual_total,
|
||||
(unsigned long long)t->cpu_delay_total,
|
||||
average_ms((double)t->cpu_delay_total, t->cpu_count),
|
||||
"count", "delay total", "delay average",
|
||||
(unsigned long long)t->blkio_count,
|
||||
(unsigned long long)t->blkio_delay_total,
|
||||
average_ms(t->blkio_delay_total, t->blkio_count),
|
||||
"count", "delay total", "delay average",
|
||||
(unsigned long long)t->swapin_count,
|
||||
(unsigned long long)t->swapin_delay_total,
|
||||
average_ms(t->swapin_delay_total, t->swapin_count),
|
||||
"count", "delay total", "delay average",
|
||||
(unsigned long long)t->freepages_count,
|
||||
(unsigned long long)t->freepages_delay_total,
|
||||
average_ms(t->freepages_delay_total, t->freepages_count));
|
||||
}
|
||||
|
||||
static void task_context_switch_counts(struct taskstats *t)
|
||||
{
|
||||
printf("\n\nTask %15s%15s\n"
|
||||
" %15llu%15llu\n",
|
||||
"voluntary", "nonvoluntary",
|
||||
(unsigned long long)t->nvcsw, (unsigned long long)t->nivcsw);
|
||||
}
|
||||
|
||||
static void print_cgroupstats(struct cgroupstats *c)
|
||||
{
|
||||
printf("sleeping %llu, blocked %llu, running %llu, stopped %llu, "
|
||||
"uninterruptible %llu\n", (unsigned long long)c->nr_sleeping,
|
||||
(unsigned long long)c->nr_io_wait,
|
||||
(unsigned long long)c->nr_running,
|
||||
(unsigned long long)c->nr_stopped,
|
||||
(unsigned long long)c->nr_uninterruptible);
|
||||
}
|
||||
|
||||
|
||||
static void print_ioacct(struct taskstats *t)
|
||||
{
|
||||
printf("%s: read=%llu, write=%llu, cancelled_write=%llu\n",
|
||||
t->ac_comm,
|
||||
(unsigned long long)t->read_bytes,
|
||||
(unsigned long long)t->write_bytes,
|
||||
(unsigned long long)t->cancelled_write_bytes);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int c, rc, rep_len, aggr_len, len2;
|
||||
int cmd_type = TASKSTATS_CMD_ATTR_UNSPEC;
|
||||
__u16 id;
|
||||
__u32 mypid;
|
||||
|
||||
struct nlattr *na;
|
||||
int nl_sd = -1;
|
||||
int len = 0;
|
||||
pid_t tid = 0;
|
||||
pid_t rtid = 0;
|
||||
|
||||
int fd = 0;
|
||||
int count = 0;
|
||||
int write_file = 0;
|
||||
int maskset = 0;
|
||||
char *logfile = NULL;
|
||||
int loop = 0;
|
||||
int containerset = 0;
|
||||
char *containerpath = NULL;
|
||||
int cfd = 0;
|
||||
int forking = 0;
|
||||
sigset_t sigset;
|
||||
|
||||
struct msgtemplate msg;
|
||||
|
||||
while (!forking) {
|
||||
c = getopt(argc, argv, "qdiw:r:m:t:p:vlC:c:");
|
||||
if (c < 0)
|
||||
break;
|
||||
|
||||
switch (c) {
|
||||
case 'd':
|
||||
printf("print delayacct stats ON\n");
|
||||
print_delays = 1;
|
||||
break;
|
||||
case 'i':
|
||||
printf("printing IO accounting\n");
|
||||
print_io_accounting = 1;
|
||||
break;
|
||||
case 'q':
|
||||
printf("printing task/process context switch rates\n");
|
||||
print_task_context_switch_counts = 1;
|
||||
break;
|
||||
case 'C':
|
||||
containerset = 1;
|
||||
containerpath = optarg;
|
||||
break;
|
||||
case 'w':
|
||||
logfile = strdup(optarg);
|
||||
printf("write to file %s\n", logfile);
|
||||
write_file = 1;
|
||||
break;
|
||||
case 'r':
|
||||
rcvbufsz = atoi(optarg);
|
||||
printf("receive buf size %d\n", rcvbufsz);
|
||||
if (rcvbufsz < 0)
|
||||
err(1, "Invalid rcv buf size\n");
|
||||
break;
|
||||
case 'm':
|
||||
strncpy(cpumask, optarg, sizeof(cpumask));
|
||||
cpumask[sizeof(cpumask) - 1] = '\0';
|
||||
maskset = 1;
|
||||
printf("cpumask %s maskset %d\n", cpumask, maskset);
|
||||
break;
|
||||
case 't':
|
||||
tid = atoi(optarg);
|
||||
if (!tid)
|
||||
err(1, "Invalid tgid\n");
|
||||
cmd_type = TASKSTATS_CMD_ATTR_TGID;
|
||||
break;
|
||||
case 'p':
|
||||
tid = atoi(optarg);
|
||||
if (!tid)
|
||||
err(1, "Invalid pid\n");
|
||||
cmd_type = TASKSTATS_CMD_ATTR_PID;
|
||||
break;
|
||||
case 'c':
|
||||
|
||||
/* Block SIGCHLD for sigwait() later */
|
||||
if (sigemptyset(&sigset) == -1)
|
||||
err(1, "Failed to empty sigset");
|
||||
if (sigaddset(&sigset, SIGCHLD))
|
||||
err(1, "Failed to set sigchld in sigset");
|
||||
sigprocmask(SIG_BLOCK, &sigset, NULL);
|
||||
|
||||
/* fork/exec a child */
|
||||
tid = fork();
|
||||
if (tid < 0)
|
||||
err(1, "Fork failed\n");
|
||||
if (tid == 0)
|
||||
if (execvp(argv[optind - 1],
|
||||
&argv[optind - 1]) < 0)
|
||||
exit(-1);
|
||||
|
||||
/* Set the command type and avoid further processing */
|
||||
cmd_type = TASKSTATS_CMD_ATTR_PID;
|
||||
forking = 1;
|
||||
break;
|
||||
case 'v':
|
||||
printf("debug on\n");
|
||||
dbg = 1;
|
||||
break;
|
||||
case 'l':
|
||||
printf("listen forever\n");
|
||||
loop = 1;
|
||||
break;
|
||||
default:
|
||||
usage();
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if (write_file) {
|
||||
fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
|
||||
if (fd == -1) {
|
||||
perror("Cannot open output file\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
nl_sd = create_nl_socket(NETLINK_GENERIC);
|
||||
if (nl_sd < 0)
|
||||
err(1, "error creating Netlink socket\n");
|
||||
|
||||
|
||||
mypid = getpid();
|
||||
id = get_family_id(nl_sd);
|
||||
if (!id) {
|
||||
fprintf(stderr, "Error getting family id, errno %d\n", errno);
|
||||
goto err;
|
||||
}
|
||||
PRINTF("family id %d\n", id);
|
||||
|
||||
if (maskset) {
|
||||
rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
|
||||
TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
|
||||
&cpumask, strlen(cpumask) + 1);
|
||||
PRINTF("Sent register cpumask, retval %d\n", rc);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "error sending register cpumask\n");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (tid && containerset) {
|
||||
fprintf(stderr, "Select either -t or -C, not both\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we forked a child, wait for it to exit. Cannot use waitpid()
|
||||
* as all the delicious data would be reaped as part of the wait
|
||||
*/
|
||||
if (tid && forking) {
|
||||
int sig_received;
|
||||
sigwait(&sigset, &sig_received);
|
||||
}
|
||||
|
||||
if (tid) {
|
||||
rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
|
||||
cmd_type, &tid, sizeof(__u32));
|
||||
PRINTF("Sent pid/tgid, retval %d\n", rc);
|
||||
if (rc < 0) {
|
||||
fprintf(stderr, "error sending tid/tgid cmd\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (containerset) {
|
||||
cfd = open(containerpath, O_RDONLY);
|
||||
if (cfd < 0) {
|
||||
perror("error opening container file");
|
||||
goto err;
|
||||
}
|
||||
rc = send_cmd(nl_sd, id, mypid, CGROUPSTATS_CMD_GET,
|
||||
CGROUPSTATS_CMD_ATTR_FD, &cfd, sizeof(__u32));
|
||||
if (rc < 0) {
|
||||
perror("error sending cgroupstats command");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
if (!maskset && !tid && !containerset) {
|
||||
usage();
|
||||
goto err;
|
||||
}
|
||||
|
||||
do {
|
||||
rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
|
||||
PRINTF("received %d bytes\n", rep_len);
|
||||
|
||||
if (rep_len < 0) {
|
||||
fprintf(stderr, "nonfatal reply error: errno %d\n",
|
||||
errno);
|
||||
continue;
|
||||
}
|
||||
if (msg.n.nlmsg_type == NLMSG_ERROR ||
|
||||
!NLMSG_OK((&msg.n), rep_len)) {
|
||||
struct nlmsgerr *err = NLMSG_DATA(&msg);
|
||||
fprintf(stderr, "fatal reply error, errno %d\n",
|
||||
err->error);
|
||||
goto done;
|
||||
}
|
||||
|
||||
PRINTF("nlmsghdr size=%zu, nlmsg_len=%d, rep_len=%d\n",
|
||||
sizeof(struct nlmsghdr), msg.n.nlmsg_len, rep_len);
|
||||
|
||||
|
||||
rep_len = GENLMSG_PAYLOAD(&msg.n);
|
||||
|
||||
na = (struct nlattr *) GENLMSG_DATA(&msg);
|
||||
len = 0;
|
||||
while (len < rep_len) {
|
||||
len += NLA_ALIGN(na->nla_len);
|
||||
switch (na->nla_type) {
|
||||
case TASKSTATS_TYPE_AGGR_TGID:
|
||||
/* Fall through */
|
||||
case TASKSTATS_TYPE_AGGR_PID:
|
||||
aggr_len = NLA_PAYLOAD(na->nla_len);
|
||||
len2 = 0;
|
||||
/* For nested attributes, na follows */
|
||||
na = (struct nlattr *) NLA_DATA(na);
|
||||
done = 0;
|
||||
while (len2 < aggr_len) {
|
||||
switch (na->nla_type) {
|
||||
case TASKSTATS_TYPE_PID:
|
||||
rtid = *(int *) NLA_DATA(na);
|
||||
if (print_delays)
|
||||
printf("PID\t%d\n", rtid);
|
||||
break;
|
||||
case TASKSTATS_TYPE_TGID:
|
||||
rtid = *(int *) NLA_DATA(na);
|
||||
if (print_delays)
|
||||
printf("TGID\t%d\n", rtid);
|
||||
break;
|
||||
case TASKSTATS_TYPE_STATS:
|
||||
count++;
|
||||
if (print_delays)
|
||||
print_delayacct((struct taskstats *) NLA_DATA(na));
|
||||
if (print_io_accounting)
|
||||
print_ioacct((struct taskstats *) NLA_DATA(na));
|
||||
if (print_task_context_switch_counts)
|
||||
task_context_switch_counts((struct taskstats *) NLA_DATA(na));
|
||||
if (fd) {
|
||||
if (write(fd, NLA_DATA(na), na->nla_len) < 0) {
|
||||
err(1,"write error\n");
|
||||
}
|
||||
}
|
||||
if (!loop)
|
||||
goto done;
|
||||
break;
|
||||
case TASKSTATS_TYPE_NULL:
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown nested"
|
||||
" nla_type %d\n",
|
||||
na->nla_type);
|
||||
break;
|
||||
}
|
||||
len2 += NLA_ALIGN(na->nla_len);
|
||||
na = (struct nlattr *)((char *)na +
|
||||
NLA_ALIGN(na->nla_len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CGROUPSTATS_TYPE_CGROUP_STATS:
|
||||
print_cgroupstats(NLA_DATA(na));
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown nla_type %d\n",
|
||||
na->nla_type);
|
||||
case TASKSTATS_TYPE_NULL:
|
||||
break;
|
||||
}
|
||||
na = (struct nlattr *) (GENLMSG_DATA(&msg) + len);
|
||||
}
|
||||
} while (loop);
|
||||
done:
|
||||
if (maskset) {
|
||||
rc = send_cmd(nl_sd, id, mypid, TASKSTATS_CMD_GET,
|
||||
TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
|
||||
&cpumask, strlen(cpumask) + 1);
|
||||
printf("Sent deregister mask, retval %d\n", rc);
|
||||
if (rc < 0)
|
||||
err(rc, "error sending deregister cpumask\n");
|
||||
}
|
||||
err:
|
||||
close(nl_sd);
|
||||
if (fd)
|
||||
close(fd);
|
||||
if (cfd)
|
||||
close(cfd);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -8,8 +8,6 @@ Interrupts
|
|||
- ARM Interrupt subsystem documentation
|
||||
IXP4xx
|
||||
- Intel IXP4xx Network processor.
|
||||
Makefile
|
||||
- Build sourcefiles as part of the Documentation-build for arm
|
||||
Netwinder
|
||||
- Netwinder specific documentation
|
||||
Porting
|
||||
|
|
|
|||
1
Documentation/auxdisplay/.gitignore
vendored
1
Documentation/auxdisplay/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
cfag12864b-example
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-y := cfag12864b-example
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
||||
HOSTCFLAGS_cfag12864b-example.o += -I$(objtree)/usr/include
|
||||
|
|
@ -101,5 +101,5 @@ Although the LCD won't get updated until the next refresh time arrives.
|
|||
Also, you can mmap the framebuffer: open & mmap, munmap & close...
|
||||
which is the best option for most uses.
|
||||
|
||||
Check Documentation/auxdisplay/cfag12864b-example.c
|
||||
Check samples/auxdisplay/cfag12864b-example.c
|
||||
for a real working userspace complete program with usage examples.
|
||||
|
|
|
|||
|
|
@ -1,281 +0,0 @@
|
|||
/*
|
||||
* Filename: cfag12864b-example.c
|
||||
* Version: 0.1.0
|
||||
* Description: cfag12864b LCD userspace example program
|
||||
* License: GPLv2
|
||||
*
|
||||
* Author: Copyright (C) Miguel Ojeda Sandonis
|
||||
* Date: 2006-10-31
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* ------------------------
|
||||
* start of cfag12864b code
|
||||
* ------------------------
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define CFAG12864B_WIDTH (128)
|
||||
#define CFAG12864B_HEIGHT (64)
|
||||
#define CFAG12864B_SIZE (128 * 64 / 8)
|
||||
#define CFAG12864B_BPB (8)
|
||||
#define CFAG12864B_ADDRESS(x, y) ((y) * CFAG12864B_WIDTH / \
|
||||
CFAG12864B_BPB + (x) / CFAG12864B_BPB)
|
||||
#define CFAG12864B_BIT(n) (((unsigned char) 1) << (n))
|
||||
|
||||
#undef CFAG12864B_DOCHECK
|
||||
#ifdef CFAG12864B_DOCHECK
|
||||
#define CFAG12864B_CHECK(x, y) ((x) < CFAG12864B_WIDTH && \
|
||||
(y) < CFAG12864B_HEIGHT)
|
||||
#else
|
||||
#define CFAG12864B_CHECK(x, y) (1)
|
||||
#endif
|
||||
|
||||
int cfag12864b_fd;
|
||||
unsigned char * cfag12864b_mem;
|
||||
unsigned char cfag12864b_buffer[CFAG12864B_SIZE];
|
||||
|
||||
/*
|
||||
* init a cfag12864b framebuffer device
|
||||
*
|
||||
* No error: return = 0
|
||||
* Unable to open: return = -1
|
||||
* Unable to mmap: return = -2
|
||||
*/
|
||||
static int cfag12864b_init(char *path)
|
||||
{
|
||||
cfag12864b_fd = open(path, O_RDWR);
|
||||
if (cfag12864b_fd == -1)
|
||||
return -1;
|
||||
|
||||
cfag12864b_mem = mmap(0, CFAG12864B_SIZE, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, cfag12864b_fd, 0);
|
||||
if (cfag12864b_mem == MAP_FAILED) {
|
||||
close(cfag12864b_fd);
|
||||
return -2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* exit a cfag12864b framebuffer device
|
||||
*/
|
||||
static void cfag12864b_exit(void)
|
||||
{
|
||||
munmap(cfag12864b_mem, CFAG12864B_SIZE);
|
||||
close(cfag12864b_fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* set (x, y) pixel
|
||||
*/
|
||||
static void cfag12864b_set(unsigned char x, unsigned char y)
|
||||
{
|
||||
if (CFAG12864B_CHECK(x, y))
|
||||
cfag12864b_buffer[CFAG12864B_ADDRESS(x, y)] |=
|
||||
CFAG12864B_BIT(x % CFAG12864B_BPB);
|
||||
}
|
||||
|
||||
/*
|
||||
* unset (x, y) pixel
|
||||
*/
|
||||
static void cfag12864b_unset(unsigned char x, unsigned char y)
|
||||
{
|
||||
if (CFAG12864B_CHECK(x, y))
|
||||
cfag12864b_buffer[CFAG12864B_ADDRESS(x, y)] &=
|
||||
~CFAG12864B_BIT(x % CFAG12864B_BPB);
|
||||
}
|
||||
|
||||
/*
|
||||
* is set (x, y) pixel?
|
||||
*
|
||||
* Pixel off: return = 0
|
||||
* Pixel on: return = 1
|
||||
*/
|
||||
static unsigned char cfag12864b_isset(unsigned char x, unsigned char y)
|
||||
{
|
||||
if (CFAG12864B_CHECK(x, y))
|
||||
if (cfag12864b_buffer[CFAG12864B_ADDRESS(x, y)] &
|
||||
CFAG12864B_BIT(x % CFAG12864B_BPB))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* not (x, y) pixel
|
||||
*/
|
||||
static void cfag12864b_not(unsigned char x, unsigned char y)
|
||||
{
|
||||
if (cfag12864b_isset(x, y))
|
||||
cfag12864b_unset(x, y);
|
||||
else
|
||||
cfag12864b_set(x, y);
|
||||
}
|
||||
|
||||
/*
|
||||
* fill (set all pixels)
|
||||
*/
|
||||
static void cfag12864b_fill(void)
|
||||
{
|
||||
unsigned short i;
|
||||
|
||||
for (i = 0; i < CFAG12864B_SIZE; i++)
|
||||
cfag12864b_buffer[i] = 0xFF;
|
||||
}
|
||||
|
||||
/*
|
||||
* clear (unset all pixels)
|
||||
*/
|
||||
static void cfag12864b_clear(void)
|
||||
{
|
||||
unsigned short i;
|
||||
|
||||
for (i = 0; i < CFAG12864B_SIZE; i++)
|
||||
cfag12864b_buffer[i] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* format a [128*64] matrix
|
||||
*
|
||||
* Pixel off: src[i] = 0
|
||||
* Pixel on: src[i] > 0
|
||||
*/
|
||||
static void cfag12864b_format(unsigned char * matrix)
|
||||
{
|
||||
unsigned char i, j, n;
|
||||
|
||||
for (i = 0; i < CFAG12864B_HEIGHT; i++)
|
||||
for (j = 0; j < CFAG12864B_WIDTH / CFAG12864B_BPB; j++) {
|
||||
cfag12864b_buffer[i * CFAG12864B_WIDTH / CFAG12864B_BPB +
|
||||
j] = 0;
|
||||
for (n = 0; n < CFAG12864B_BPB; n++)
|
||||
if (matrix[i * CFAG12864B_WIDTH +
|
||||
j * CFAG12864B_BPB + n])
|
||||
cfag12864b_buffer[i * CFAG12864B_WIDTH /
|
||||
CFAG12864B_BPB + j] |=
|
||||
CFAG12864B_BIT(n);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* blit buffer to lcd
|
||||
*/
|
||||
static void cfag12864b_blit(void)
|
||||
{
|
||||
memcpy(cfag12864b_mem, cfag12864b_buffer, CFAG12864B_SIZE);
|
||||
}
|
||||
|
||||
/*
|
||||
* ----------------------
|
||||
* end of cfag12864b code
|
||||
* ----------------------
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define EXAMPLES 6
|
||||
|
||||
static void example(unsigned char n)
|
||||
{
|
||||
unsigned short i, j;
|
||||
unsigned char matrix[CFAG12864B_WIDTH * CFAG12864B_HEIGHT];
|
||||
|
||||
if (n > EXAMPLES)
|
||||
return;
|
||||
|
||||
printf("Example %i/%i - ", n, EXAMPLES);
|
||||
|
||||
switch (n) {
|
||||
case 1:
|
||||
printf("Draw points setting bits");
|
||||
cfag12864b_clear();
|
||||
for (i = 0; i < CFAG12864B_WIDTH; i += 2)
|
||||
for (j = 0; j < CFAG12864B_HEIGHT; j += 2)
|
||||
cfag12864b_set(i, j);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
printf("Clear the LCD");
|
||||
cfag12864b_clear();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
printf("Draw rows formatting a [128*64] matrix");
|
||||
memset(matrix, 0, CFAG12864B_WIDTH * CFAG12864B_HEIGHT);
|
||||
for (i = 0; i < CFAG12864B_WIDTH; i++)
|
||||
for (j = 0; j < CFAG12864B_HEIGHT; j += 2)
|
||||
matrix[j * CFAG12864B_WIDTH + i] = 1;
|
||||
cfag12864b_format(matrix);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
printf("Fill the lcd");
|
||||
cfag12864b_fill();
|
||||
break;
|
||||
|
||||
case 5:
|
||||
printf("Draw columns unsetting bits");
|
||||
for (i = 0; i < CFAG12864B_WIDTH; i += 2)
|
||||
for (j = 0; j < CFAG12864B_HEIGHT; j++)
|
||||
cfag12864b_unset(i, j);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
printf("Do negative not-ing all bits");
|
||||
for (i = 0; i < CFAG12864B_WIDTH; i++)
|
||||
for (j = 0; j < CFAG12864B_HEIGHT; j ++)
|
||||
cfag12864b_not(i, j);
|
||||
break;
|
||||
}
|
||||
|
||||
puts(" - [Press Enter]");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
unsigned char n;
|
||||
|
||||
if (argc != 2) {
|
||||
printf(
|
||||
"Sintax: %s fbdev\n"
|
||||
"Usually: /dev/fb0, /dev/fb1...\n", argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (cfag12864b_init(argv[1])) {
|
||||
printf("Can't init %s fbdev\n", argv[1]);
|
||||
return -2;
|
||||
}
|
||||
|
||||
for (n = 1; n <= EXAMPLES; n++) {
|
||||
example(n);
|
||||
cfag12864b_blit();
|
||||
while (getchar() != '\n');
|
||||
}
|
||||
|
||||
cfag12864b_exit();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,10 +1,6 @@
|
|||
00-INDEX
|
||||
- This file
|
||||
Makefile
|
||||
- Makefile for gptimers example file.
|
||||
bfin-gpio-notes.txt
|
||||
- Notes in developing/using bfin-gpio driver.
|
||||
bfin-spi-notes.txt
|
||||
- Notes for using bfin spi bus driver.
|
||||
gptimers-example.c
|
||||
- gptimers example
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
ifneq ($(CONFIG_BLACKFIN),)
|
||||
ifneq ($(CONFIG_BFIN_GPTIMERS),)
|
||||
obj-m := gptimers-example.o
|
||||
endif
|
||||
endif
|
||||
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Simple gptimers example
|
||||
* http://docs.blackfin.uclinux.org/doku.php?id=linux-kernel:drivers:gptimers
|
||||
*
|
||||
* Copyright 2007-2009 Analog Devices Inc.
|
||||
*
|
||||
* Licensed under the GPL-2 or later.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <asm/gptimers.h>
|
||||
#include <asm/portmux.h>
|
||||
|
||||
/* ... random driver includes ... */
|
||||
|
||||
#define DRIVER_NAME "gptimer_example"
|
||||
|
||||
#ifdef IRQ_TIMER5
|
||||
#define SAMPLE_IRQ_TIMER IRQ_TIMER5
|
||||
#else
|
||||
#define SAMPLE_IRQ_TIMER IRQ_TIMER2
|
||||
#endif
|
||||
|
||||
struct gptimer_data {
|
||||
uint32_t period, width;
|
||||
};
|
||||
static struct gptimer_data data;
|
||||
|
||||
/* ... random driver state ... */
|
||||
|
||||
static irqreturn_t gptimer_example_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct gptimer_data *data = dev_id;
|
||||
|
||||
/* make sure it was our timer which caused the interrupt */
|
||||
if (!get_gptimer_intr(TIMER5_id))
|
||||
return IRQ_NONE;
|
||||
|
||||
/* read the width/period values that were captured for the waveform */
|
||||
data->width = get_gptimer_pwidth(TIMER5_id);
|
||||
data->period = get_gptimer_period(TIMER5_id);
|
||||
|
||||
/* acknowledge the interrupt */
|
||||
clear_gptimer_intr(TIMER5_id);
|
||||
|
||||
/* tell the upper layers we took care of things */
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
/* ... random driver code ... */
|
||||
|
||||
static int __init gptimer_example_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* grab the peripheral pins */
|
||||
ret = peripheral_request(P_TMR5, DRIVER_NAME);
|
||||
if (ret) {
|
||||
printk(KERN_NOTICE DRIVER_NAME ": peripheral request failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* grab the IRQ for the timer */
|
||||
ret = request_irq(SAMPLE_IRQ_TIMER, gptimer_example_irq,
|
||||
IRQF_SHARED, DRIVER_NAME, &data);
|
||||
if (ret) {
|
||||
printk(KERN_NOTICE DRIVER_NAME ": IRQ request failed\n");
|
||||
peripheral_free(P_TMR5);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* setup the timer and enable it */
|
||||
set_gptimer_config(TIMER5_id,
|
||||
WDTH_CAP | PULSE_HI | PERIOD_CNT | IRQ_ENA);
|
||||
enable_gptimers(TIMER5bit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
module_init(gptimer_example_init);
|
||||
|
||||
static void __exit gptimer_example_exit(void)
|
||||
{
|
||||
disable_gptimers(TIMER5bit);
|
||||
free_irq(SAMPLE_IRQ_TIMER, &data);
|
||||
peripheral_free(P_TMR5);
|
||||
}
|
||||
module_exit(gptimer_example_exit);
|
||||
|
||||
MODULE_LICENSE("BSD");
|
||||
1
Documentation/filesystems/.gitignore
vendored
1
Documentation/filesystems/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
dnotify_test
|
||||
|
|
@ -2,8 +2,6 @@
|
|||
- this file (info on some of the filesystems supported by linux).
|
||||
Locking
|
||||
- info on locking rules as they pertain to Linux VFS.
|
||||
Makefile
|
||||
- Makefile for building the filsystems-part of DocBook.
|
||||
9p.txt
|
||||
- 9p (v9fs) is an implementation of the Plan 9 remote fs protocol.
|
||||
adfs.txt
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-y := dnotify_test
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
#define _GNU_SOURCE /* needed to get the defines */
|
||||
#include <fcntl.h> /* in glibc 2.2 this has the needed
|
||||
values defined */
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static volatile int event_fd;
|
||||
|
||||
static void handler(int sig, siginfo_t *si, void *data)
|
||||
{
|
||||
event_fd = si->si_fd;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct sigaction act;
|
||||
int fd;
|
||||
|
||||
act.sa_sigaction = handler;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGRTMIN + 1, &act, NULL);
|
||||
|
||||
fd = open(".", O_RDONLY);
|
||||
fcntl(fd, F_SETSIG, SIGRTMIN + 1);
|
||||
fcntl(fd, F_NOTIFY, DN_MODIFY|DN_CREATE|DN_MULTISHOT);
|
||||
/* we will now be notified if any of the files
|
||||
in "." is modified or new files are created */
|
||||
while (1) {
|
||||
pause();
|
||||
printf("Got event on fd=%d\n", event_fd);
|
||||
}
|
||||
}
|
||||
1
Documentation/ia64/.gitignore
vendored
1
Documentation/ia64/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
aliasing-test
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-y := aliasing-test
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
|
@ -1,263 +0,0 @@
|
|||
/*
|
||||
* Exercise /dev/mem mmap cases that have been troublesome in the past
|
||||
*
|
||||
* (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
|
||||
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <fnmatch.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
int sum;
|
||||
|
||||
static int map_mem(char *path, off_t offset, size_t length, int touch)
|
||||
{
|
||||
int fd, rc;
|
||||
void *addr;
|
||||
int *c;
|
||||
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd == -1) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fnmatch("/proc/bus/pci/*", path, 0) == 0) {
|
||||
rc = ioctl(fd, PCIIOC_MMAP_IS_MEM);
|
||||
if (rc == -1)
|
||||
perror("PCIIOC_MMAP_IS_MEM ioctl");
|
||||
}
|
||||
|
||||
addr = mmap(NULL, length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset);
|
||||
if (addr == MAP_FAILED)
|
||||
return 1;
|
||||
|
||||
if (touch) {
|
||||
c = (int *) addr;
|
||||
while (c < (int *) (addr + length))
|
||||
sum += *c++;
|
||||
}
|
||||
|
||||
rc = munmap(addr, length);
|
||||
if (rc == -1) {
|
||||
perror("munmap");
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int scan_tree(char *path, char *file, off_t offset, size_t length, int touch)
|
||||
{
|
||||
struct dirent **namelist;
|
||||
char *name, *path2;
|
||||
int i, n, r, rc = 0, result = 0;
|
||||
struct stat buf;
|
||||
|
||||
n = scandir(path, &namelist, 0, alphasort);
|
||||
if (n < 0) {
|
||||
perror("scandir");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
name = namelist[i]->d_name;
|
||||
|
||||
if (fnmatch(".", name, 0) == 0)
|
||||
goto skip;
|
||||
if (fnmatch("..", name, 0) == 0)
|
||||
goto skip;
|
||||
|
||||
path2 = malloc(strlen(path) + strlen(name) + 3);
|
||||
strcpy(path2, path);
|
||||
strcat(path2, "/");
|
||||
strcat(path2, name);
|
||||
|
||||
if (fnmatch(file, name, 0) == 0) {
|
||||
rc = map_mem(path2, offset, length, touch);
|
||||
if (rc == 0)
|
||||
fprintf(stderr, "PASS: %s 0x%lx-0x%lx is %s\n", path2, offset, offset + length, touch ? "readable" : "mappable");
|
||||
else if (rc > 0)
|
||||
fprintf(stderr, "PASS: %s 0x%lx-0x%lx not mappable\n", path2, offset, offset + length);
|
||||
else {
|
||||
fprintf(stderr, "FAIL: %s 0x%lx-0x%lx not accessible\n", path2, offset, offset + length);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
r = lstat(path2, &buf);
|
||||
if (r == 0 && S_ISDIR(buf.st_mode)) {
|
||||
rc = scan_tree(path2, file, offset, length, touch);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
result |= rc;
|
||||
free(path2);
|
||||
|
||||
skip:
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
return result;
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
|
||||
static int read_rom(char *path)
|
||||
{
|
||||
int fd, rc;
|
||||
size_t size = 0;
|
||||
|
||||
fd = open(path, O_RDWR);
|
||||
if (fd == -1) {
|
||||
perror(path);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rc = write(fd, "1", 2);
|
||||
if (rc <= 0) {
|
||||
close(fd);
|
||||
perror("write");
|
||||
return -1;
|
||||
}
|
||||
|
||||
do {
|
||||
rc = read(fd, buf, sizeof(buf));
|
||||
if (rc > 0)
|
||||
size += rc;
|
||||
} while (rc > 0);
|
||||
|
||||
close(fd);
|
||||
return size;
|
||||
}
|
||||
|
||||
static int scan_rom(char *path, char *file)
|
||||
{
|
||||
struct dirent **namelist;
|
||||
char *name, *path2;
|
||||
int i, n, r, rc = 0, result = 0;
|
||||
struct stat buf;
|
||||
|
||||
n = scandir(path, &namelist, 0, alphasort);
|
||||
if (n < 0) {
|
||||
perror("scandir");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
name = namelist[i]->d_name;
|
||||
|
||||
if (fnmatch(".", name, 0) == 0)
|
||||
goto skip;
|
||||
if (fnmatch("..", name, 0) == 0)
|
||||
goto skip;
|
||||
|
||||
path2 = malloc(strlen(path) + strlen(name) + 3);
|
||||
strcpy(path2, path);
|
||||
strcat(path2, "/");
|
||||
strcat(path2, name);
|
||||
|
||||
if (fnmatch(file, name, 0) == 0) {
|
||||
rc = read_rom(path2);
|
||||
|
||||
/*
|
||||
* It's OK if the ROM is unreadable. Maybe there
|
||||
* is no ROM, or some other error occurred. The
|
||||
* important thing is that no MCA happened.
|
||||
*/
|
||||
if (rc > 0)
|
||||
fprintf(stderr, "PASS: %s read %d bytes\n", path2, rc);
|
||||
else {
|
||||
fprintf(stderr, "PASS: %s not readable\n", path2);
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
r = lstat(path2, &buf);
|
||||
if (r == 0 && S_ISDIR(buf.st_mode)) {
|
||||
rc = scan_rom(path2, file);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
result |= rc;
|
||||
free(path2);
|
||||
|
||||
skip:
|
||||
free(namelist[i]);
|
||||
}
|
||||
free(namelist);
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (map_mem("/dev/mem", 0, 0xA0000, 1) == 0)
|
||||
fprintf(stderr, "PASS: /dev/mem 0x0-0xa0000 is readable\n");
|
||||
else
|
||||
fprintf(stderr, "FAIL: /dev/mem 0x0-0xa0000 not accessible\n");
|
||||
|
||||
/*
|
||||
* It's not safe to blindly read the VGA frame buffer. If you know
|
||||
* how to poke the card the right way, it should respond, but it's
|
||||
* not safe in general. Many machines, e.g., Intel chipsets, cover
|
||||
* up a non-responding card by just returning -1, but others will
|
||||
* report the failure as a machine check.
|
||||
*/
|
||||
if (map_mem("/dev/mem", 0xA0000, 0x20000, 0) == 0)
|
||||
fprintf(stderr, "PASS: /dev/mem 0xa0000-0xc0000 is mappable\n");
|
||||
else
|
||||
fprintf(stderr, "FAIL: /dev/mem 0xa0000-0xc0000 not accessible\n");
|
||||
|
||||
if (map_mem("/dev/mem", 0xC0000, 0x40000, 1) == 0)
|
||||
fprintf(stderr, "PASS: /dev/mem 0xc0000-0x100000 is readable\n");
|
||||
else
|
||||
fprintf(stderr, "FAIL: /dev/mem 0xc0000-0x100000 not accessible\n");
|
||||
|
||||
/*
|
||||
* Often you can map all the individual pieces above (0-0xA0000,
|
||||
* 0xA0000-0xC0000, and 0xC0000-0x100000), but can't map the whole
|
||||
* thing at once. This is because the individual pieces use different
|
||||
* attributes, and there's no single attribute supported over the
|
||||
* whole region.
|
||||
*/
|
||||
rc = map_mem("/dev/mem", 0, 1024*1024, 0);
|
||||
if (rc == 0)
|
||||
fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 is mappable\n");
|
||||
else if (rc > 0)
|
||||
fprintf(stderr, "PASS: /dev/mem 0x0-0x100000 not mappable\n");
|
||||
else
|
||||
fprintf(stderr, "FAIL: /dev/mem 0x0-0x100000 not accessible\n");
|
||||
|
||||
scan_tree("/sys/class/pci_bus", "legacy_mem", 0, 0xA0000, 1);
|
||||
scan_tree("/sys/class/pci_bus", "legacy_mem", 0xA0000, 0x20000, 0);
|
||||
scan_tree("/sys/class/pci_bus", "legacy_mem", 0xC0000, 0x40000, 1);
|
||||
scan_tree("/sys/class/pci_bus", "legacy_mem", 0, 1024*1024, 0);
|
||||
|
||||
scan_rom("/sys/devices", "rom");
|
||||
|
||||
scan_tree("/proc/bus/pci", "??.?", 0, 0xA0000, 1);
|
||||
scan_tree("/proc/bus/pci", "??.?", 0xA0000, 0x20000, 0);
|
||||
scan_tree("/proc/bus/pci", "??.?", 0xC0000, 0x40000, 1);
|
||||
scan_tree("/proc/bus/pci", "??.?", 0, 1024*1024, 0);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
Linux Kernel Selftests
|
||||
|
||||
The kernel contains a set of "self tests" under the tools/testing/selftests/
|
||||
directory. These are intended to be small unit tests to exercise individual
|
||||
code paths in the kernel.
|
||||
directory. These are intended to be small tests to exercise individual code
|
||||
paths in the kernel. Tests are intended to be run after building, installing
|
||||
and booting a kernel.
|
||||
|
||||
On some systems, hot-plug tests could hang forever waiting for cpu and
|
||||
memory to be ready to be offlined. A special hot-plug target is created
|
||||
|
|
|
|||
1
Documentation/laptops/.gitignore
vendored
1
Documentation/laptops/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
dslm
|
||||
|
|
@ -1,13 +1,9 @@
|
|||
00-INDEX
|
||||
- This file
|
||||
Makefile
|
||||
- Makefile for building dslm example program.
|
||||
asus-laptop.txt
|
||||
- information on the Asus Laptop Extras driver.
|
||||
disk-shock-protection.txt
|
||||
- information on hard disk shock protection.
|
||||
dslm.c
|
||||
- Simple Disk Sleep Monitor program
|
||||
laptop-mode.txt
|
||||
- how to conserve battery power using laptop-mode.
|
||||
sony-laptop.txt
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-y := dslm
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
|
@ -1,166 +0,0 @@
|
|||
/*
|
||||
* dslm.c
|
||||
* Simple Disk Sleep Monitor
|
||||
* by Bartek Kania
|
||||
* Licensed under the GPL
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/hdreg.h>
|
||||
|
||||
#ifdef DEBUG
|
||||
#define D(x) x
|
||||
#else
|
||||
#define D(x)
|
||||
#endif
|
||||
|
||||
int endit = 0;
|
||||
|
||||
/* Check if the disk is in powersave-mode
|
||||
* Most of the code is stolen from hdparm.
|
||||
* 1 = active, 0 = standby/sleep, -1 = unknown */
|
||||
static int check_powermode(int fd)
|
||||
{
|
||||
unsigned char args[4] = {WIN_CHECKPOWERMODE1,0,0,0};
|
||||
int state;
|
||||
|
||||
if (ioctl(fd, HDIO_DRIVE_CMD, &args)
|
||||
&& (args[0] = WIN_CHECKPOWERMODE2) /* try again with 0x98 */
|
||||
&& ioctl(fd, HDIO_DRIVE_CMD, &args)) {
|
||||
if (errno != EIO || args[0] != 0 || args[1] != 0) {
|
||||
state = -1; /* "unknown"; */
|
||||
} else
|
||||
state = 0; /* "sleeping"; */
|
||||
} else {
|
||||
state = (args[2] == 255) ? 1 : 0;
|
||||
}
|
||||
D(printf(" drive state is: %d\n", state));
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
static char *state_name(int i)
|
||||
{
|
||||
if (i == -1) return "unknown";
|
||||
if (i == 0) return "sleeping";
|
||||
if (i == 1) return "active";
|
||||
|
||||
return "internal error";
|
||||
}
|
||||
|
||||
static char *myctime(time_t time)
|
||||
{
|
||||
char *ts = ctime(&time);
|
||||
ts[strlen(ts) - 1] = 0;
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
static void measure(int fd)
|
||||
{
|
||||
time_t start_time;
|
||||
int last_state;
|
||||
time_t last_time;
|
||||
int curr_state;
|
||||
time_t curr_time = 0;
|
||||
time_t time_diff;
|
||||
time_t active_time = 0;
|
||||
time_t sleep_time = 0;
|
||||
time_t unknown_time = 0;
|
||||
time_t total_time = 0;
|
||||
int changes = 0;
|
||||
float tmp;
|
||||
|
||||
printf("Starting measurements\n");
|
||||
|
||||
last_state = check_powermode(fd);
|
||||
start_time = last_time = time(0);
|
||||
printf(" System is in state %s\n\n", state_name(last_state));
|
||||
|
||||
while(!endit) {
|
||||
sleep(1);
|
||||
curr_state = check_powermode(fd);
|
||||
|
||||
if (curr_state != last_state || endit) {
|
||||
changes++;
|
||||
curr_time = time(0);
|
||||
time_diff = curr_time - last_time;
|
||||
|
||||
if (last_state == 1) active_time += time_diff;
|
||||
else if (last_state == 0) sleep_time += time_diff;
|
||||
else unknown_time += time_diff;
|
||||
|
||||
last_state = curr_state;
|
||||
last_time = curr_time;
|
||||
|
||||
printf("%s: State-change to %s\n", myctime(curr_time),
|
||||
state_name(curr_state));
|
||||
}
|
||||
}
|
||||
changes--; /* Compensate for SIGINT */
|
||||
|
||||
total_time = time(0) - start_time;
|
||||
printf("\nTotal running time: %lus\n", curr_time - start_time);
|
||||
printf(" State changed %d times\n", changes);
|
||||
|
||||
tmp = (float)sleep_time / (float)total_time * 100;
|
||||
printf(" Time in sleep state: %lus (%.2f%%)\n", sleep_time, tmp);
|
||||
tmp = (float)active_time / (float)total_time * 100;
|
||||
printf(" Time in active state: %lus (%.2f%%)\n", active_time, tmp);
|
||||
tmp = (float)unknown_time / (float)total_time * 100;
|
||||
printf(" Time in unknown state: %lus (%.2f%%)\n", unknown_time, tmp);
|
||||
}
|
||||
|
||||
static void ender(int s)
|
||||
{
|
||||
endit = 1;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
puts("usage: dslm [-w <time>] <disk>");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd;
|
||||
char *disk = 0;
|
||||
int settle_time = 60;
|
||||
|
||||
/* Parse the simple command-line */
|
||||
if (argc == 2)
|
||||
disk = argv[1];
|
||||
else if (argc == 4) {
|
||||
settle_time = atoi(argv[2]);
|
||||
disk = argv[3];
|
||||
} else
|
||||
usage();
|
||||
|
||||
if (!(fd = open(disk, O_RDONLY|O_NONBLOCK))) {
|
||||
printf("Can't open %s, because: %s\n", disk, strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (settle_time) {
|
||||
printf("Waiting %d seconds for the system to settle down to "
|
||||
"'normal'\n", settle_time);
|
||||
sleep(settle_time);
|
||||
} else
|
||||
puts("Not waiting for system to settle down");
|
||||
|
||||
signal(SIGINT, ender);
|
||||
|
||||
measure(fd);
|
||||
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -779,4 +779,4 @@ Monitoring tool
|
|||
---------------
|
||||
|
||||
Bartek Kania submitted this, it can be used to measure how much time your disk
|
||||
spends spun up/down. See Documentation/laptops/dslm.c
|
||||
spends spun up/down. See tools/laptop/dslm/dslm.c
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
subdir-y := mpssd
|
||||
1
Documentation/mic/mpssd/.gitignore
vendored
1
Documentation/mic/mpssd/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
mpssd
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
ifndef CROSS_COMPILE
|
||||
# List of programs to build
|
||||
hostprogs-$(CONFIG_X86_64) := mpssd
|
||||
|
||||
mpssd-objs := mpssd.o sysfs.o
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
||||
HOSTCFLAGS += -I$(objtree)/usr/include -I$(srctree)/tools/include
|
||||
|
||||
ifdef DEBUG
|
||||
HOSTCFLAGS += -DDEBUG=$(DEBUG)
|
||||
endif
|
||||
|
||||
HOSTLOADLIBES_mpssd := -lpthread
|
||||
|
||||
install:
|
||||
install mpssd /usr/sbin/mpssd
|
||||
install micctrl /usr/sbin/micctrl
|
||||
endif
|
||||
|
|
@ -1,173 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Intel MIC Platform Software Stack (MPSS)
|
||||
#
|
||||
# Copyright(c) 2013 Intel Corporation.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License, version 2, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# The full GNU General Public License is included in this distribution in
|
||||
# the file called "COPYING".
|
||||
#
|
||||
# Intel MIC User Space Tools.
|
||||
#
|
||||
# micctrl - Controls MIC boot/start/stop.
|
||||
#
|
||||
# chkconfig: 2345 95 05
|
||||
# description: start MPSS stack processing.
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: micctrl
|
||||
### END INIT INFO
|
||||
|
||||
# Source function library.
|
||||
. /etc/init.d/functions
|
||||
|
||||
sysfs="/sys/class/mic"
|
||||
|
||||
_status()
|
||||
{
|
||||
f=$sysfs/$1
|
||||
echo -e $1 state: "`cat $f/state`" shutdown_status: "`cat $f/shutdown_status`"
|
||||
}
|
||||
|
||||
status()
|
||||
{
|
||||
if [ "`echo $1 | head -c3`" == "mic" ]; then
|
||||
_status $1
|
||||
return $?
|
||||
fi
|
||||
for f in $sysfs/*
|
||||
do
|
||||
_status `basename $f`
|
||||
RETVAL=$?
|
||||
[ $RETVAL -ne 0 ] && return $RETVAL
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
_reset()
|
||||
{
|
||||
f=$sysfs/$1
|
||||
echo reset > $f/state
|
||||
}
|
||||
|
||||
reset()
|
||||
{
|
||||
if [ "`echo $1 | head -c3`" == "mic" ]; then
|
||||
_reset $1
|
||||
return $?
|
||||
fi
|
||||
for f in $sysfs/*
|
||||
do
|
||||
_reset `basename $f`
|
||||
RETVAL=$?
|
||||
[ $RETVAL -ne 0 ] && return $RETVAL
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
_boot()
|
||||
{
|
||||
f=$sysfs/$1
|
||||
echo "linux" > $f/bootmode
|
||||
echo "mic/uos.img" > $f/firmware
|
||||
echo "mic/$1.image" > $f/ramdisk
|
||||
echo "boot" > $f/state
|
||||
}
|
||||
|
||||
boot()
|
||||
{
|
||||
if [ "`echo $1 | head -c3`" == "mic" ]; then
|
||||
_boot $1
|
||||
return $?
|
||||
fi
|
||||
for f in $sysfs/*
|
||||
do
|
||||
_boot `basename $f`
|
||||
RETVAL=$?
|
||||
[ $RETVAL -ne 0 ] && return $RETVAL
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
_shutdown()
|
||||
{
|
||||
f=$sysfs/$1
|
||||
echo shutdown > $f/state
|
||||
}
|
||||
|
||||
shutdown()
|
||||
{
|
||||
if [ "`echo $1 | head -c3`" == "mic" ]; then
|
||||
_shutdown $1
|
||||
return $?
|
||||
fi
|
||||
for f in $sysfs/*
|
||||
do
|
||||
_shutdown `basename $f`
|
||||
RETVAL=$?
|
||||
[ $RETVAL -ne 0 ] && return $RETVAL
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
_wait()
|
||||
{
|
||||
f=$sysfs/$1
|
||||
while [ "`cat $f/state`" != "offline" -a "`cat $f/state`" != "online" ]
|
||||
do
|
||||
sleep 1
|
||||
echo -e "Waiting for $1 to go offline"
|
||||
done
|
||||
}
|
||||
|
||||
wait()
|
||||
{
|
||||
if [ "`echo $1 | head -c3`" == "mic" ]; then
|
||||
_wait $1
|
||||
return $?
|
||||
fi
|
||||
# Wait for the cards to go offline
|
||||
for f in $sysfs/*
|
||||
do
|
||||
_wait `basename $f`
|
||||
RETVAL=$?
|
||||
[ $RETVAL -ne 0 ] && return $RETVAL
|
||||
done
|
||||
return 0
|
||||
}
|
||||
|
||||
if [ ! -d "$sysfs" ]; then
|
||||
echo -e $"Module unloaded "
|
||||
exit 3
|
||||
fi
|
||||
|
||||
case $1 in
|
||||
-s)
|
||||
status $2
|
||||
;;
|
||||
-r)
|
||||
reset $2
|
||||
;;
|
||||
-b)
|
||||
boot $2
|
||||
;;
|
||||
-S)
|
||||
shutdown $2
|
||||
;;
|
||||
-w)
|
||||
wait $2
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {-s (status) |-r (reset) |-b (boot) |-S (shutdown) |-w (wait)}"
|
||||
exit 2
|
||||
esac
|
||||
|
||||
exit $?
|
||||
|
|
@ -1,200 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Intel MIC Platform Software Stack (MPSS)
|
||||
#
|
||||
# Copyright(c) 2013 Intel Corporation.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License, version 2, as
|
||||
# published by the Free Software Foundation.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# The full GNU General Public License is included in this distribution in
|
||||
# the file called "COPYING".
|
||||
#
|
||||
# Intel MIC User Space Tools.
|
||||
#
|
||||
# mpss Start mpssd.
|
||||
#
|
||||
# chkconfig: 2345 95 05
|
||||
# description: start MPSS stack processing.
|
||||
#
|
||||
### BEGIN INIT INFO
|
||||
# Provides: mpss
|
||||
# Required-Start:
|
||||
# Required-Stop:
|
||||
# Short-Description: MPSS stack control
|
||||
# Description: MPSS stack control
|
||||
### END INIT INFO
|
||||
|
||||
# Source function library.
|
||||
. /etc/init.d/functions
|
||||
|
||||
exec=/usr/sbin/mpssd
|
||||
sysfs="/sys/class/mic"
|
||||
mic_modules="mic_host mic_x100_dma scif vop"
|
||||
|
||||
start()
|
||||
{
|
||||
[ -x $exec ] || exit 5
|
||||
|
||||
if [ "`ps -e | awk '{print $4}' | grep mpssd | head -1`" = "mpssd" ]; then
|
||||
echo -e $"MPSSD already running! "
|
||||
success
|
||||
echo
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e $"Starting MPSS Stack"
|
||||
echo -e $"Loading MIC drivers:" $mic_modules
|
||||
|
||||
modprobe -a $mic_modules
|
||||
RETVAL=$?
|
||||
if [ $RETVAL -ne 0 ]; then
|
||||
failure
|
||||
echo
|
||||
return $RETVAL
|
||||
fi
|
||||
|
||||
# Start the daemon
|
||||
echo -n $"Starting MPSSD "
|
||||
$exec
|
||||
RETVAL=$?
|
||||
if [ $RETVAL -ne 0 ]; then
|
||||
failure
|
||||
echo
|
||||
return $RETVAL
|
||||
fi
|
||||
success
|
||||
echo
|
||||
|
||||
sleep 5
|
||||
|
||||
# Boot the cards
|
||||
micctrl -b
|
||||
|
||||
# Wait till ping works
|
||||
for f in $sysfs/*
|
||||
do
|
||||
count=100
|
||||
ipaddr=`cat $f/cmdline`
|
||||
ipaddr=${ipaddr#*address,}
|
||||
ipaddr=`echo $ipaddr | cut -d, -f1 | cut -d\; -f1`
|
||||
while [ $count -ge 0 ]
|
||||
do
|
||||
echo -e "Pinging "`basename $f`" "
|
||||
ping -c 1 $ipaddr &> /dev/null
|
||||
RETVAL=$?
|
||||
if [ $RETVAL -eq 0 ]; then
|
||||
success
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
count=`expr $count - 1`
|
||||
done
|
||||
[ $RETVAL -ne 0 ] && failure || success
|
||||
echo
|
||||
done
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
stop()
|
||||
{
|
||||
echo -e $"Shutting down MPSS Stack: "
|
||||
|
||||
# Bail out if module is unloaded
|
||||
if [ ! -d "$sysfs" ]; then
|
||||
echo -n $"Module unloaded "
|
||||
success
|
||||
echo
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Shut down the cards.
|
||||
micctrl -S
|
||||
|
||||
# Wait for the cards to go offline
|
||||
for f in $sysfs/*
|
||||
do
|
||||
while [ "`cat $f/state`" != "ready" ]
|
||||
do
|
||||
sleep 1
|
||||
echo -e "Waiting for "`basename $f`" to become ready"
|
||||
done
|
||||
done
|
||||
|
||||
# Display the status of the cards
|
||||
micctrl -s
|
||||
|
||||
# Kill MPSSD now
|
||||
echo -n $"Killing MPSSD"
|
||||
killall -9 mpssd 2>/dev/null
|
||||
RETVAL=$?
|
||||
[ $RETVAL -ne 0 ] && failure || success
|
||||
echo
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
restart()
|
||||
{
|
||||
stop
|
||||
sleep 5
|
||||
start
|
||||
}
|
||||
|
||||
status()
|
||||
{
|
||||
micctrl -s
|
||||
if [ "`ps -e | awk '{print $4}' | grep mpssd | head -n 1`" = "mpssd" ]; then
|
||||
echo "mpssd is running"
|
||||
else
|
||||
echo "mpssd is stopped"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
unload()
|
||||
{
|
||||
if [ ! -d "$sysfs" ]; then
|
||||
echo -n $"No MIC_HOST Module: "
|
||||
success
|
||||
echo
|
||||
return
|
||||
fi
|
||||
|
||||
stop
|
||||
|
||||
sleep 5
|
||||
echo -n $"Removing MIC drivers:" $mic_modules
|
||||
modprobe -r $mic_modules
|
||||
RETVAL=$?
|
||||
[ $RETVAL -ne 0 ] && failure || success
|
||||
echo
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
case $1 in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
restart)
|
||||
restart
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
unload)
|
||||
unload
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|restart|status|unload}"
|
||||
exit 2
|
||||
esac
|
||||
|
||||
exit $?
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,103 +0,0 @@
|
|||
/*
|
||||
* Intel MIC Platform Software Stack (MPSS)
|
||||
*
|
||||
* Copyright(c) 2013 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Intel MIC User Space Tools.
|
||||
*/
|
||||
#ifndef _MPSSD_H_
|
||||
#define _MPSSD_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <dirent.h>
|
||||
#include <libgen.h>
|
||||
#include <pthread.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <sys/dir.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <limits.h>
|
||||
#include <syslog.h>
|
||||
#include <getopt.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/virtio_ids.h>
|
||||
|
||||
#define MICSYSFSDIR "/sys/class/mic"
|
||||
#define LOGFILE_NAME "/var/log/mpssd"
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
struct mic_console_info {
|
||||
pthread_t console_thread;
|
||||
int virtio_console_fd;
|
||||
void *console_dp;
|
||||
};
|
||||
|
||||
struct mic_net_info {
|
||||
pthread_t net_thread;
|
||||
int virtio_net_fd;
|
||||
int tap_fd;
|
||||
void *net_dp;
|
||||
};
|
||||
|
||||
struct mic_virtblk_info {
|
||||
pthread_t block_thread;
|
||||
int virtio_block_fd;
|
||||
void *block_dp;
|
||||
volatile sig_atomic_t signaled;
|
||||
char *backend_file;
|
||||
int backend;
|
||||
void *backend_addr;
|
||||
long backend_size;
|
||||
};
|
||||
|
||||
struct mic_info {
|
||||
int id;
|
||||
char *name;
|
||||
pthread_t config_thread;
|
||||
pthread_t init_thread;
|
||||
pid_t pid;
|
||||
struct mic_console_info mic_console;
|
||||
struct mic_net_info mic_net;
|
||||
struct mic_virtblk_info mic_virtblk;
|
||||
int restart;
|
||||
int boot_on_resume;
|
||||
struct mic_info *next;
|
||||
};
|
||||
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
void mpsslog(char *format, ...);
|
||||
char *readsysfs(char *dir, char *entry);
|
||||
int setsysfs(char *dir, char *entry, char *value);
|
||||
#endif
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
/*
|
||||
* Intel MIC Platform Software Stack (MPSS)
|
||||
*
|
||||
* Copyright(c) 2013 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution in
|
||||
* the file called "COPYING".
|
||||
*
|
||||
* Intel MIC User Space Tools.
|
||||
*/
|
||||
|
||||
#include "mpssd.h"
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
|
||||
char *
|
||||
readsysfs(char *dir, char *entry)
|
||||
{
|
||||
char filename[PATH_MAX];
|
||||
char value[PAGE_SIZE];
|
||||
char *string = NULL;
|
||||
int fd;
|
||||
int len;
|
||||
|
||||
if (dir == NULL)
|
||||
snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry);
|
||||
else
|
||||
snprintf(filename, PATH_MAX,
|
||||
"%s/%s/%s", MICSYSFSDIR, dir, entry);
|
||||
|
||||
fd = open(filename, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
mpsslog("Failed to open sysfs entry '%s': %s\n",
|
||||
filename, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = read(fd, value, sizeof(value));
|
||||
if (len < 0) {
|
||||
mpsslog("Failed to read sysfs entry '%s': %s\n",
|
||||
filename, strerror(errno));
|
||||
goto readsys_ret;
|
||||
}
|
||||
if (len == 0)
|
||||
goto readsys_ret;
|
||||
|
||||
value[len - 1] = '\0';
|
||||
|
||||
string = malloc(strlen(value) + 1);
|
||||
if (string)
|
||||
strcpy(string, value);
|
||||
|
||||
readsys_ret:
|
||||
close(fd);
|
||||
return string;
|
||||
}
|
||||
|
||||
int
|
||||
setsysfs(char *dir, char *entry, char *value)
|
||||
{
|
||||
char filename[PATH_MAX];
|
||||
char *oldvalue;
|
||||
int fd, ret = 0;
|
||||
|
||||
if (dir == NULL)
|
||||
snprintf(filename, PATH_MAX, "%s/%s", MICSYSFSDIR, entry);
|
||||
else
|
||||
snprintf(filename, PATH_MAX, "%s/%s/%s",
|
||||
MICSYSFSDIR, dir, entry);
|
||||
|
||||
oldvalue = readsysfs(dir, entry);
|
||||
|
||||
fd = open(filename, O_RDWR);
|
||||
if (fd < 0) {
|
||||
ret = errno;
|
||||
mpsslog("Failed to open sysfs entry '%s': %s\n",
|
||||
filename, strerror(errno));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!oldvalue || strcmp(value, oldvalue)) {
|
||||
if (write(fd, value, strlen(value)) < 0) {
|
||||
ret = errno;
|
||||
mpsslog("Failed to write new sysfs entry '%s': %s\n",
|
||||
filename, strerror(errno));
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
done:
|
||||
if (oldvalue)
|
||||
free(oldvalue);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
subdir-y := mei
|
||||
1
Documentation/misc-devices/mei/.gitignore
vendored
1
Documentation/misc-devices/mei/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
mei-amt-version
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-y := mei-amt-version
|
||||
HOSTCFLAGS_mei-amt-version.o += -I$(objtree)/usr/include
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
TODO:
|
||||
- Cleanup and split the timer function
|
||||
|
|
@ -1,479 +0,0 @@
|
|||
/******************************************************************************
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Intel MEI Interface Header
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||
* USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called LICENSE.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Corporation.
|
||||
* linux-mei@linux.intel.com
|
||||
* http://www.intel.com
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <bits/wordsize.h>
|
||||
#include <linux/mei.h>
|
||||
|
||||
/*****************************************************************************
|
||||
* Intel Management Engine Interface
|
||||
*****************************************************************************/
|
||||
|
||||
#define mei_msg(_me, fmt, ARGS...) do { \
|
||||
if (_me->verbose) \
|
||||
fprintf(stderr, fmt, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
#define mei_err(_me, fmt, ARGS...) do { \
|
||||
fprintf(stderr, "Error: " fmt, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
struct mei {
|
||||
uuid_le guid;
|
||||
bool initialized;
|
||||
bool verbose;
|
||||
unsigned int buf_size;
|
||||
unsigned char prot_ver;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static void mei_deinit(struct mei *cl)
|
||||
{
|
||||
if (cl->fd != -1)
|
||||
close(cl->fd);
|
||||
cl->fd = -1;
|
||||
cl->buf_size = 0;
|
||||
cl->prot_ver = 0;
|
||||
cl->initialized = false;
|
||||
}
|
||||
|
||||
static bool mei_init(struct mei *me, const uuid_le *guid,
|
||||
unsigned char req_protocol_version, bool verbose)
|
||||
{
|
||||
int result;
|
||||
struct mei_client *cl;
|
||||
struct mei_connect_client_data data;
|
||||
|
||||
me->verbose = verbose;
|
||||
|
||||
me->fd = open("/dev/mei", O_RDWR);
|
||||
if (me->fd == -1) {
|
||||
mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
|
||||
goto err;
|
||||
}
|
||||
memcpy(&me->guid, guid, sizeof(*guid));
|
||||
memset(&data, 0, sizeof(data));
|
||||
me->initialized = true;
|
||||
|
||||
memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
|
||||
result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
|
||||
if (result) {
|
||||
mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
|
||||
goto err;
|
||||
}
|
||||
cl = &data.out_client_properties;
|
||||
mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
|
||||
mei_msg(me, "protocol_version %d\n", cl->protocol_version);
|
||||
|
||||
if ((req_protocol_version > 0) &&
|
||||
(cl->protocol_version != req_protocol_version)) {
|
||||
mei_err(me, "Intel MEI protocol version not supported\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
me->buf_size = cl->max_msg_length;
|
||||
me->prot_ver = cl->protocol_version;
|
||||
|
||||
return true;
|
||||
err:
|
||||
mei_deinit(me);
|
||||
return false;
|
||||
}
|
||||
|
||||
static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
|
||||
ssize_t len, unsigned long timeout)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
mei_msg(me, "call read length = %zd\n", len);
|
||||
|
||||
rc = read(me->fd, buffer, len);
|
||||
if (rc < 0) {
|
||||
mei_err(me, "read failed with status %zd %s\n",
|
||||
rc, strerror(errno));
|
||||
mei_deinit(me);
|
||||
} else {
|
||||
mei_msg(me, "read succeeded with result %zd\n", rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
|
||||
ssize_t len, unsigned long timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
ssize_t written;
|
||||
ssize_t rc;
|
||||
fd_set set;
|
||||
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout % 1000) * 1000000;
|
||||
|
||||
mei_msg(me, "call write length = %zd\n", len);
|
||||
|
||||
written = write(me->fd, buffer, len);
|
||||
if (written < 0) {
|
||||
rc = -errno;
|
||||
mei_err(me, "write failed with status %zd %s\n",
|
||||
written, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(me->fd, &set);
|
||||
rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
|
||||
if (rc > 0 && FD_ISSET(me->fd, &set)) {
|
||||
mei_msg(me, "write success\n");
|
||||
} else if (rc == 0) {
|
||||
mei_err(me, "write failed on timeout with status\n");
|
||||
goto out;
|
||||
} else { /* rc < 0 */
|
||||
mei_err(me, "write failed on select with status %zd\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = written;
|
||||
out:
|
||||
if (rc < 0)
|
||||
mei_deinit(me);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Intel Advanced Management Technology ME Client
|
||||
***************************************************************************/
|
||||
|
||||
#define AMT_MAJOR_VERSION 1
|
||||
#define AMT_MINOR_VERSION 1
|
||||
|
||||
#define AMT_STATUS_SUCCESS 0x0
|
||||
#define AMT_STATUS_INTERNAL_ERROR 0x1
|
||||
#define AMT_STATUS_NOT_READY 0x2
|
||||
#define AMT_STATUS_INVALID_AMT_MODE 0x3
|
||||
#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
|
||||
|
||||
#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000
|
||||
#define AMT_STATUS_SDK_RESOURCES 0x1004
|
||||
|
||||
|
||||
#define AMT_BIOS_VERSION_LEN 65
|
||||
#define AMT_VERSIONS_NUMBER 50
|
||||
#define AMT_UNICODE_STRING_LEN 20
|
||||
|
||||
struct amt_unicode_string {
|
||||
uint16_t length;
|
||||
char string[AMT_UNICODE_STRING_LEN];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct amt_version_type {
|
||||
struct amt_unicode_string description;
|
||||
struct amt_unicode_string version;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct amt_version {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct amt_code_versions {
|
||||
uint8_t bios[AMT_BIOS_VERSION_LEN];
|
||||
uint32_t count;
|
||||
struct amt_version_type versions[AMT_VERSIONS_NUMBER];
|
||||
} __attribute__((packed));
|
||||
|
||||
/***************************************************************************
|
||||
* Intel Advanced Management Technology Host Interface
|
||||
***************************************************************************/
|
||||
|
||||
struct amt_host_if_msg_header {
|
||||
struct amt_version version;
|
||||
uint16_t _reserved;
|
||||
uint32_t command;
|
||||
uint32_t length;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct amt_host_if_resp_header {
|
||||
struct amt_host_if_msg_header header;
|
||||
uint32_t status;
|
||||
unsigned char data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \
|
||||
0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
|
||||
|
||||
#define AMT_HOST_IF_CODE_VERSIONS_REQUEST 0x0400001A
|
||||
#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
|
||||
|
||||
const struct amt_host_if_msg_header CODE_VERSION_REQ = {
|
||||
.version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
|
||||
._reserved = 0,
|
||||
.command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
|
||||
.length = 0
|
||||
};
|
||||
|
||||
|
||||
struct amt_host_if {
|
||||
struct mei mei_cl;
|
||||
unsigned long send_timeout;
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
|
||||
static bool amt_host_if_init(struct amt_host_if *acmd,
|
||||
unsigned long send_timeout, bool verbose)
|
||||
{
|
||||
acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
|
||||
acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
|
||||
return acmd->initialized;
|
||||
}
|
||||
|
||||
static void amt_host_if_deinit(struct amt_host_if *acmd)
|
||||
{
|
||||
mei_deinit(&acmd->mei_cl);
|
||||
acmd->initialized = false;
|
||||
}
|
||||
|
||||
static uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
|
||||
{
|
||||
uint32_t status = AMT_STATUS_SUCCESS;
|
||||
struct amt_code_versions *code_ver;
|
||||
size_t code_ver_len;
|
||||
uint32_t ver_type_cnt;
|
||||
uint32_t len;
|
||||
uint32_t i;
|
||||
|
||||
code_ver = (struct amt_code_versions *)resp->data;
|
||||
/* length - sizeof(status) */
|
||||
code_ver_len = resp->header.length - sizeof(uint32_t);
|
||||
ver_type_cnt = code_ver_len -
|
||||
sizeof(code_ver->bios) -
|
||||
sizeof(code_ver->count);
|
||||
if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
|
||||
status = AMT_STATUS_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < code_ver->count; i++) {
|
||||
len = code_ver->versions[i].description.length;
|
||||
|
||||
if (len > AMT_UNICODE_STRING_LEN) {
|
||||
status = AMT_STATUS_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = code_ver->versions[i].version.length;
|
||||
if (code_ver->versions[i].version.string[len] != '\0' ||
|
||||
len != strlen(code_ver->versions[i].version.string)) {
|
||||
status = AMT_STATUS_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static uint32_t amt_verify_response_header(uint32_t command,
|
||||
const struct amt_host_if_msg_header *resp_hdr,
|
||||
uint32_t response_size)
|
||||
{
|
||||
if (response_size < sizeof(struct amt_host_if_resp_header)) {
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
} else if (response_size != (resp_hdr->length +
|
||||
sizeof(struct amt_host_if_msg_header))) {
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
} else if (resp_hdr->command != command) {
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
} else if (resp_hdr->_reserved != 0) {
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
} else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
|
||||
resp_hdr->version.minor < AMT_MINOR_VERSION) {
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
return AMT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t amt_host_if_call(struct amt_host_if *acmd,
|
||||
const unsigned char *command, ssize_t command_sz,
|
||||
uint8_t **read_buf, uint32_t rcmd,
|
||||
unsigned int expected_sz)
|
||||
{
|
||||
uint32_t in_buf_sz;
|
||||
uint32_t out_buf_sz;
|
||||
ssize_t written;
|
||||
uint32_t status;
|
||||
struct amt_host_if_resp_header *msg_hdr;
|
||||
|
||||
in_buf_sz = acmd->mei_cl.buf_size;
|
||||
*read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
|
||||
if (*read_buf == NULL)
|
||||
return AMT_STATUS_SDK_RESOURCES;
|
||||
memset(*read_buf, 0, in_buf_sz);
|
||||
msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
|
||||
|
||||
written = mei_send_msg(&acmd->mei_cl,
|
||||
command, command_sz, acmd->send_timeout);
|
||||
if (written != command_sz)
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
|
||||
out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
|
||||
if (out_buf_sz <= 0)
|
||||
return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
|
||||
|
||||
status = msg_hdr->status;
|
||||
if (status != AMT_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = amt_verify_response_header(rcmd,
|
||||
&msg_hdr->header, out_buf_sz);
|
||||
if (status != AMT_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (expected_sz && expected_sz != out_buf_sz)
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
|
||||
return AMT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static uint32_t amt_get_code_versions(struct amt_host_if *cmd,
|
||||
struct amt_code_versions *versions)
|
||||
{
|
||||
struct amt_host_if_resp_header *response = NULL;
|
||||
uint32_t status;
|
||||
|
||||
status = amt_host_if_call(cmd,
|
||||
(const unsigned char *)&CODE_VERSION_REQ,
|
||||
sizeof(CODE_VERSION_REQ),
|
||||
(uint8_t **)&response,
|
||||
AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
|
||||
|
||||
if (status != AMT_STATUS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
status = amt_verify_code_versions(response);
|
||||
if (status != AMT_STATUS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
memcpy(versions, response->data, sizeof(struct amt_code_versions));
|
||||
out:
|
||||
if (response != NULL)
|
||||
free(response);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/************************** end of amt_host_if_command ***********************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct amt_code_versions ver;
|
||||
struct amt_host_if acmd;
|
||||
unsigned int i;
|
||||
uint32_t status;
|
||||
int ret;
|
||||
bool verbose;
|
||||
|
||||
verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
|
||||
|
||||
if (!amt_host_if_init(&acmd, 5000, verbose)) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = amt_get_code_versions(&acmd, &ver);
|
||||
|
||||
amt_host_if_deinit(&acmd);
|
||||
|
||||
switch (status) {
|
||||
case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
|
||||
printf("Intel AMT: DISABLED\n");
|
||||
ret = 0;
|
||||
break;
|
||||
case AMT_STATUS_SUCCESS:
|
||||
printf("Intel AMT: ENABLED\n");
|
||||
for (i = 0; i < ver.count; i++) {
|
||||
printf("%s:\t%s\n", ver.versions[i].description.string,
|
||||
ver.versions[i].version.string);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
printf("An error has occurred\n");
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -10,8 +10,6 @@ LICENSE.qlge
|
|||
- GPLv2 for QLogic Linux qlge NIC Driver
|
||||
LICENSE.qlcnic
|
||||
- GPLv2 for QLogic Linux qlcnic NIC Driver
|
||||
Makefile
|
||||
- Makefile for docsrc.
|
||||
PLIP.txt
|
||||
- PLIP: The Parallel Line Internet Protocol device driver
|
||||
README.ipw2100
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
subdir-y := timestamping
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
timestamping
|
||||
txtimestamp
|
||||
hwtstamp_config
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
# To compile, from the source root
|
||||
#
|
||||
# make headers_install
|
||||
# make M=documentation
|
||||
|
||||
# List of programs to build
|
||||
hostprogs-y := hwtstamp_config timestamping txtimestamp
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
||||
HOSTCFLAGS_timestamping.o += -I$(objtree)/usr/include
|
||||
HOSTCFLAGS_txtimestamp.o += -I$(objtree)/usr/include
|
||||
HOSTCFLAGS_hwtstamp_config.o += -I$(objtree)/usr/include
|
||||
|
|
@ -1,134 +0,0 @@
|
|||
/* Test program for SIOC{G,S}HWTSTAMP
|
||||
* Copyright 2013 Solarflare Communications
|
||||
* Author: Ben Hutchings
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <linux/if.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/sockios.h>
|
||||
|
||||
static int
|
||||
lookup_value(const char **names, int size, const char *name)
|
||||
{
|
||||
int value;
|
||||
|
||||
for (value = 0; value < size; value++)
|
||||
if (names[value] && strcasecmp(names[value], name) == 0)
|
||||
return value;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static const char *
|
||||
lookup_name(const char **names, int size, int value)
|
||||
{
|
||||
return (value >= 0 && value < size) ? names[value] : NULL;
|
||||
}
|
||||
|
||||
static void list_names(FILE *f, const char **names, int size)
|
||||
{
|
||||
int value;
|
||||
|
||||
for (value = 0; value < size; value++)
|
||||
if (names[value])
|
||||
fprintf(f, " %s\n", names[value]);
|
||||
}
|
||||
|
||||
static const char *tx_types[] = {
|
||||
#define TX_TYPE(name) [HWTSTAMP_TX_ ## name] = #name
|
||||
TX_TYPE(OFF),
|
||||
TX_TYPE(ON),
|
||||
TX_TYPE(ONESTEP_SYNC)
|
||||
#undef TX_TYPE
|
||||
};
|
||||
#define N_TX_TYPES ((int)(sizeof(tx_types) / sizeof(tx_types[0])))
|
||||
|
||||
static const char *rx_filters[] = {
|
||||
#define RX_FILTER(name) [HWTSTAMP_FILTER_ ## name] = #name
|
||||
RX_FILTER(NONE),
|
||||
RX_FILTER(ALL),
|
||||
RX_FILTER(SOME),
|
||||
RX_FILTER(PTP_V1_L4_EVENT),
|
||||
RX_FILTER(PTP_V1_L4_SYNC),
|
||||
RX_FILTER(PTP_V1_L4_DELAY_REQ),
|
||||
RX_FILTER(PTP_V2_L4_EVENT),
|
||||
RX_FILTER(PTP_V2_L4_SYNC),
|
||||
RX_FILTER(PTP_V2_L4_DELAY_REQ),
|
||||
RX_FILTER(PTP_V2_L2_EVENT),
|
||||
RX_FILTER(PTP_V2_L2_SYNC),
|
||||
RX_FILTER(PTP_V2_L2_DELAY_REQ),
|
||||
RX_FILTER(PTP_V2_EVENT),
|
||||
RX_FILTER(PTP_V2_SYNC),
|
||||
RX_FILTER(PTP_V2_DELAY_REQ),
|
||||
#undef RX_FILTER
|
||||
};
|
||||
#define N_RX_FILTERS ((int)(sizeof(rx_filters) / sizeof(rx_filters[0])))
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
fputs("Usage: hwtstamp_config if_name [tx_type rx_filter]\n"
|
||||
"tx_type is any of (case-insensitive):\n",
|
||||
stderr);
|
||||
list_names(stderr, tx_types, N_TX_TYPES);
|
||||
fputs("rx_filter is any of (case-insensitive):\n", stderr);
|
||||
list_names(stderr, rx_filters, N_RX_FILTERS);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct hwtstamp_config config;
|
||||
const char *name;
|
||||
int sock;
|
||||
|
||||
if ((argc != 2 && argc != 4) || (strlen(argv[1]) >= IFNAMSIZ)) {
|
||||
usage();
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (argc == 4) {
|
||||
config.flags = 0;
|
||||
config.tx_type = lookup_value(tx_types, N_TX_TYPES, argv[2]);
|
||||
config.rx_filter = lookup_value(rx_filters, N_RX_FILTERS, argv[3]);
|
||||
if (config.tx_type < 0 || config.rx_filter < 0) {
|
||||
usage();
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (sock < 0) {
|
||||
perror("socket");
|
||||
return 1;
|
||||
}
|
||||
|
||||
strcpy(ifr.ifr_name, argv[1]);
|
||||
ifr.ifr_data = (caddr_t)&config;
|
||||
|
||||
if (ioctl(sock, (argc == 2) ? SIOCGHWTSTAMP : SIOCSHWTSTAMP, &ifr)) {
|
||||
perror("ioctl");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("flags = %#x\n", config.flags);
|
||||
name = lookup_name(tx_types, N_TX_TYPES, config.tx_type);
|
||||
if (name)
|
||||
printf("tx_type = %s\n", name);
|
||||
else
|
||||
printf("tx_type = %d\n", config.tx_type);
|
||||
name = lookup_name(rx_filters, N_RX_FILTERS, config.rx_filter);
|
||||
if (name)
|
||||
printf("rx_filter = %s\n", name);
|
||||
else
|
||||
printf("rx_filter = %d\n", config.rx_filter);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,528 +0,0 @@
|
|||
/*
|
||||
* This program demonstrates how the various time stamping features in
|
||||
* the Linux kernel work. It emulates the behavior of a PTP
|
||||
* implementation in stand-alone master mode by sending PTPv1 Sync
|
||||
* multicasts once every second. It looks for similar packets, but
|
||||
* beyond that doesn't actually implement PTP.
|
||||
*
|
||||
* Outgoing packets are time stamped with SO_TIMESTAMPING with or
|
||||
* without hardware support.
|
||||
*
|
||||
* Incoming packets are time stamped with SO_TIMESTAMPING with or
|
||||
* without hardware support, SIOCGSTAMP[NS] (per-socket time stamp) and
|
||||
* SO_TIMESTAMP[NS].
|
||||
*
|
||||
* Copyright (C) 2009 Intel Corporation.
|
||||
* Author: Patrick Ohly <patrick.ohly@intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <linux/errqueue.h>
|
||||
|
||||
#ifndef SO_TIMESTAMPING
|
||||
# define SO_TIMESTAMPING 37
|
||||
# define SCM_TIMESTAMPING SO_TIMESTAMPING
|
||||
#endif
|
||||
|
||||
#ifndef SO_TIMESTAMPNS
|
||||
# define SO_TIMESTAMPNS 35
|
||||
#endif
|
||||
|
||||
#ifndef SIOCGSTAMPNS
|
||||
# define SIOCGSTAMPNS 0x8907
|
||||
#endif
|
||||
|
||||
#ifndef SIOCSHWTSTAMP
|
||||
# define SIOCSHWTSTAMP 0x89b0
|
||||
#endif
|
||||
|
||||
static void usage(const char *error)
|
||||
{
|
||||
if (error)
|
||||
printf("invalid option: %s\n", error);
|
||||
printf("timestamping interface option*\n\n"
|
||||
"Options:\n"
|
||||
" IP_MULTICAST_LOOP - looping outgoing multicasts\n"
|
||||
" SO_TIMESTAMP - normal software time stamping, ms resolution\n"
|
||||
" SO_TIMESTAMPNS - more accurate software time stamping\n"
|
||||
" SOF_TIMESTAMPING_TX_HARDWARE - hardware time stamping of outgoing packets\n"
|
||||
" SOF_TIMESTAMPING_TX_SOFTWARE - software fallback for outgoing packets\n"
|
||||
" SOF_TIMESTAMPING_RX_HARDWARE - hardware time stamping of incoming packets\n"
|
||||
" SOF_TIMESTAMPING_RX_SOFTWARE - software fallback for incoming packets\n"
|
||||
" SOF_TIMESTAMPING_SOFTWARE - request reporting of software time stamps\n"
|
||||
" SOF_TIMESTAMPING_RAW_HARDWARE - request reporting of raw HW time stamps\n"
|
||||
" SIOCGSTAMP - check last socket time stamp\n"
|
||||
" SIOCGSTAMPNS - more accurate socket time stamp\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void bail(const char *error)
|
||||
{
|
||||
printf("%s: %s\n", error, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static const unsigned char sync[] = {
|
||||
0x00, 0x01, 0x00, 0x01,
|
||||
0x5f, 0x44, 0x46, 0x4c,
|
||||
0x54, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x01,
|
||||
|
||||
/* fake uuid */
|
||||
0x00, 0x01,
|
||||
0x02, 0x03, 0x04, 0x05,
|
||||
|
||||
0x00, 0x01, 0x00, 0x37,
|
||||
0x00, 0x00, 0x00, 0x08,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x49, 0x05, 0xcd, 0x01,
|
||||
0x29, 0xb1, 0x8d, 0xb0,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x01,
|
||||
|
||||
/* fake uuid */
|
||||
0x00, 0x01,
|
||||
0x02, 0x03, 0x04, 0x05,
|
||||
|
||||
0x00, 0x00, 0x00, 0x37,
|
||||
0x00, 0x00, 0x00, 0x04,
|
||||
0x44, 0x46, 0x4c, 0x54,
|
||||
0x00, 0x00, 0xf0, 0x60,
|
||||
0x00, 0x01, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0xf0, 0x60,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x04,
|
||||
0x44, 0x46, 0x4c, 0x54,
|
||||
0x00, 0x01,
|
||||
|
||||
/* fake uuid */
|
||||
0x00, 0x01,
|
||||
0x02, 0x03, 0x04, 0x05,
|
||||
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static void sendpacket(int sock, struct sockaddr *addr, socklen_t addr_len)
|
||||
{
|
||||
struct timeval now;
|
||||
int res;
|
||||
|
||||
res = sendto(sock, sync, sizeof(sync), 0,
|
||||
addr, addr_len);
|
||||
gettimeofday(&now, 0);
|
||||
if (res < 0)
|
||||
printf("%s: %s\n", "send", strerror(errno));
|
||||
else
|
||||
printf("%ld.%06ld: sent %d bytes\n",
|
||||
(long)now.tv_sec, (long)now.tv_usec,
|
||||
res);
|
||||
}
|
||||
|
||||
static void printpacket(struct msghdr *msg, int res,
|
||||
char *data,
|
||||
int sock, int recvmsg_flags,
|
||||
int siocgstamp, int siocgstampns)
|
||||
{
|
||||
struct sockaddr_in *from_addr = (struct sockaddr_in *)msg->msg_name;
|
||||
struct cmsghdr *cmsg;
|
||||
struct timeval tv;
|
||||
struct timespec ts;
|
||||
struct timeval now;
|
||||
|
||||
gettimeofday(&now, 0);
|
||||
|
||||
printf("%ld.%06ld: received %s data, %d bytes from %s, %zu bytes control messages\n",
|
||||
(long)now.tv_sec, (long)now.tv_usec,
|
||||
(recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
|
||||
res,
|
||||
inet_ntoa(from_addr->sin_addr),
|
||||
msg->msg_controllen);
|
||||
for (cmsg = CMSG_FIRSTHDR(msg);
|
||||
cmsg;
|
||||
cmsg = CMSG_NXTHDR(msg, cmsg)) {
|
||||
printf(" cmsg len %zu: ", cmsg->cmsg_len);
|
||||
switch (cmsg->cmsg_level) {
|
||||
case SOL_SOCKET:
|
||||
printf("SOL_SOCKET ");
|
||||
switch (cmsg->cmsg_type) {
|
||||
case SO_TIMESTAMP: {
|
||||
struct timeval *stamp =
|
||||
(struct timeval *)CMSG_DATA(cmsg);
|
||||
printf("SO_TIMESTAMP %ld.%06ld",
|
||||
(long)stamp->tv_sec,
|
||||
(long)stamp->tv_usec);
|
||||
break;
|
||||
}
|
||||
case SO_TIMESTAMPNS: {
|
||||
struct timespec *stamp =
|
||||
(struct timespec *)CMSG_DATA(cmsg);
|
||||
printf("SO_TIMESTAMPNS %ld.%09ld",
|
||||
(long)stamp->tv_sec,
|
||||
(long)stamp->tv_nsec);
|
||||
break;
|
||||
}
|
||||
case SO_TIMESTAMPING: {
|
||||
struct timespec *stamp =
|
||||
(struct timespec *)CMSG_DATA(cmsg);
|
||||
printf("SO_TIMESTAMPING ");
|
||||
printf("SW %ld.%09ld ",
|
||||
(long)stamp->tv_sec,
|
||||
(long)stamp->tv_nsec);
|
||||
stamp++;
|
||||
/* skip deprecated HW transformed */
|
||||
stamp++;
|
||||
printf("HW raw %ld.%09ld",
|
||||
(long)stamp->tv_sec,
|
||||
(long)stamp->tv_nsec);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("type %d", cmsg->cmsg_type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case IPPROTO_IP:
|
||||
printf("IPPROTO_IP ");
|
||||
switch (cmsg->cmsg_type) {
|
||||
case IP_RECVERR: {
|
||||
struct sock_extended_err *err =
|
||||
(struct sock_extended_err *)CMSG_DATA(cmsg);
|
||||
printf("IP_RECVERR ee_errno '%s' ee_origin %d => %s",
|
||||
strerror(err->ee_errno),
|
||||
err->ee_origin,
|
||||
#ifdef SO_EE_ORIGIN_TIMESTAMPING
|
||||
err->ee_origin == SO_EE_ORIGIN_TIMESTAMPING ?
|
||||
"bounced packet" : "unexpected origin"
|
||||
#else
|
||||
"probably SO_EE_ORIGIN_TIMESTAMPING"
|
||||
#endif
|
||||
);
|
||||
if (res < sizeof(sync))
|
||||
printf(" => truncated data?!");
|
||||
else if (!memcmp(sync, data + res - sizeof(sync),
|
||||
sizeof(sync)))
|
||||
printf(" => GOT OUR DATA BACK (HURRAY!)");
|
||||
break;
|
||||
}
|
||||
case IP_PKTINFO: {
|
||||
struct in_pktinfo *pktinfo =
|
||||
(struct in_pktinfo *)CMSG_DATA(cmsg);
|
||||
printf("IP_PKTINFO interface index %u",
|
||||
pktinfo->ipi_ifindex);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printf("type %d", cmsg->cmsg_type);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
printf("level %d type %d",
|
||||
cmsg->cmsg_level,
|
||||
cmsg->cmsg_type);
|
||||
break;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (siocgstamp) {
|
||||
if (ioctl(sock, SIOCGSTAMP, &tv))
|
||||
printf(" %s: %s\n", "SIOCGSTAMP", strerror(errno));
|
||||
else
|
||||
printf("SIOCGSTAMP %ld.%06ld\n",
|
||||
(long)tv.tv_sec,
|
||||
(long)tv.tv_usec);
|
||||
}
|
||||
if (siocgstampns) {
|
||||
if (ioctl(sock, SIOCGSTAMPNS, &ts))
|
||||
printf(" %s: %s\n", "SIOCGSTAMPNS", strerror(errno));
|
||||
else
|
||||
printf("SIOCGSTAMPNS %ld.%09ld\n",
|
||||
(long)ts.tv_sec,
|
||||
(long)ts.tv_nsec);
|
||||
}
|
||||
}
|
||||
|
||||
static void recvpacket(int sock, int recvmsg_flags,
|
||||
int siocgstamp, int siocgstampns)
|
||||
{
|
||||
char data[256];
|
||||
struct msghdr msg;
|
||||
struct iovec entry;
|
||||
struct sockaddr_in from_addr;
|
||||
struct {
|
||||
struct cmsghdr cm;
|
||||
char control[512];
|
||||
} control;
|
||||
int res;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = &entry;
|
||||
msg.msg_iovlen = 1;
|
||||
entry.iov_base = data;
|
||||
entry.iov_len = sizeof(data);
|
||||
msg.msg_name = (caddr_t)&from_addr;
|
||||
msg.msg_namelen = sizeof(from_addr);
|
||||
msg.msg_control = &control;
|
||||
msg.msg_controllen = sizeof(control);
|
||||
|
||||
res = recvmsg(sock, &msg, recvmsg_flags|MSG_DONTWAIT);
|
||||
if (res < 0) {
|
||||
printf("%s %s: %s\n",
|
||||
"recvmsg",
|
||||
(recvmsg_flags & MSG_ERRQUEUE) ? "error" : "regular",
|
||||
strerror(errno));
|
||||
} else {
|
||||
printpacket(&msg, res, data,
|
||||
sock, recvmsg_flags,
|
||||
siocgstamp, siocgstampns);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int so_timestamping_flags = 0;
|
||||
int so_timestamp = 0;
|
||||
int so_timestampns = 0;
|
||||
int siocgstamp = 0;
|
||||
int siocgstampns = 0;
|
||||
int ip_multicast_loop = 0;
|
||||
char *interface;
|
||||
int i;
|
||||
int enabled = 1;
|
||||
int sock;
|
||||
struct ifreq device;
|
||||
struct ifreq hwtstamp;
|
||||
struct hwtstamp_config hwconfig, hwconfig_requested;
|
||||
struct sockaddr_in addr;
|
||||
struct ip_mreq imr;
|
||||
struct in_addr iaddr;
|
||||
int val;
|
||||
socklen_t len;
|
||||
struct timeval next;
|
||||
|
||||
if (argc < 2)
|
||||
usage(0);
|
||||
interface = argv[1];
|
||||
|
||||
for (i = 2; i < argc; i++) {
|
||||
if (!strcasecmp(argv[i], "SO_TIMESTAMP"))
|
||||
so_timestamp = 1;
|
||||
else if (!strcasecmp(argv[i], "SO_TIMESTAMPNS"))
|
||||
so_timestampns = 1;
|
||||
else if (!strcasecmp(argv[i], "SIOCGSTAMP"))
|
||||
siocgstamp = 1;
|
||||
else if (!strcasecmp(argv[i], "SIOCGSTAMPNS"))
|
||||
siocgstampns = 1;
|
||||
else if (!strcasecmp(argv[i], "IP_MULTICAST_LOOP"))
|
||||
ip_multicast_loop = 1;
|
||||
else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_HARDWARE"))
|
||||
so_timestamping_flags |= SOF_TIMESTAMPING_TX_HARDWARE;
|
||||
else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_TX_SOFTWARE"))
|
||||
so_timestamping_flags |= SOF_TIMESTAMPING_TX_SOFTWARE;
|
||||
else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_HARDWARE"))
|
||||
so_timestamping_flags |= SOF_TIMESTAMPING_RX_HARDWARE;
|
||||
else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RX_SOFTWARE"))
|
||||
so_timestamping_flags |= SOF_TIMESTAMPING_RX_SOFTWARE;
|
||||
else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_SOFTWARE"))
|
||||
so_timestamping_flags |= SOF_TIMESTAMPING_SOFTWARE;
|
||||
else if (!strcasecmp(argv[i], "SOF_TIMESTAMPING_RAW_HARDWARE"))
|
||||
so_timestamping_flags |= SOF_TIMESTAMPING_RAW_HARDWARE;
|
||||
else
|
||||
usage(argv[i]);
|
||||
}
|
||||
|
||||
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (sock < 0)
|
||||
bail("socket");
|
||||
|
||||
memset(&device, 0, sizeof(device));
|
||||
strncpy(device.ifr_name, interface, sizeof(device.ifr_name));
|
||||
if (ioctl(sock, SIOCGIFADDR, &device) < 0)
|
||||
bail("getting interface IP address");
|
||||
|
||||
memset(&hwtstamp, 0, sizeof(hwtstamp));
|
||||
strncpy(hwtstamp.ifr_name, interface, sizeof(hwtstamp.ifr_name));
|
||||
hwtstamp.ifr_data = (void *)&hwconfig;
|
||||
memset(&hwconfig, 0, sizeof(hwconfig));
|
||||
hwconfig.tx_type =
|
||||
(so_timestamping_flags & SOF_TIMESTAMPING_TX_HARDWARE) ?
|
||||
HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
|
||||
hwconfig.rx_filter =
|
||||
(so_timestamping_flags & SOF_TIMESTAMPING_RX_HARDWARE) ?
|
||||
HWTSTAMP_FILTER_PTP_V1_L4_SYNC : HWTSTAMP_FILTER_NONE;
|
||||
hwconfig_requested = hwconfig;
|
||||
if (ioctl(sock, SIOCSHWTSTAMP, &hwtstamp) < 0) {
|
||||
if ((errno == EINVAL || errno == ENOTSUP) &&
|
||||
hwconfig_requested.tx_type == HWTSTAMP_TX_OFF &&
|
||||
hwconfig_requested.rx_filter == HWTSTAMP_FILTER_NONE)
|
||||
printf("SIOCSHWTSTAMP: disabling hardware time stamping not possible\n");
|
||||
else
|
||||
bail("SIOCSHWTSTAMP");
|
||||
}
|
||||
printf("SIOCSHWTSTAMP: tx_type %d requested, got %d; rx_filter %d requested, got %d\n",
|
||||
hwconfig_requested.tx_type, hwconfig.tx_type,
|
||||
hwconfig_requested.rx_filter, hwconfig.rx_filter);
|
||||
|
||||
/* bind to PTP port */
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
addr.sin_port = htons(319 /* PTP event port */);
|
||||
if (bind(sock,
|
||||
(struct sockaddr *)&addr,
|
||||
sizeof(struct sockaddr_in)) < 0)
|
||||
bail("bind");
|
||||
|
||||
/* set multicast group for outgoing packets */
|
||||
inet_aton("224.0.1.130", &iaddr); /* alternate PTP domain 1 */
|
||||
addr.sin_addr = iaddr;
|
||||
imr.imr_multiaddr.s_addr = iaddr.s_addr;
|
||||
imr.imr_interface.s_addr =
|
||||
((struct sockaddr_in *)&device.ifr_addr)->sin_addr.s_addr;
|
||||
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_IF,
|
||||
&imr.imr_interface.s_addr, sizeof(struct in_addr)) < 0)
|
||||
bail("set multicast");
|
||||
|
||||
/* join multicast group, loop our own packet */
|
||||
if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
&imr, sizeof(struct ip_mreq)) < 0)
|
||||
bail("join multicast group");
|
||||
|
||||
if (setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
&ip_multicast_loop, sizeof(enabled)) < 0) {
|
||||
bail("loop multicast");
|
||||
}
|
||||
|
||||
/* set socket options for time stamping */
|
||||
if (so_timestamp &&
|
||||
setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP,
|
||||
&enabled, sizeof(enabled)) < 0)
|
||||
bail("setsockopt SO_TIMESTAMP");
|
||||
|
||||
if (so_timestampns &&
|
||||
setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS,
|
||||
&enabled, sizeof(enabled)) < 0)
|
||||
bail("setsockopt SO_TIMESTAMPNS");
|
||||
|
||||
if (so_timestamping_flags &&
|
||||
setsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING,
|
||||
&so_timestamping_flags,
|
||||
sizeof(so_timestamping_flags)) < 0)
|
||||
bail("setsockopt SO_TIMESTAMPING");
|
||||
|
||||
/* request IP_PKTINFO for debugging purposes */
|
||||
if (setsockopt(sock, SOL_IP, IP_PKTINFO,
|
||||
&enabled, sizeof(enabled)) < 0)
|
||||
printf("%s: %s\n", "setsockopt IP_PKTINFO", strerror(errno));
|
||||
|
||||
/* verify socket options */
|
||||
len = sizeof(val);
|
||||
if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, &len) < 0)
|
||||
printf("%s: %s\n", "getsockopt SO_TIMESTAMP", strerror(errno));
|
||||
else
|
||||
printf("SO_TIMESTAMP %d\n", val);
|
||||
|
||||
if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPNS, &val, &len) < 0)
|
||||
printf("%s: %s\n", "getsockopt SO_TIMESTAMPNS",
|
||||
strerror(errno));
|
||||
else
|
||||
printf("SO_TIMESTAMPNS %d\n", val);
|
||||
|
||||
if (getsockopt(sock, SOL_SOCKET, SO_TIMESTAMPING, &val, &len) < 0) {
|
||||
printf("%s: %s\n", "getsockopt SO_TIMESTAMPING",
|
||||
strerror(errno));
|
||||
} else {
|
||||
printf("SO_TIMESTAMPING %d\n", val);
|
||||
if (val != so_timestamping_flags)
|
||||
printf(" not the expected value %d\n",
|
||||
so_timestamping_flags);
|
||||
}
|
||||
|
||||
/* send packets forever every five seconds */
|
||||
gettimeofday(&next, 0);
|
||||
next.tv_sec = (next.tv_sec + 1) / 5 * 5;
|
||||
next.tv_usec = 0;
|
||||
while (1) {
|
||||
struct timeval now;
|
||||
struct timeval delta;
|
||||
long delta_us;
|
||||
int res;
|
||||
fd_set readfs, errorfs;
|
||||
|
||||
gettimeofday(&now, 0);
|
||||
delta_us = (long)(next.tv_sec - now.tv_sec) * 1000000 +
|
||||
(long)(next.tv_usec - now.tv_usec);
|
||||
if (delta_us > 0) {
|
||||
/* continue waiting for timeout or data */
|
||||
delta.tv_sec = delta_us / 1000000;
|
||||
delta.tv_usec = delta_us % 1000000;
|
||||
|
||||
FD_ZERO(&readfs);
|
||||
FD_ZERO(&errorfs);
|
||||
FD_SET(sock, &readfs);
|
||||
FD_SET(sock, &errorfs);
|
||||
printf("%ld.%06ld: select %ldus\n",
|
||||
(long)now.tv_sec, (long)now.tv_usec,
|
||||
delta_us);
|
||||
res = select(sock + 1, &readfs, 0, &errorfs, &delta);
|
||||
gettimeofday(&now, 0);
|
||||
printf("%ld.%06ld: select returned: %d, %s\n",
|
||||
(long)now.tv_sec, (long)now.tv_usec,
|
||||
res,
|
||||
res < 0 ? strerror(errno) : "success");
|
||||
if (res > 0) {
|
||||
if (FD_ISSET(sock, &readfs))
|
||||
printf("ready for reading\n");
|
||||
if (FD_ISSET(sock, &errorfs))
|
||||
printf("has error\n");
|
||||
recvpacket(sock, 0,
|
||||
siocgstamp,
|
||||
siocgstampns);
|
||||
recvpacket(sock, MSG_ERRQUEUE,
|
||||
siocgstamp,
|
||||
siocgstampns);
|
||||
}
|
||||
} else {
|
||||
/* write one packet */
|
||||
sendpacket(sock,
|
||||
(struct sockaddr *)&addr,
|
||||
sizeof(addr));
|
||||
next.tv_sec += 5;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,549 +0,0 @@
|
|||
/*
|
||||
* Copyright 2014 Google Inc.
|
||||
* Author: willemb@google.com (Willem de Bruijn)
|
||||
*
|
||||
* Test software tx timestamping, including
|
||||
*
|
||||
* - SCHED, SND and ACK timestamps
|
||||
* - RAW, UDP and TCP
|
||||
* - IPv4 and IPv6
|
||||
* - various packet sizes (to test GSO and TSO)
|
||||
*
|
||||
* Consult the command line arguments for help on running
|
||||
* the various testcases.
|
||||
*
|
||||
* This test requires a dummy TCP server.
|
||||
* A simple `nc6 [-u] -l -p $DESTPORT` will do
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <asm/types.h>
|
||||
#include <error.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <linux/errqueue.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/net_tstamp.h>
|
||||
#include <netdb.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netpacket/packet.h>
|
||||
#include <poll.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* command line parameters */
|
||||
static int cfg_proto = SOCK_STREAM;
|
||||
static int cfg_ipproto = IPPROTO_TCP;
|
||||
static int cfg_num_pkts = 4;
|
||||
static int do_ipv4 = 1;
|
||||
static int do_ipv6 = 1;
|
||||
static int cfg_payload_len = 10;
|
||||
static bool cfg_show_payload;
|
||||
static bool cfg_do_pktinfo;
|
||||
static bool cfg_loop_nodata;
|
||||
static uint16_t dest_port = 9000;
|
||||
|
||||
static struct sockaddr_in daddr;
|
||||
static struct sockaddr_in6 daddr6;
|
||||
static struct timespec ts_prev;
|
||||
|
||||
static void __print_timestamp(const char *name, struct timespec *cur,
|
||||
uint32_t key, int payload_len)
|
||||
{
|
||||
if (!(cur->tv_sec | cur->tv_nsec))
|
||||
return;
|
||||
|
||||
fprintf(stderr, " %s: %lu s %lu us (seq=%u, len=%u)",
|
||||
name, cur->tv_sec, cur->tv_nsec / 1000,
|
||||
key, payload_len);
|
||||
|
||||
if ((ts_prev.tv_sec | ts_prev.tv_nsec)) {
|
||||
int64_t cur_ms, prev_ms;
|
||||
|
||||
cur_ms = (long) cur->tv_sec * 1000 * 1000;
|
||||
cur_ms += cur->tv_nsec / 1000;
|
||||
|
||||
prev_ms = (long) ts_prev.tv_sec * 1000 * 1000;
|
||||
prev_ms += ts_prev.tv_nsec / 1000;
|
||||
|
||||
fprintf(stderr, " (%+" PRId64 " us)", cur_ms - prev_ms);
|
||||
}
|
||||
|
||||
ts_prev = *cur;
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static void print_timestamp_usr(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
struct timeval tv; /* avoid dependency on -lrt */
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
|
||||
__print_timestamp(" USR", &ts, 0, 0);
|
||||
}
|
||||
|
||||
static void print_timestamp(struct scm_timestamping *tss, int tstype,
|
||||
int tskey, int payload_len)
|
||||
{
|
||||
const char *tsname;
|
||||
|
||||
switch (tstype) {
|
||||
case SCM_TSTAMP_SCHED:
|
||||
tsname = " ENQ";
|
||||
break;
|
||||
case SCM_TSTAMP_SND:
|
||||
tsname = " SND";
|
||||
break;
|
||||
case SCM_TSTAMP_ACK:
|
||||
tsname = " ACK";
|
||||
break;
|
||||
default:
|
||||
error(1, 0, "unknown timestamp type: %u",
|
||||
tstype);
|
||||
}
|
||||
__print_timestamp(tsname, &tss->ts[0], tskey, payload_len);
|
||||
}
|
||||
|
||||
/* TODO: convert to check_and_print payload once API is stable */
|
||||
static void print_payload(char *data, int len)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
if (len > 70)
|
||||
len = 70;
|
||||
|
||||
fprintf(stderr, "payload: ");
|
||||
for (i = 0; i < len; i++)
|
||||
fprintf(stderr, "%02hhx ", data[i]);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
static void print_pktinfo(int family, int ifindex, void *saddr, void *daddr)
|
||||
{
|
||||
char sa[INET6_ADDRSTRLEN], da[INET6_ADDRSTRLEN];
|
||||
|
||||
fprintf(stderr, " pktinfo: ifindex=%u src=%s dst=%s\n",
|
||||
ifindex,
|
||||
saddr ? inet_ntop(family, saddr, sa, sizeof(sa)) : "unknown",
|
||||
daddr ? inet_ntop(family, daddr, da, sizeof(da)) : "unknown");
|
||||
}
|
||||
|
||||
static void __poll(int fd)
|
||||
{
|
||||
struct pollfd pollfd;
|
||||
int ret;
|
||||
|
||||
memset(&pollfd, 0, sizeof(pollfd));
|
||||
pollfd.fd = fd;
|
||||
ret = poll(&pollfd, 1, 100);
|
||||
if (ret != 1)
|
||||
error(1, errno, "poll");
|
||||
}
|
||||
|
||||
static void __recv_errmsg_cmsg(struct msghdr *msg, int payload_len)
|
||||
{
|
||||
struct sock_extended_err *serr = NULL;
|
||||
struct scm_timestamping *tss = NULL;
|
||||
struct cmsghdr *cm;
|
||||
int batch = 0;
|
||||
|
||||
for (cm = CMSG_FIRSTHDR(msg);
|
||||
cm && cm->cmsg_len;
|
||||
cm = CMSG_NXTHDR(msg, cm)) {
|
||||
if (cm->cmsg_level == SOL_SOCKET &&
|
||||
cm->cmsg_type == SCM_TIMESTAMPING) {
|
||||
tss = (void *) CMSG_DATA(cm);
|
||||
} else if ((cm->cmsg_level == SOL_IP &&
|
||||
cm->cmsg_type == IP_RECVERR) ||
|
||||
(cm->cmsg_level == SOL_IPV6 &&
|
||||
cm->cmsg_type == IPV6_RECVERR)) {
|
||||
serr = (void *) CMSG_DATA(cm);
|
||||
if (serr->ee_errno != ENOMSG ||
|
||||
serr->ee_origin != SO_EE_ORIGIN_TIMESTAMPING) {
|
||||
fprintf(stderr, "unknown ip error %d %d\n",
|
||||
serr->ee_errno,
|
||||
serr->ee_origin);
|
||||
serr = NULL;
|
||||
}
|
||||
} else if (cm->cmsg_level == SOL_IP &&
|
||||
cm->cmsg_type == IP_PKTINFO) {
|
||||
struct in_pktinfo *info = (void *) CMSG_DATA(cm);
|
||||
print_pktinfo(AF_INET, info->ipi_ifindex,
|
||||
&info->ipi_spec_dst, &info->ipi_addr);
|
||||
} else if (cm->cmsg_level == SOL_IPV6 &&
|
||||
cm->cmsg_type == IPV6_PKTINFO) {
|
||||
struct in6_pktinfo *info6 = (void *) CMSG_DATA(cm);
|
||||
print_pktinfo(AF_INET6, info6->ipi6_ifindex,
|
||||
NULL, &info6->ipi6_addr);
|
||||
} else
|
||||
fprintf(stderr, "unknown cmsg %d,%d\n",
|
||||
cm->cmsg_level, cm->cmsg_type);
|
||||
|
||||
if (serr && tss) {
|
||||
print_timestamp(tss, serr->ee_info, serr->ee_data,
|
||||
payload_len);
|
||||
serr = NULL;
|
||||
tss = NULL;
|
||||
batch++;
|
||||
}
|
||||
}
|
||||
|
||||
if (batch > 1)
|
||||
fprintf(stderr, "batched %d timestamps\n", batch);
|
||||
}
|
||||
|
||||
static int recv_errmsg(int fd)
|
||||
{
|
||||
static char ctrl[1024 /* overprovision*/];
|
||||
static struct msghdr msg;
|
||||
struct iovec entry;
|
||||
static char *data;
|
||||
int ret = 0;
|
||||
|
||||
data = malloc(cfg_payload_len);
|
||||
if (!data)
|
||||
error(1, 0, "malloc");
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
memset(ctrl, 0, sizeof(ctrl));
|
||||
|
||||
entry.iov_base = data;
|
||||
entry.iov_len = cfg_payload_len;
|
||||
msg.msg_iov = &entry;
|
||||
msg.msg_iovlen = 1;
|
||||
msg.msg_name = NULL;
|
||||
msg.msg_namelen = 0;
|
||||
msg.msg_control = ctrl;
|
||||
msg.msg_controllen = sizeof(ctrl);
|
||||
|
||||
ret = recvmsg(fd, &msg, MSG_ERRQUEUE);
|
||||
if (ret == -1 && errno != EAGAIN)
|
||||
error(1, errno, "recvmsg");
|
||||
|
||||
if (ret >= 0) {
|
||||
__recv_errmsg_cmsg(&msg, ret);
|
||||
if (cfg_show_payload)
|
||||
print_payload(data, cfg_payload_len);
|
||||
}
|
||||
|
||||
free(data);
|
||||
return ret == -1;
|
||||
}
|
||||
|
||||
static void do_test(int family, unsigned int opt)
|
||||
{
|
||||
char *buf;
|
||||
int fd, i, val = 1, total_len;
|
||||
|
||||
if (family == AF_INET6 && cfg_proto != SOCK_STREAM) {
|
||||
/* due to lack of checksum generation code */
|
||||
fprintf(stderr, "test: skipping datagram over IPv6\n");
|
||||
return;
|
||||
}
|
||||
|
||||
total_len = cfg_payload_len;
|
||||
if (cfg_proto == SOCK_RAW) {
|
||||
total_len += sizeof(struct udphdr);
|
||||
if (cfg_ipproto == IPPROTO_RAW)
|
||||
total_len += sizeof(struct iphdr);
|
||||
}
|
||||
|
||||
buf = malloc(total_len);
|
||||
if (!buf)
|
||||
error(1, 0, "malloc");
|
||||
|
||||
fd = socket(family, cfg_proto, cfg_ipproto);
|
||||
if (fd < 0)
|
||||
error(1, errno, "socket");
|
||||
|
||||
if (cfg_proto == SOCK_STREAM) {
|
||||
if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
|
||||
(char*) &val, sizeof(val)))
|
||||
error(1, 0, "setsockopt no nagle");
|
||||
|
||||
if (family == PF_INET) {
|
||||
if (connect(fd, (void *) &daddr, sizeof(daddr)))
|
||||
error(1, errno, "connect ipv4");
|
||||
} else {
|
||||
if (connect(fd, (void *) &daddr6, sizeof(daddr6)))
|
||||
error(1, errno, "connect ipv6");
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg_do_pktinfo) {
|
||||
if (family == AF_INET6) {
|
||||
if (setsockopt(fd, SOL_IPV6, IPV6_RECVPKTINFO,
|
||||
&val, sizeof(val)))
|
||||
error(1, errno, "setsockopt pktinfo ipv6");
|
||||
} else {
|
||||
if (setsockopt(fd, SOL_IP, IP_PKTINFO,
|
||||
&val, sizeof(val)))
|
||||
error(1, errno, "setsockopt pktinfo ipv4");
|
||||
}
|
||||
}
|
||||
|
||||
opt |= SOF_TIMESTAMPING_SOFTWARE |
|
||||
SOF_TIMESTAMPING_OPT_CMSG |
|
||||
SOF_TIMESTAMPING_OPT_ID;
|
||||
if (cfg_loop_nodata)
|
||||
opt |= SOF_TIMESTAMPING_OPT_TSONLY;
|
||||
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_TIMESTAMPING,
|
||||
(char *) &opt, sizeof(opt)))
|
||||
error(1, 0, "setsockopt timestamping");
|
||||
|
||||
for (i = 0; i < cfg_num_pkts; i++) {
|
||||
memset(&ts_prev, 0, sizeof(ts_prev));
|
||||
memset(buf, 'a' + i, total_len);
|
||||
|
||||
if (cfg_proto == SOCK_RAW) {
|
||||
struct udphdr *udph;
|
||||
int off = 0;
|
||||
|
||||
if (cfg_ipproto == IPPROTO_RAW) {
|
||||
struct iphdr *iph = (void *) buf;
|
||||
|
||||
memset(iph, 0, sizeof(*iph));
|
||||
iph->ihl = 5;
|
||||
iph->version = 4;
|
||||
iph->ttl = 2;
|
||||
iph->daddr = daddr.sin_addr.s_addr;
|
||||
iph->protocol = IPPROTO_UDP;
|
||||
/* kernel writes saddr, csum, len */
|
||||
|
||||
off = sizeof(*iph);
|
||||
}
|
||||
|
||||
udph = (void *) buf + off;
|
||||
udph->source = ntohs(9000); /* random spoof */
|
||||
udph->dest = ntohs(dest_port);
|
||||
udph->len = ntohs(sizeof(*udph) + cfg_payload_len);
|
||||
udph->check = 0; /* not allowed for IPv6 */
|
||||
}
|
||||
|
||||
print_timestamp_usr();
|
||||
if (cfg_proto != SOCK_STREAM) {
|
||||
if (family == PF_INET)
|
||||
val = sendto(fd, buf, total_len, 0, (void *) &daddr, sizeof(daddr));
|
||||
else
|
||||
val = sendto(fd, buf, total_len, 0, (void *) &daddr6, sizeof(daddr6));
|
||||
} else {
|
||||
val = send(fd, buf, cfg_payload_len, 0);
|
||||
}
|
||||
if (val != total_len)
|
||||
error(1, errno, "send");
|
||||
|
||||
/* wait for all errors to be queued, else ACKs arrive OOO */
|
||||
usleep(50 * 1000);
|
||||
|
||||
__poll(fd);
|
||||
|
||||
while (!recv_errmsg(fd)) {}
|
||||
}
|
||||
|
||||
if (close(fd))
|
||||
error(1, errno, "close");
|
||||
|
||||
free(buf);
|
||||
usleep(400 * 1000);
|
||||
}
|
||||
|
||||
static void __attribute__((noreturn)) usage(const char *filepath)
|
||||
{
|
||||
fprintf(stderr, "\nUsage: %s [options] hostname\n"
|
||||
"\nwhere options are:\n"
|
||||
" -4: only IPv4\n"
|
||||
" -6: only IPv6\n"
|
||||
" -h: show this message\n"
|
||||
" -I: request PKTINFO\n"
|
||||
" -l N: send N bytes at a time\n"
|
||||
" -n: set no-payload option\n"
|
||||
" -r: use raw\n"
|
||||
" -R: use raw (IP_HDRINCL)\n"
|
||||
" -p N: connect to port N\n"
|
||||
" -u: use udp\n"
|
||||
" -x: show payload (up to 70 bytes)\n",
|
||||
filepath);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void parse_opt(int argc, char **argv)
|
||||
{
|
||||
int proto_count = 0;
|
||||
char c;
|
||||
|
||||
while ((c = getopt(argc, argv, "46hIl:np:rRux")) != -1) {
|
||||
switch (c) {
|
||||
case '4':
|
||||
do_ipv6 = 0;
|
||||
break;
|
||||
case '6':
|
||||
do_ipv4 = 0;
|
||||
break;
|
||||
case 'I':
|
||||
cfg_do_pktinfo = true;
|
||||
break;
|
||||
case 'n':
|
||||
cfg_loop_nodata = true;
|
||||
break;
|
||||
case 'r':
|
||||
proto_count++;
|
||||
cfg_proto = SOCK_RAW;
|
||||
cfg_ipproto = IPPROTO_UDP;
|
||||
break;
|
||||
case 'R':
|
||||
proto_count++;
|
||||
cfg_proto = SOCK_RAW;
|
||||
cfg_ipproto = IPPROTO_RAW;
|
||||
break;
|
||||
case 'u':
|
||||
proto_count++;
|
||||
cfg_proto = SOCK_DGRAM;
|
||||
cfg_ipproto = IPPROTO_UDP;
|
||||
break;
|
||||
case 'l':
|
||||
cfg_payload_len = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'p':
|
||||
dest_port = strtoul(optarg, NULL, 10);
|
||||
break;
|
||||
case 'x':
|
||||
cfg_show_payload = true;
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage(argv[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!cfg_payload_len)
|
||||
error(1, 0, "payload may not be nonzero");
|
||||
if (cfg_proto != SOCK_STREAM && cfg_payload_len > 1472)
|
||||
error(1, 0, "udp packet might exceed expected MTU");
|
||||
if (!do_ipv4 && !do_ipv6)
|
||||
error(1, 0, "pass -4 or -6, not both");
|
||||
if (proto_count > 1)
|
||||
error(1, 0, "pass -r, -R or -u, not multiple");
|
||||
|
||||
if (optind != argc - 1)
|
||||
error(1, 0, "missing required hostname argument");
|
||||
}
|
||||
|
||||
static void resolve_hostname(const char *hostname)
|
||||
{
|
||||
struct addrinfo *addrs, *cur;
|
||||
int have_ipv4 = 0, have_ipv6 = 0;
|
||||
|
||||
if (getaddrinfo(hostname, NULL, NULL, &addrs))
|
||||
error(1, errno, "getaddrinfo");
|
||||
|
||||
cur = addrs;
|
||||
while (cur && !have_ipv4 && !have_ipv6) {
|
||||
if (!have_ipv4 && cur->ai_family == AF_INET) {
|
||||
memcpy(&daddr, cur->ai_addr, sizeof(daddr));
|
||||
daddr.sin_port = htons(dest_port);
|
||||
have_ipv4 = 1;
|
||||
}
|
||||
else if (!have_ipv6 && cur->ai_family == AF_INET6) {
|
||||
memcpy(&daddr6, cur->ai_addr, sizeof(daddr6));
|
||||
daddr6.sin6_port = htons(dest_port);
|
||||
have_ipv6 = 1;
|
||||
}
|
||||
cur = cur->ai_next;
|
||||
}
|
||||
if (addrs)
|
||||
freeaddrinfo(addrs);
|
||||
|
||||
do_ipv4 &= have_ipv4;
|
||||
do_ipv6 &= have_ipv6;
|
||||
}
|
||||
|
||||
static void do_main(int family)
|
||||
{
|
||||
fprintf(stderr, "family: %s\n",
|
||||
family == PF_INET ? "INET" : "INET6");
|
||||
|
||||
fprintf(stderr, "test SND\n");
|
||||
do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE);
|
||||
|
||||
fprintf(stderr, "test ENQ\n");
|
||||
do_test(family, SOF_TIMESTAMPING_TX_SCHED);
|
||||
|
||||
fprintf(stderr, "test ENQ + SND\n");
|
||||
do_test(family, SOF_TIMESTAMPING_TX_SCHED |
|
||||
SOF_TIMESTAMPING_TX_SOFTWARE);
|
||||
|
||||
if (cfg_proto == SOCK_STREAM) {
|
||||
fprintf(stderr, "\ntest ACK\n");
|
||||
do_test(family, SOF_TIMESTAMPING_TX_ACK);
|
||||
|
||||
fprintf(stderr, "\ntest SND + ACK\n");
|
||||
do_test(family, SOF_TIMESTAMPING_TX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_TX_ACK);
|
||||
|
||||
fprintf(stderr, "\ntest ENQ + SND + ACK\n");
|
||||
do_test(family, SOF_TIMESTAMPING_TX_SCHED |
|
||||
SOF_TIMESTAMPING_TX_SOFTWARE |
|
||||
SOF_TIMESTAMPING_TX_ACK);
|
||||
}
|
||||
}
|
||||
|
||||
const char *sock_names[] = { NULL, "TCP", "UDP", "RAW" };
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc == 1)
|
||||
usage(argv[0]);
|
||||
|
||||
parse_opt(argc, argv);
|
||||
resolve_hostname(argv[argc - 1]);
|
||||
|
||||
fprintf(stderr, "protocol: %s\n", sock_names[cfg_proto]);
|
||||
fprintf(stderr, "payload: %u\n", cfg_payload_len);
|
||||
fprintf(stderr, "server port: %u\n", dest_port);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
if (do_ipv4)
|
||||
do_main(PF_INET);
|
||||
if (do_ipv6)
|
||||
do_main(PF_INET6);
|
||||
|
||||
return 0;
|
||||
}
|
||||
1
Documentation/pcmcia/.gitignore
vendored
1
Documentation/pcmcia/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
crc32hash
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-y := crc32hash
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
||||
HOSTCFLAGS_crc32hash.o += -I$(objtree)/usr/include
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
/* crc32hash.c - derived from linux/lib/crc32.c, GNU GPL v2 */
|
||||
/* Usage example:
|
||||
$ ./crc32hash "Dual Speed"
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static unsigned int crc32(unsigned char const *p, unsigned int len)
|
||||
{
|
||||
int i;
|
||||
unsigned int crc = 0;
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
unsigned int result;
|
||||
if (argc != 2) {
|
||||
printf("no string passed as argument\n");
|
||||
return -1;
|
||||
}
|
||||
result = crc32((unsigned char const *)argv[1], strlen(argv[1]));
|
||||
printf("0x%x\n", result);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -27,7 +27,7 @@ pcmcia:m0149cC1ABf06pfn00fn00pa725B842DpbF1EFEE84pc0877B627pd00000000
|
|||
The hex value after "pa" is the hash of product ID string 1, after "pb" for
|
||||
string 2 and so on.
|
||||
|
||||
Alternatively, you can use crc32hash (see Documentation/pcmcia/crc32hash.c)
|
||||
Alternatively, you can use crc32hash (see tools/pcmcia/crc32hash.c)
|
||||
to determine the crc32 hash. Simply pass the string you want to evaluate
|
||||
as argument to this program, e.g.:
|
||||
$ ./crc32hash "Dual Speed"
|
||||
$ tools/pcmcia/crc32hash "Dual Speed"
|
||||
|
|
|
|||
3
Documentation/prctl/.gitignore
vendored
3
Documentation/prctl/.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
|||
disable-tsc-ctxt-sw-stress-test
|
||||
disable-tsc-on-off-stress-test
|
||||
disable-tsc-test
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
ifndef CROSS_COMPILE
|
||||
# List of programs to build
|
||||
hostprogs-$(CONFIG_X86) := disable-tsc-ctxt-sw-stress-test disable-tsc-on-off-stress-test disable-tsc-test
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
||||
HOSTCFLAGS_disable-tsc-ctxt-sw-stress-test.o += -I$(objtree)/usr/include
|
||||
HOSTCFLAGS_disable-tsc-on-off-stress-test.o += -I$(objtree)/usr/include
|
||||
HOSTCFLAGS_disable-tsc-test.o += -I$(objtree)/usr/include
|
||||
endif
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
/*
|
||||
* Tests for prctl(PR_GET_TSC, ...) / prctl(PR_SET_TSC, ...)
|
||||
*
|
||||
* Tests if the control register is updated correctly
|
||||
* at context switches
|
||||
*
|
||||
* Warning: this test will cause a very high load for a few seconds
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <inttypes.h>
|
||||
#include <wait.h>
|
||||
|
||||
|
||||
#include <sys/prctl.h>
|
||||
#include <linux/prctl.h>
|
||||
|
||||
/* Get/set the process' ability to use the timestamp counter instruction */
|
||||
#ifndef PR_GET_TSC
|
||||
#define PR_GET_TSC 25
|
||||
#define PR_SET_TSC 26
|
||||
# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
|
||||
# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */
|
||||
#endif
|
||||
|
||||
static uint64_t rdtsc(void)
|
||||
{
|
||||
uint32_t lo, hi;
|
||||
/* We cannot use "=A", since this would use %rax on x86_64 */
|
||||
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
||||
return (uint64_t)hi << 32 | lo;
|
||||
}
|
||||
|
||||
static void sigsegv_expect(int sig)
|
||||
{
|
||||
/* */
|
||||
}
|
||||
|
||||
static void segvtask(void)
|
||||
{
|
||||
if (prctl(PR_SET_TSC, PR_TSC_SIGSEGV) < 0)
|
||||
{
|
||||
perror("prctl");
|
||||
exit(0);
|
||||
}
|
||||
signal(SIGSEGV, sigsegv_expect);
|
||||
alarm(10);
|
||||
rdtsc();
|
||||
fprintf(stderr, "FATAL ERROR, rdtsc() succeeded while disabled\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
static void sigsegv_fail(int sig)
|
||||
{
|
||||
fprintf(stderr, "FATAL ERROR, rdtsc() failed while enabled\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void rdtsctask(void)
|
||||
{
|
||||
if (prctl(PR_SET_TSC, PR_TSC_ENABLE) < 0)
|
||||
{
|
||||
perror("prctl");
|
||||
exit(0);
|
||||
}
|
||||
signal(SIGSEGV, sigsegv_fail);
|
||||
alarm(10);
|
||||
for(;;) rdtsc();
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int n_tasks = 100, i;
|
||||
|
||||
fprintf(stderr, "[No further output means we're allright]\n");
|
||||
|
||||
for (i=0; i<n_tasks; i++)
|
||||
if (fork() == 0)
|
||||
{
|
||||
if (i & 1)
|
||||
segvtask();
|
||||
else
|
||||
rdtsctask();
|
||||
}
|
||||
|
||||
for (i=0; i<n_tasks; i++)
|
||||
wait(NULL);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Tests for prctl(PR_GET_TSC, ...) / prctl(PR_SET_TSC, ...)
|
||||
*
|
||||
* Tests if the control register is updated correctly
|
||||
* when set with prctl()
|
||||
*
|
||||
* Warning: this test will cause a very high load for a few seconds
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <inttypes.h>
|
||||
#include <wait.h>
|
||||
|
||||
|
||||
#include <sys/prctl.h>
|
||||
#include <linux/prctl.h>
|
||||
|
||||
/* Get/set the process' ability to use the timestamp counter instruction */
|
||||
#ifndef PR_GET_TSC
|
||||
#define PR_GET_TSC 25
|
||||
#define PR_SET_TSC 26
|
||||
# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
|
||||
# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */
|
||||
#endif
|
||||
|
||||
/* snippet from wikipedia :-) */
|
||||
|
||||
static uint64_t rdtsc(void)
|
||||
{
|
||||
uint32_t lo, hi;
|
||||
/* We cannot use "=A", since this would use %rax on x86_64 */
|
||||
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
||||
return (uint64_t)hi << 32 | lo;
|
||||
}
|
||||
|
||||
int should_segv = 0;
|
||||
|
||||
static void sigsegv_cb(int sig)
|
||||
{
|
||||
if (!should_segv)
|
||||
{
|
||||
fprintf(stderr, "FATAL ERROR, rdtsc() failed while enabled\n");
|
||||
exit(0);
|
||||
}
|
||||
if (prctl(PR_SET_TSC, PR_TSC_ENABLE) < 0)
|
||||
{
|
||||
perror("prctl");
|
||||
exit(0);
|
||||
}
|
||||
should_segv = 0;
|
||||
|
||||
rdtsc();
|
||||
}
|
||||
|
||||
static void task(void)
|
||||
{
|
||||
signal(SIGSEGV, sigsegv_cb);
|
||||
alarm(10);
|
||||
for(;;)
|
||||
{
|
||||
rdtsc();
|
||||
if (should_segv)
|
||||
{
|
||||
fprintf(stderr, "FATAL ERROR, rdtsc() succeeded while disabled\n");
|
||||
exit(0);
|
||||
}
|
||||
if (prctl(PR_SET_TSC, PR_TSC_SIGSEGV) < 0)
|
||||
{
|
||||
perror("prctl");
|
||||
exit(0);
|
||||
}
|
||||
should_segv = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int n_tasks = 100, i;
|
||||
|
||||
fprintf(stderr, "[No further output means we're allright]\n");
|
||||
|
||||
for (i=0; i<n_tasks; i++)
|
||||
if (fork() == 0)
|
||||
task();
|
||||
|
||||
for (i=0; i<n_tasks; i++)
|
||||
wait(NULL);
|
||||
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
/*
|
||||
* Tests for prctl(PR_GET_TSC, ...) / prctl(PR_SET_TSC, ...)
|
||||
*
|
||||
* Basic test to test behaviour of PR_GET_TSC and PR_SET_TSC
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
#include <sys/prctl.h>
|
||||
#include <linux/prctl.h>
|
||||
|
||||
/* Get/set the process' ability to use the timestamp counter instruction */
|
||||
#ifndef PR_GET_TSC
|
||||
#define PR_GET_TSC 25
|
||||
#define PR_SET_TSC 26
|
||||
# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */
|
||||
# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */
|
||||
#endif
|
||||
|
||||
const char *tsc_names[] =
|
||||
{
|
||||
[0] = "[not set]",
|
||||
[PR_TSC_ENABLE] = "PR_TSC_ENABLE",
|
||||
[PR_TSC_SIGSEGV] = "PR_TSC_SIGSEGV",
|
||||
};
|
||||
|
||||
static uint64_t rdtsc(void)
|
||||
{
|
||||
uint32_t lo, hi;
|
||||
/* We cannot use "=A", since this would use %rax on x86_64 */
|
||||
__asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi));
|
||||
return (uint64_t)hi << 32 | lo;
|
||||
}
|
||||
|
||||
static void sigsegv_cb(int sig)
|
||||
{
|
||||
int tsc_val = 0;
|
||||
|
||||
printf("[ SIG_SEGV ]\n");
|
||||
printf("prctl(PR_GET_TSC, &tsc_val); ");
|
||||
fflush(stdout);
|
||||
|
||||
if ( prctl(PR_GET_TSC, &tsc_val) == -1)
|
||||
perror("prctl");
|
||||
|
||||
printf("tsc_val == %s\n", tsc_names[tsc_val]);
|
||||
printf("prctl(PR_SET_TSC, PR_TSC_ENABLE)\n");
|
||||
fflush(stdout);
|
||||
if ( prctl(PR_SET_TSC, PR_TSC_ENABLE) == -1)
|
||||
perror("prctl");
|
||||
|
||||
printf("rdtsc() == ");
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int tsc_val = 0;
|
||||
|
||||
signal(SIGSEGV, sigsegv_cb);
|
||||
|
||||
printf("rdtsc() == %llu\n", (unsigned long long)rdtsc());
|
||||
printf("prctl(PR_GET_TSC, &tsc_val); ");
|
||||
fflush(stdout);
|
||||
|
||||
if ( prctl(PR_GET_TSC, &tsc_val) == -1)
|
||||
perror("prctl");
|
||||
|
||||
printf("tsc_val == %s\n", tsc_names[tsc_val]);
|
||||
printf("rdtsc() == %llu\n", (unsigned long long)rdtsc());
|
||||
printf("prctl(PR_SET_TSC, PR_TSC_ENABLE)\n");
|
||||
fflush(stdout);
|
||||
|
||||
if ( prctl(PR_SET_TSC, PR_TSC_ENABLE) == -1)
|
||||
perror("prctl");
|
||||
|
||||
printf("rdtsc() == %llu\n", (unsigned long long)rdtsc());
|
||||
printf("prctl(PR_SET_TSC, PR_TSC_SIGSEGV)\n");
|
||||
fflush(stdout);
|
||||
|
||||
if ( prctl(PR_SET_TSC, PR_TSC_SIGSEGV) == -1)
|
||||
perror("prctl");
|
||||
|
||||
printf("rdtsc() == ");
|
||||
fflush(stdout);
|
||||
printf("%llu\n", (unsigned long long)rdtsc());
|
||||
fflush(stdout);
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
1
Documentation/ptp/.gitignore
vendored
1
Documentation/ptp/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
testptp
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-y := testptp
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
||||
HOSTCFLAGS_testptp.o += -I$(objtree)/usr/include
|
||||
HOSTLOADLIBES_testptp := -lrt
|
||||
|
|
@ -1,523 +0,0 @@
|
|||
/*
|
||||
* PTP 1588 clock support - User space test program
|
||||
*
|
||||
* Copyright (C) 2010 OMICRON electronics GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#define __SANE_USERSPACE_TYPES__ /* For PPC64, to get LL64 types */
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/timex.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/ptp_clock.h>
|
||||
|
||||
#define DEVICE "/dev/ptp0"
|
||||
|
||||
#ifndef ADJ_SETOFFSET
|
||||
#define ADJ_SETOFFSET 0x0100
|
||||
#endif
|
||||
|
||||
#ifndef CLOCK_INVALID
|
||||
#define CLOCK_INVALID -1
|
||||
#endif
|
||||
|
||||
/* clock_adjtime is not available in GLIBC < 2.14 */
|
||||
#if !__GLIBC_PREREQ(2, 14)
|
||||
#include <sys/syscall.h>
|
||||
static int clock_adjtime(clockid_t id, struct timex *tx)
|
||||
{
|
||||
return syscall(__NR_clock_adjtime, id, tx);
|
||||
}
|
||||
#endif
|
||||
|
||||
static clockid_t get_clockid(int fd)
|
||||
{
|
||||
#define CLOCKFD 3
|
||||
#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD)
|
||||
|
||||
return FD_TO_CLOCKID(fd);
|
||||
}
|
||||
|
||||
static void handle_alarm(int s)
|
||||
{
|
||||
printf("received signal %d\n", s);
|
||||
}
|
||||
|
||||
static int install_handler(int signum, void (*handler)(int))
|
||||
{
|
||||
struct sigaction action;
|
||||
sigset_t mask;
|
||||
|
||||
/* Unblock the signal. */
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signum);
|
||||
sigprocmask(SIG_UNBLOCK, &mask, NULL);
|
||||
|
||||
/* Install the signal handler. */
|
||||
action.sa_handler = handler;
|
||||
action.sa_flags = 0;
|
||||
sigemptyset(&action.sa_mask);
|
||||
sigaction(signum, &action, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long ppb_to_scaled_ppm(int ppb)
|
||||
{
|
||||
/*
|
||||
* The 'freq' field in the 'struct timex' is in parts per
|
||||
* million, but with a 16 bit binary fractional field.
|
||||
* Instead of calculating either one of
|
||||
*
|
||||
* scaled_ppm = (ppb / 1000) << 16 [1]
|
||||
* scaled_ppm = (ppb << 16) / 1000 [2]
|
||||
*
|
||||
* we simply use double precision math, in order to avoid the
|
||||
* truncation in [1] and the possible overflow in [2].
|
||||
*/
|
||||
return (long) (ppb * 65.536);
|
||||
}
|
||||
|
||||
static int64_t pctns(struct ptp_clock_time *t)
|
||||
{
|
||||
return t->sec * 1000000000LL + t->nsec;
|
||||
}
|
||||
|
||||
static void usage(char *progname)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"usage: %s [options]\n"
|
||||
" -a val request a one-shot alarm after 'val' seconds\n"
|
||||
" -A val request a periodic alarm every 'val' seconds\n"
|
||||
" -c query the ptp clock's capabilities\n"
|
||||
" -d name device to open\n"
|
||||
" -e val read 'val' external time stamp events\n"
|
||||
" -f val adjust the ptp clock frequency by 'val' ppb\n"
|
||||
" -g get the ptp clock time\n"
|
||||
" -h prints this message\n"
|
||||
" -i val index for event/trigger\n"
|
||||
" -k val measure the time offset between system and phc clock\n"
|
||||
" for 'val' times (Maximum 25)\n"
|
||||
" -l list the current pin configuration\n"
|
||||
" -L pin,val configure pin index 'pin' with function 'val'\n"
|
||||
" the channel index is taken from the '-i' option\n"
|
||||
" 'val' specifies the auxiliary function:\n"
|
||||
" 0 - none\n"
|
||||
" 1 - external time stamp\n"
|
||||
" 2 - periodic output\n"
|
||||
" -p val enable output with a period of 'val' nanoseconds\n"
|
||||
" -P val enable or disable (val=1|0) the system clock PPS\n"
|
||||
" -s set the ptp clock time from the system time\n"
|
||||
" -S set the system time from the ptp clock time\n"
|
||||
" -t val shift the ptp clock time by 'val' seconds\n"
|
||||
" -T val set the ptp clock time to 'val' seconds\n",
|
||||
progname);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct ptp_clock_caps caps;
|
||||
struct ptp_extts_event event;
|
||||
struct ptp_extts_request extts_request;
|
||||
struct ptp_perout_request perout_request;
|
||||
struct ptp_pin_desc desc;
|
||||
struct timespec ts;
|
||||
struct timex tx;
|
||||
|
||||
static timer_t timerid;
|
||||
struct itimerspec timeout;
|
||||
struct sigevent sigevent;
|
||||
|
||||
struct ptp_clock_time *pct;
|
||||
struct ptp_sys_offset *sysoff;
|
||||
|
||||
|
||||
char *progname;
|
||||
unsigned int i;
|
||||
int c, cnt, fd;
|
||||
|
||||
char *device = DEVICE;
|
||||
clockid_t clkid;
|
||||
int adjfreq = 0x7fffffff;
|
||||
int adjtime = 0;
|
||||
int capabilities = 0;
|
||||
int extts = 0;
|
||||
int gettime = 0;
|
||||
int index = 0;
|
||||
int list_pins = 0;
|
||||
int oneshot = 0;
|
||||
int pct_offset = 0;
|
||||
int n_samples = 0;
|
||||
int periodic = 0;
|
||||
int perout = -1;
|
||||
int pin_index = -1, pin_func;
|
||||
int pps = -1;
|
||||
int seconds = 0;
|
||||
int settime = 0;
|
||||
|
||||
int64_t t1, t2, tp;
|
||||
int64_t interval, offset;
|
||||
|
||||
progname = strrchr(argv[0], '/');
|
||||
progname = progname ? 1+progname : argv[0];
|
||||
while (EOF != (c = getopt(argc, argv, "a:A:cd:e:f:ghi:k:lL:p:P:sSt:T:v"))) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
oneshot = atoi(optarg);
|
||||
break;
|
||||
case 'A':
|
||||
periodic = atoi(optarg);
|
||||
break;
|
||||
case 'c':
|
||||
capabilities = 1;
|
||||
break;
|
||||
case 'd':
|
||||
device = optarg;
|
||||
break;
|
||||
case 'e':
|
||||
extts = atoi(optarg);
|
||||
break;
|
||||
case 'f':
|
||||
adjfreq = atoi(optarg);
|
||||
break;
|
||||
case 'g':
|
||||
gettime = 1;
|
||||
break;
|
||||
case 'i':
|
||||
index = atoi(optarg);
|
||||
break;
|
||||
case 'k':
|
||||
pct_offset = 1;
|
||||
n_samples = atoi(optarg);
|
||||
break;
|
||||
case 'l':
|
||||
list_pins = 1;
|
||||
break;
|
||||
case 'L':
|
||||
cnt = sscanf(optarg, "%d,%d", &pin_index, &pin_func);
|
||||
if (cnt != 2) {
|
||||
usage(progname);
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
perout = atoi(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
pps = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
settime = 1;
|
||||
break;
|
||||
case 'S':
|
||||
settime = 2;
|
||||
break;
|
||||
case 't':
|
||||
adjtime = atoi(optarg);
|
||||
break;
|
||||
case 'T':
|
||||
settime = 3;
|
||||
seconds = atoi(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
usage(progname);
|
||||
return 0;
|
||||
case '?':
|
||||
default:
|
||||
usage(progname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fd = open(device, O_RDWR);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "opening %s: %s\n", device, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
clkid = get_clockid(fd);
|
||||
if (CLOCK_INVALID == clkid) {
|
||||
fprintf(stderr, "failed to read clock id\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (capabilities) {
|
||||
if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
|
||||
perror("PTP_CLOCK_GETCAPS");
|
||||
} else {
|
||||
printf("capabilities:\n"
|
||||
" %d maximum frequency adjustment (ppb)\n"
|
||||
" %d programmable alarms\n"
|
||||
" %d external time stamp channels\n"
|
||||
" %d programmable periodic signals\n"
|
||||
" %d pulse per second\n"
|
||||
" %d programmable pins\n"
|
||||
" %d cross timestamping\n",
|
||||
caps.max_adj,
|
||||
caps.n_alarm,
|
||||
caps.n_ext_ts,
|
||||
caps.n_per_out,
|
||||
caps.pps,
|
||||
caps.n_pins,
|
||||
caps.cross_timestamping);
|
||||
}
|
||||
}
|
||||
|
||||
if (0x7fffffff != adjfreq) {
|
||||
memset(&tx, 0, sizeof(tx));
|
||||
tx.modes = ADJ_FREQUENCY;
|
||||
tx.freq = ppb_to_scaled_ppm(adjfreq);
|
||||
if (clock_adjtime(clkid, &tx)) {
|
||||
perror("clock_adjtime");
|
||||
} else {
|
||||
puts("frequency adjustment okay");
|
||||
}
|
||||
}
|
||||
|
||||
if (adjtime) {
|
||||
memset(&tx, 0, sizeof(tx));
|
||||
tx.modes = ADJ_SETOFFSET;
|
||||
tx.time.tv_sec = adjtime;
|
||||
tx.time.tv_usec = 0;
|
||||
if (clock_adjtime(clkid, &tx) < 0) {
|
||||
perror("clock_adjtime");
|
||||
} else {
|
||||
puts("time shift okay");
|
||||
}
|
||||
}
|
||||
|
||||
if (gettime) {
|
||||
if (clock_gettime(clkid, &ts)) {
|
||||
perror("clock_gettime");
|
||||
} else {
|
||||
printf("clock time: %ld.%09ld or %s",
|
||||
ts.tv_sec, ts.tv_nsec, ctime(&ts.tv_sec));
|
||||
}
|
||||
}
|
||||
|
||||
if (settime == 1) {
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
if (clock_settime(clkid, &ts)) {
|
||||
perror("clock_settime");
|
||||
} else {
|
||||
puts("set time okay");
|
||||
}
|
||||
}
|
||||
|
||||
if (settime == 2) {
|
||||
clock_gettime(clkid, &ts);
|
||||
if (clock_settime(CLOCK_REALTIME, &ts)) {
|
||||
perror("clock_settime");
|
||||
} else {
|
||||
puts("set time okay");
|
||||
}
|
||||
}
|
||||
|
||||
if (settime == 3) {
|
||||
ts.tv_sec = seconds;
|
||||
ts.tv_nsec = 0;
|
||||
if (clock_settime(clkid, &ts)) {
|
||||
perror("clock_settime");
|
||||
} else {
|
||||
puts("set time okay");
|
||||
}
|
||||
}
|
||||
|
||||
if (extts) {
|
||||
memset(&extts_request, 0, sizeof(extts_request));
|
||||
extts_request.index = index;
|
||||
extts_request.flags = PTP_ENABLE_FEATURE;
|
||||
if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
|
||||
perror("PTP_EXTTS_REQUEST");
|
||||
extts = 0;
|
||||
} else {
|
||||
puts("external time stamp request okay");
|
||||
}
|
||||
for (; extts; extts--) {
|
||||
cnt = read(fd, &event, sizeof(event));
|
||||
if (cnt != sizeof(event)) {
|
||||
perror("read");
|
||||
break;
|
||||
}
|
||||
printf("event index %u at %lld.%09u\n", event.index,
|
||||
event.t.sec, event.t.nsec);
|
||||
fflush(stdout);
|
||||
}
|
||||
/* Disable the feature again. */
|
||||
extts_request.flags = 0;
|
||||
if (ioctl(fd, PTP_EXTTS_REQUEST, &extts_request)) {
|
||||
perror("PTP_EXTTS_REQUEST");
|
||||
}
|
||||
}
|
||||
|
||||
if (list_pins) {
|
||||
int n_pins = 0;
|
||||
if (ioctl(fd, PTP_CLOCK_GETCAPS, &caps)) {
|
||||
perror("PTP_CLOCK_GETCAPS");
|
||||
} else {
|
||||
n_pins = caps.n_pins;
|
||||
}
|
||||
for (i = 0; i < n_pins; i++) {
|
||||
desc.index = i;
|
||||
if (ioctl(fd, PTP_PIN_GETFUNC, &desc)) {
|
||||
perror("PTP_PIN_GETFUNC");
|
||||
break;
|
||||
}
|
||||
printf("name %s index %u func %u chan %u\n",
|
||||
desc.name, desc.index, desc.func, desc.chan);
|
||||
}
|
||||
}
|
||||
|
||||
if (oneshot) {
|
||||
install_handler(SIGALRM, handle_alarm);
|
||||
/* Create a timer. */
|
||||
sigevent.sigev_notify = SIGEV_SIGNAL;
|
||||
sigevent.sigev_signo = SIGALRM;
|
||||
if (timer_create(clkid, &sigevent, &timerid)) {
|
||||
perror("timer_create");
|
||||
return -1;
|
||||
}
|
||||
/* Start the timer. */
|
||||
memset(&timeout, 0, sizeof(timeout));
|
||||
timeout.it_value.tv_sec = oneshot;
|
||||
if (timer_settime(timerid, 0, &timeout, NULL)) {
|
||||
perror("timer_settime");
|
||||
return -1;
|
||||
}
|
||||
pause();
|
||||
timer_delete(timerid);
|
||||
}
|
||||
|
||||
if (periodic) {
|
||||
install_handler(SIGALRM, handle_alarm);
|
||||
/* Create a timer. */
|
||||
sigevent.sigev_notify = SIGEV_SIGNAL;
|
||||
sigevent.sigev_signo = SIGALRM;
|
||||
if (timer_create(clkid, &sigevent, &timerid)) {
|
||||
perror("timer_create");
|
||||
return -1;
|
||||
}
|
||||
/* Start the timer. */
|
||||
memset(&timeout, 0, sizeof(timeout));
|
||||
timeout.it_interval.tv_sec = periodic;
|
||||
timeout.it_value.tv_sec = periodic;
|
||||
if (timer_settime(timerid, 0, &timeout, NULL)) {
|
||||
perror("timer_settime");
|
||||
return -1;
|
||||
}
|
||||
while (1) {
|
||||
pause();
|
||||
}
|
||||
timer_delete(timerid);
|
||||
}
|
||||
|
||||
if (perout >= 0) {
|
||||
if (clock_gettime(clkid, &ts)) {
|
||||
perror("clock_gettime");
|
||||
return -1;
|
||||
}
|
||||
memset(&perout_request, 0, sizeof(perout_request));
|
||||
perout_request.index = index;
|
||||
perout_request.start.sec = ts.tv_sec + 2;
|
||||
perout_request.start.nsec = 0;
|
||||
perout_request.period.sec = 0;
|
||||
perout_request.period.nsec = perout;
|
||||
if (ioctl(fd, PTP_PEROUT_REQUEST, &perout_request)) {
|
||||
perror("PTP_PEROUT_REQUEST");
|
||||
} else {
|
||||
puts("periodic output request okay");
|
||||
}
|
||||
}
|
||||
|
||||
if (pin_index >= 0) {
|
||||
memset(&desc, 0, sizeof(desc));
|
||||
desc.index = pin_index;
|
||||
desc.func = pin_func;
|
||||
desc.chan = index;
|
||||
if (ioctl(fd, PTP_PIN_SETFUNC, &desc)) {
|
||||
perror("PTP_PIN_SETFUNC");
|
||||
} else {
|
||||
puts("set pin function okay");
|
||||
}
|
||||
}
|
||||
|
||||
if (pps != -1) {
|
||||
int enable = pps ? 1 : 0;
|
||||
if (ioctl(fd, PTP_ENABLE_PPS, enable)) {
|
||||
perror("PTP_ENABLE_PPS");
|
||||
} else {
|
||||
puts("pps for system time request okay");
|
||||
}
|
||||
}
|
||||
|
||||
if (pct_offset) {
|
||||
if (n_samples <= 0 || n_samples > 25) {
|
||||
puts("n_samples should be between 1 and 25");
|
||||
usage(progname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sysoff = calloc(1, sizeof(*sysoff));
|
||||
if (!sysoff) {
|
||||
perror("calloc");
|
||||
return -1;
|
||||
}
|
||||
sysoff->n_samples = n_samples;
|
||||
|
||||
if (ioctl(fd, PTP_SYS_OFFSET, sysoff))
|
||||
perror("PTP_SYS_OFFSET");
|
||||
else
|
||||
puts("system and phc clock time offset request okay");
|
||||
|
||||
pct = &sysoff->ts[0];
|
||||
for (i = 0; i < sysoff->n_samples; i++) {
|
||||
t1 = pctns(pct+2*i);
|
||||
tp = pctns(pct+2*i+1);
|
||||
t2 = pctns(pct+2*i+2);
|
||||
interval = t2 - t1;
|
||||
offset = (t2 + t1) / 2 - tp;
|
||||
|
||||
printf("system time: %lld.%u\n",
|
||||
(pct+2*i)->sec, (pct+2*i)->nsec);
|
||||
printf("phc time: %lld.%u\n",
|
||||
(pct+2*i+1)->sec, (pct+2*i+1)->nsec);
|
||||
printf("system time: %lld.%u\n",
|
||||
(pct+2*i+2)->sec, (pct+2*i+2)->nsec);
|
||||
printf("system/phc clock time offset is %" PRId64 " ns\n"
|
||||
"system clock time delay is %" PRId64 " ns\n",
|
||||
offset, interval);
|
||||
}
|
||||
|
||||
free(sysoff);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
# PTP 1588 clock support - User space test program
|
||||
#
|
||||
# Copyright (C) 2010 OMICRON electronics GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
CC = $(CROSS_COMPILE)gcc
|
||||
INC = -I$(KBUILD_OUTPUT)/usr/include
|
||||
CFLAGS = -Wall $(INC)
|
||||
LDLIBS = -lrt
|
||||
PROGS = testptp
|
||||
|
||||
all: $(PROGS)
|
||||
|
||||
testptp: testptp.o
|
||||
|
||||
clean:
|
||||
rm -f testptp.o
|
||||
|
||||
distclean: clean
|
||||
rm -f $(PROGS)
|
||||
|
|
@ -1,7 +1,5 @@
|
|||
00-INDEX
|
||||
- this file.
|
||||
Makefile
|
||||
- Makefile for the example sourcefiles.
|
||||
butterfly
|
||||
- AVR Butterfly SPI driver overview and pin configuration.
|
||||
ep93xx_spi
|
||||
|
|
|
|||
1
Documentation/timers/.gitignore
vendored
1
Documentation/timers/.gitignore
vendored
|
|
@ -1 +0,0 @@
|
|||
hpet_example
|
||||
|
|
@ -4,12 +4,8 @@ highres.txt
|
|||
- High resolution timers and dynamic ticks design notes
|
||||
hpet.txt
|
||||
- High Precision Event Timer Driver for Linux
|
||||
hpet_example.c
|
||||
- sample hpet timer test program
|
||||
hrtimers.txt
|
||||
- subsystem for high-resolution kernel timers
|
||||
Makefile
|
||||
- Build and link hpet_example
|
||||
NO_HZ.txt
|
||||
- Summary of the different methods for the scheduler clock-interrupts management.
|
||||
timekeeping.txt
|
||||
|
|
|
|||
|
|
@ -1,5 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-$(CONFIG_X86) := hpet_example
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
|
@ -25,4 +25,4 @@ arch/x86/kernel/hpet.c.
|
|||
|
||||
The driver provides a userspace API which resembles the API found in the
|
||||
RTC driver framework. An example user space program is provided in
|
||||
file:Documentation/timers/hpet_example.c
|
||||
file:samples/timers/hpet_example.c
|
||||
|
|
|
|||
|
|
@ -1,294 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <memory.h>
|
||||
#include <malloc.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <linux/hpet.h>
|
||||
|
||||
|
||||
extern void hpet_open_close(int, const char **);
|
||||
extern void hpet_info(int, const char **);
|
||||
extern void hpet_poll(int, const char **);
|
||||
extern void hpet_fasync(int, const char **);
|
||||
extern void hpet_read(int, const char **);
|
||||
|
||||
#include <sys/poll.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
struct hpet_command {
|
||||
char *command;
|
||||
void (*func)(int argc, const char ** argv);
|
||||
} hpet_command[] = {
|
||||
{
|
||||
"open-close",
|
||||
hpet_open_close
|
||||
},
|
||||
{
|
||||
"info",
|
||||
hpet_info
|
||||
},
|
||||
{
|
||||
"poll",
|
||||
hpet_poll
|
||||
},
|
||||
{
|
||||
"fasync",
|
||||
hpet_fasync
|
||||
},
|
||||
};
|
||||
|
||||
int
|
||||
main(int argc, const char ** argv)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
if (!argc) {
|
||||
fprintf(stderr, "-hpet: requires command\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
for (i = 0; i < (sizeof (hpet_command) / sizeof (hpet_command[0])); i++)
|
||||
if (!strcmp(argv[0], hpet_command[i].command)) {
|
||||
argc--;
|
||||
argv++;
|
||||
fprintf(stderr, "-hpet: executing %s\n",
|
||||
hpet_command[i].command);
|
||||
hpet_command[i].func(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(stderr, "do_hpet: command %s not implemented\n", argv[0]);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
hpet_open_close(int argc, const char **argv)
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (argc != 1) {
|
||||
fprintf(stderr, "hpet_open_close: device-name\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open(argv[0], O_RDONLY);
|
||||
if (fd < 0)
|
||||
fprintf(stderr, "hpet_open_close: open failed\n");
|
||||
else
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
hpet_info(int argc, const char **argv)
|
||||
{
|
||||
struct hpet_info info;
|
||||
int fd;
|
||||
|
||||
if (argc != 1) {
|
||||
fprintf(stderr, "hpet_info: device-name\n");
|
||||
return;
|
||||
}
|
||||
|
||||
fd = open(argv[0], O_RDONLY);
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "hpet_info: open of %s failed\n", argv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ioctl(fd, HPET_INFO, &info) < 0) {
|
||||
fprintf(stderr, "hpet_info: failed to get info\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
fprintf(stderr, "hpet_info: hi_irqfreq 0x%lx hi_flags 0x%lx ",
|
||||
info.hi_ireqfreq, info.hi_flags);
|
||||
fprintf(stderr, "hi_hpet %d hi_timer %d\n",
|
||||
info.hi_hpet, info.hi_timer);
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
hpet_poll(int argc, const char **argv)
|
||||
{
|
||||
unsigned long freq;
|
||||
int iterations, i, fd;
|
||||
struct pollfd pfd;
|
||||
struct hpet_info info;
|
||||
struct timeval stv, etv;
|
||||
struct timezone tz;
|
||||
long usec;
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "hpet_poll: device-name freq iterations\n");
|
||||
return;
|
||||
}
|
||||
|
||||
freq = atoi(argv[1]);
|
||||
iterations = atoi(argv[2]);
|
||||
|
||||
fd = open(argv[0], O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "hpet_poll: open of %s failed\n", argv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
|
||||
fprintf(stderr, "hpet_poll: HPET_IRQFREQ failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ioctl(fd, HPET_INFO, &info) < 0) {
|
||||
fprintf(stderr, "hpet_poll: failed to get info\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
fprintf(stderr, "hpet_poll: info.hi_flags 0x%lx\n", info.hi_flags);
|
||||
|
||||
if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
|
||||
fprintf(stderr, "hpet_poll: HPET_EPI failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ioctl(fd, HPET_IE_ON, 0) < 0) {
|
||||
fprintf(stderr, "hpet_poll, HPET_IE_ON failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
pfd.fd = fd;
|
||||
pfd.events = POLLIN;
|
||||
|
||||
for (i = 0; i < iterations; i++) {
|
||||
pfd.revents = 0;
|
||||
gettimeofday(&stv, &tz);
|
||||
if (poll(&pfd, 1, -1) < 0)
|
||||
fprintf(stderr, "hpet_poll: poll failed\n");
|
||||
else {
|
||||
long data;
|
||||
|
||||
gettimeofday(&etv, &tz);
|
||||
usec = stv.tv_sec * 1000000 + stv.tv_usec;
|
||||
usec = (etv.tv_sec * 1000000 + etv.tv_usec) - usec;
|
||||
|
||||
fprintf(stderr,
|
||||
"hpet_poll: expired time = 0x%lx\n", usec);
|
||||
|
||||
fprintf(stderr, "hpet_poll: revents = 0x%x\n",
|
||||
pfd.revents);
|
||||
|
||||
if (read(fd, &data, sizeof(data)) != sizeof(data)) {
|
||||
fprintf(stderr, "hpet_poll: read failed\n");
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "hpet_poll: data 0x%lx\n",
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
static int hpet_sigio_count;
|
||||
|
||||
static void
|
||||
hpet_sigio(int val)
|
||||
{
|
||||
fprintf(stderr, "hpet_sigio: called\n");
|
||||
hpet_sigio_count++;
|
||||
}
|
||||
|
||||
void
|
||||
hpet_fasync(int argc, const char **argv)
|
||||
{
|
||||
unsigned long freq;
|
||||
int iterations, i, fd, value;
|
||||
sig_t oldsig;
|
||||
struct hpet_info info;
|
||||
|
||||
hpet_sigio_count = 0;
|
||||
fd = -1;
|
||||
|
||||
if ((oldsig = signal(SIGIO, hpet_sigio)) == SIG_ERR) {
|
||||
fprintf(stderr, "hpet_fasync: failed to set signal handler\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (argc != 3) {
|
||||
fprintf(stderr, "hpet_fasync: device-name freq iterations\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
fd = open(argv[0], O_RDONLY);
|
||||
|
||||
if (fd < 0) {
|
||||
fprintf(stderr, "hpet_fasync: failed to open %s\n", argv[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if ((fcntl(fd, F_SETOWN, getpid()) == 1) ||
|
||||
((value = fcntl(fd, F_GETFL)) == 1) ||
|
||||
(fcntl(fd, F_SETFL, value | O_ASYNC) == 1)) {
|
||||
fprintf(stderr, "hpet_fasync: fcntl failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
freq = atoi(argv[1]);
|
||||
iterations = atoi(argv[2]);
|
||||
|
||||
if (ioctl(fd, HPET_IRQFREQ, freq) < 0) {
|
||||
fprintf(stderr, "hpet_fasync: HPET_IRQFREQ failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ioctl(fd, HPET_INFO, &info) < 0) {
|
||||
fprintf(stderr, "hpet_fasync: failed to get info\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
fprintf(stderr, "hpet_fasync: info.hi_flags 0x%lx\n", info.hi_flags);
|
||||
|
||||
if (info.hi_flags && (ioctl(fd, HPET_EPI, 0) < 0)) {
|
||||
fprintf(stderr, "hpet_fasync: HPET_EPI failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ioctl(fd, HPET_IE_ON, 0) < 0) {
|
||||
fprintf(stderr, "hpet_fasync, HPET_IE_ON failed\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < iterations; i++) {
|
||||
(void) pause();
|
||||
fprintf(stderr, "hpet_fasync: count = %d\n", hpet_sigio_count);
|
||||
}
|
||||
|
||||
out:
|
||||
signal(SIGIO, oldsig);
|
||||
|
||||
if (fd >= 0)
|
||||
close(fd);
|
||||
|
||||
return;
|
||||
}
|
||||
2
Documentation/vDSO/.gitignore
vendored
2
Documentation/vDSO/.gitignore
vendored
|
|
@ -1,2 +0,0 @@
|
|||
vdso_test
|
||||
vdso_standalone_test_x86
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
ifndef CROSS_COMPILE
|
||||
# vdso_test won't build for glibc < 2.16, so disable it
|
||||
# hostprogs-y := vdso_test
|
||||
hostprogs-$(CONFIG_X86) := vdso_standalone_test_x86
|
||||
vdso_standalone_test_x86-objs := vdso_standalone_test_x86.o parse_vdso.o
|
||||
vdso_test-objs := parse_vdso.o vdso_test.o
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
||||
HOSTCFLAGS := -I$(objtree)/usr/include -std=gnu99
|
||||
HOSTCFLAGS_vdso_standalone_test_x86.o := -fno-asynchronous-unwind-tables -fno-stack-protector
|
||||
HOSTLOADLIBES_vdso_standalone_test_x86 := -nostdlib
|
||||
ifeq ($(CONFIG_X86_32),y)
|
||||
HOSTLOADLIBES_vdso_standalone_test_x86 += -lgcc_s
|
||||
endif
|
||||
endif
|
||||
|
|
@ -1,269 +0,0 @@
|
|||
/*
|
||||
* parse_vdso.c: Linux reference vDSO parser
|
||||
* Written by Andrew Lutomirski, 2011-2014.
|
||||
*
|
||||
* This code is meant to be linked in to various programs that run on Linux.
|
||||
* As such, it is available with as few restrictions as possible. This file
|
||||
* is licensed under the Creative Commons Zero License, version 1.0,
|
||||
* available at http://creativecommons.org/publicdomain/zero/1.0/legalcode
|
||||
*
|
||||
* The vDSO is a regular ELF DSO that the kernel maps into user space when
|
||||
* it starts a program. It works equally well in statically and dynamically
|
||||
* linked binaries.
|
||||
*
|
||||
* This code is tested on x86. In principle it should work on any
|
||||
* architecture that has a vDSO.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <elf.h>
|
||||
|
||||
/*
|
||||
* To use this vDSO parser, first call one of the vdso_init_* functions.
|
||||
* If you've already parsed auxv, then pass the value of AT_SYSINFO_EHDR
|
||||
* to vdso_init_from_sysinfo_ehdr. Otherwise pass auxv to vdso_init_from_auxv.
|
||||
* Then call vdso_sym for each symbol you want. For example, to look up
|
||||
* gettimeofday on x86_64, use:
|
||||
*
|
||||
* <some pointer> = vdso_sym("LINUX_2.6", "gettimeofday");
|
||||
* or
|
||||
* <some pointer> = vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
|
||||
*
|
||||
* vdso_sym will return 0 if the symbol doesn't exist or if the init function
|
||||
* failed or was not called. vdso_sym is a little slow, so its return value
|
||||
* should be cached.
|
||||
*
|
||||
* vdso_sym is threadsafe; the init functions are not.
|
||||
*
|
||||
* These are the prototypes:
|
||||
*/
|
||||
extern void vdso_init_from_auxv(void *auxv);
|
||||
extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
|
||||
extern void *vdso_sym(const char *version, const char *name);
|
||||
|
||||
|
||||
/* And here's the code. */
|
||||
#ifndef ELF_BITS
|
||||
# if ULONG_MAX > 0xffffffffUL
|
||||
# define ELF_BITS 64
|
||||
# else
|
||||
# define ELF_BITS 32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define ELF_BITS_XFORM2(bits, x) Elf##bits##_##x
|
||||
#define ELF_BITS_XFORM(bits, x) ELF_BITS_XFORM2(bits, x)
|
||||
#define ELF(x) ELF_BITS_XFORM(ELF_BITS, x)
|
||||
|
||||
static struct vdso_info
|
||||
{
|
||||
bool valid;
|
||||
|
||||
/* Load information */
|
||||
uintptr_t load_addr;
|
||||
uintptr_t load_offset; /* load_addr - recorded vaddr */
|
||||
|
||||
/* Symbol table */
|
||||
ELF(Sym) *symtab;
|
||||
const char *symstrings;
|
||||
ELF(Word) *bucket, *chain;
|
||||
ELF(Word) nbucket, nchain;
|
||||
|
||||
/* Version table */
|
||||
ELF(Versym) *versym;
|
||||
ELF(Verdef) *verdef;
|
||||
} vdso_info;
|
||||
|
||||
/* Straight from the ELF specification. */
|
||||
static unsigned long elf_hash(const unsigned char *name)
|
||||
{
|
||||
unsigned long h = 0, g;
|
||||
while (*name)
|
||||
{
|
||||
h = (h << 4) + *name++;
|
||||
if (g = h & 0xf0000000)
|
||||
h ^= g >> 24;
|
||||
h &= ~g;
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
void vdso_init_from_sysinfo_ehdr(uintptr_t base)
|
||||
{
|
||||
size_t i;
|
||||
bool found_vaddr = false;
|
||||
|
||||
vdso_info.valid = false;
|
||||
|
||||
vdso_info.load_addr = base;
|
||||
|
||||
ELF(Ehdr) *hdr = (ELF(Ehdr)*)base;
|
||||
if (hdr->e_ident[EI_CLASS] !=
|
||||
(ELF_BITS == 32 ? ELFCLASS32 : ELFCLASS64)) {
|
||||
return; /* Wrong ELF class -- check ELF_BITS */
|
||||
}
|
||||
|
||||
ELF(Phdr) *pt = (ELF(Phdr)*)(vdso_info.load_addr + hdr->e_phoff);
|
||||
ELF(Dyn) *dyn = 0;
|
||||
|
||||
/*
|
||||
* We need two things from the segment table: the load offset
|
||||
* and the dynamic table.
|
||||
*/
|
||||
for (i = 0; i < hdr->e_phnum; i++)
|
||||
{
|
||||
if (pt[i].p_type == PT_LOAD && !found_vaddr) {
|
||||
found_vaddr = true;
|
||||
vdso_info.load_offset = base
|
||||
+ (uintptr_t)pt[i].p_offset
|
||||
- (uintptr_t)pt[i].p_vaddr;
|
||||
} else if (pt[i].p_type == PT_DYNAMIC) {
|
||||
dyn = (ELF(Dyn)*)(base + pt[i].p_offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (!found_vaddr || !dyn)
|
||||
return; /* Failed */
|
||||
|
||||
/*
|
||||
* Fish out the useful bits of the dynamic table.
|
||||
*/
|
||||
ELF(Word) *hash = 0;
|
||||
vdso_info.symstrings = 0;
|
||||
vdso_info.symtab = 0;
|
||||
vdso_info.versym = 0;
|
||||
vdso_info.verdef = 0;
|
||||
for (i = 0; dyn[i].d_tag != DT_NULL; i++) {
|
||||
switch (dyn[i].d_tag) {
|
||||
case DT_STRTAB:
|
||||
vdso_info.symstrings = (const char *)
|
||||
((uintptr_t)dyn[i].d_un.d_ptr
|
||||
+ vdso_info.load_offset);
|
||||
break;
|
||||
case DT_SYMTAB:
|
||||
vdso_info.symtab = (ELF(Sym) *)
|
||||
((uintptr_t)dyn[i].d_un.d_ptr
|
||||
+ vdso_info.load_offset);
|
||||
break;
|
||||
case DT_HASH:
|
||||
hash = (ELF(Word) *)
|
||||
((uintptr_t)dyn[i].d_un.d_ptr
|
||||
+ vdso_info.load_offset);
|
||||
break;
|
||||
case DT_VERSYM:
|
||||
vdso_info.versym = (ELF(Versym) *)
|
||||
((uintptr_t)dyn[i].d_un.d_ptr
|
||||
+ vdso_info.load_offset);
|
||||
break;
|
||||
case DT_VERDEF:
|
||||
vdso_info.verdef = (ELF(Verdef) *)
|
||||
((uintptr_t)dyn[i].d_un.d_ptr
|
||||
+ vdso_info.load_offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!vdso_info.symstrings || !vdso_info.symtab || !hash)
|
||||
return; /* Failed */
|
||||
|
||||
if (!vdso_info.verdef)
|
||||
vdso_info.versym = 0;
|
||||
|
||||
/* Parse the hash table header. */
|
||||
vdso_info.nbucket = hash[0];
|
||||
vdso_info.nchain = hash[1];
|
||||
vdso_info.bucket = &hash[2];
|
||||
vdso_info.chain = &hash[vdso_info.nbucket + 2];
|
||||
|
||||
/* That's all we need. */
|
||||
vdso_info.valid = true;
|
||||
}
|
||||
|
||||
static bool vdso_match_version(ELF(Versym) ver,
|
||||
const char *name, ELF(Word) hash)
|
||||
{
|
||||
/*
|
||||
* This is a helper function to check if the version indexed by
|
||||
* ver matches name (which hashes to hash).
|
||||
*
|
||||
* The version definition table is a mess, and I don't know how
|
||||
* to do this in better than linear time without allocating memory
|
||||
* to build an index. I also don't know why the table has
|
||||
* variable size entries in the first place.
|
||||
*
|
||||
* For added fun, I can't find a comprehensible specification of how
|
||||
* to parse all the weird flags in the table.
|
||||
*
|
||||
* So I just parse the whole table every time.
|
||||
*/
|
||||
|
||||
/* First step: find the version definition */
|
||||
ver &= 0x7fff; /* Apparently bit 15 means "hidden" */
|
||||
ELF(Verdef) *def = vdso_info.verdef;
|
||||
while(true) {
|
||||
if ((def->vd_flags & VER_FLG_BASE) == 0
|
||||
&& (def->vd_ndx & 0x7fff) == ver)
|
||||
break;
|
||||
|
||||
if (def->vd_next == 0)
|
||||
return false; /* No definition. */
|
||||
|
||||
def = (ELF(Verdef) *)((char *)def + def->vd_next);
|
||||
}
|
||||
|
||||
/* Now figure out whether it matches. */
|
||||
ELF(Verdaux) *aux = (ELF(Verdaux)*)((char *)def + def->vd_aux);
|
||||
return def->vd_hash == hash
|
||||
&& !strcmp(name, vdso_info.symstrings + aux->vda_name);
|
||||
}
|
||||
|
||||
void *vdso_sym(const char *version, const char *name)
|
||||
{
|
||||
unsigned long ver_hash;
|
||||
if (!vdso_info.valid)
|
||||
return 0;
|
||||
|
||||
ver_hash = elf_hash(version);
|
||||
ELF(Word) chain = vdso_info.bucket[elf_hash(name) % vdso_info.nbucket];
|
||||
|
||||
for (; chain != STN_UNDEF; chain = vdso_info.chain[chain]) {
|
||||
ELF(Sym) *sym = &vdso_info.symtab[chain];
|
||||
|
||||
/* Check for a defined global or weak function w/ right name. */
|
||||
if (ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
|
||||
continue;
|
||||
if (ELF64_ST_BIND(sym->st_info) != STB_GLOBAL &&
|
||||
ELF64_ST_BIND(sym->st_info) != STB_WEAK)
|
||||
continue;
|
||||
if (sym->st_shndx == SHN_UNDEF)
|
||||
continue;
|
||||
if (strcmp(name, vdso_info.symstrings + sym->st_name))
|
||||
continue;
|
||||
|
||||
/* Check symbol version. */
|
||||
if (vdso_info.versym
|
||||
&& !vdso_match_version(vdso_info.versym[chain],
|
||||
version, ver_hash))
|
||||
continue;
|
||||
|
||||
return (void *)(vdso_info.load_offset + sym->st_value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void vdso_init_from_auxv(void *auxv)
|
||||
{
|
||||
ELF(auxv_t) *elf_auxv = auxv;
|
||||
for (int i = 0; elf_auxv[i].a_type != AT_NULL; i++)
|
||||
{
|
||||
if (elf_auxv[i].a_type == AT_SYSINFO_EHDR) {
|
||||
vdso_init_from_sysinfo_ehdr(elf_auxv[i].a_un.a_val);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vdso_info.valid = false;
|
||||
}
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
* vdso_test.c: Sample code to test parse_vdso.c on x86
|
||||
* Copyright (c) 2011-2014 Andy Lutomirski
|
||||
* Subject to the GNU General Public License, version 2
|
||||
*
|
||||
* You can amuse yourself by compiling with:
|
||||
* gcc -std=gnu99 -nostdlib
|
||||
* -Os -fno-asynchronous-unwind-tables -flto -lgcc_s
|
||||
* vdso_standalone_test_x86.c parse_vdso.c
|
||||
* to generate a small binary. On x86_64, you can omit -lgcc_s
|
||||
* if you want the binary to be completely standalone.
|
||||
*/
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
extern void *vdso_sym(const char *version, const char *name);
|
||||
extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
|
||||
extern void vdso_init_from_auxv(void *auxv);
|
||||
|
||||
/* We need a libc functions... */
|
||||
int strcmp(const char *a, const char *b)
|
||||
{
|
||||
/* This implementation is buggy: it never returns -1. */
|
||||
while (*a || *b) {
|
||||
if (*a != *b)
|
||||
return 1;
|
||||
if (*a == 0 || *b == 0)
|
||||
return 1;
|
||||
a++;
|
||||
b++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ...and two syscalls. This is x86-specific. */
|
||||
static inline long x86_syscall3(long nr, long a0, long a1, long a2)
|
||||
{
|
||||
long ret;
|
||||
#ifdef __x86_64__
|
||||
asm volatile ("syscall" : "=a" (ret) : "a" (nr),
|
||||
"D" (a0), "S" (a1), "d" (a2) :
|
||||
"cc", "memory", "rcx",
|
||||
"r8", "r9", "r10", "r11" );
|
||||
#else
|
||||
asm volatile ("int $0x80" : "=a" (ret) : "a" (nr),
|
||||
"b" (a0), "c" (a1), "d" (a2) :
|
||||
"cc", "memory" );
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long linux_write(int fd, const void *data, size_t len)
|
||||
{
|
||||
return x86_syscall3(__NR_write, fd, (long)data, (long)len);
|
||||
}
|
||||
|
||||
static inline void linux_exit(int code)
|
||||
{
|
||||
x86_syscall3(__NR_exit, code, 0, 0);
|
||||
}
|
||||
|
||||
void to_base10(char *lastdig, time_t n)
|
||||
{
|
||||
while (n) {
|
||||
*lastdig = (n % 10) + '0';
|
||||
n /= 10;
|
||||
lastdig--;
|
||||
}
|
||||
}
|
||||
|
||||
__attribute__((externally_visible)) void c_main(void **stack)
|
||||
{
|
||||
/* Parse the stack */
|
||||
long argc = (long)*stack;
|
||||
stack += argc + 2;
|
||||
|
||||
/* Now we're pointing at the environment. Skip it. */
|
||||
while(*stack)
|
||||
stack++;
|
||||
stack++;
|
||||
|
||||
/* Now we're pointing at auxv. Initialize the vDSO parser. */
|
||||
vdso_init_from_auxv((void *)stack);
|
||||
|
||||
/* Find gettimeofday. */
|
||||
typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz);
|
||||
gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
|
||||
|
||||
if (!gtod)
|
||||
linux_exit(1);
|
||||
|
||||
struct timeval tv;
|
||||
long ret = gtod(&tv, 0);
|
||||
|
||||
if (ret == 0) {
|
||||
char buf[] = "The time is .000000\n";
|
||||
to_base10(buf + 31, tv.tv_sec);
|
||||
to_base10(buf + 38, tv.tv_usec);
|
||||
linux_write(1, buf, sizeof(buf) - 1);
|
||||
} else {
|
||||
linux_exit(ret);
|
||||
}
|
||||
|
||||
linux_exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the real entry point. It passes the initial stack into
|
||||
* the C entry point.
|
||||
*/
|
||||
asm (
|
||||
".text\n"
|
||||
".global _start\n"
|
||||
".type _start,@function\n"
|
||||
"_start:\n\t"
|
||||
#ifdef __x86_64__
|
||||
"mov %rsp,%rdi\n\t"
|
||||
"jmp c_main"
|
||||
#else
|
||||
"push %esp\n\t"
|
||||
"call c_main\n\t"
|
||||
"int $3"
|
||||
#endif
|
||||
);
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* vdso_test.c: Sample code to test parse_vdso.c
|
||||
* Copyright (c) 2014 Andy Lutomirski
|
||||
* Subject to the GNU General Public License, version 2
|
||||
*
|
||||
* Compile with:
|
||||
* gcc -std=gnu99 vdso_test.c parse_vdso.c
|
||||
*
|
||||
* Tested on x86, 32-bit and 64-bit. It may work on other architectures, too.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <elf.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
extern void *vdso_sym(const char *version, const char *name);
|
||||
extern void vdso_init_from_sysinfo_ehdr(uintptr_t base);
|
||||
extern void vdso_init_from_auxv(void *auxv);
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
unsigned long sysinfo_ehdr = getauxval(AT_SYSINFO_EHDR);
|
||||
if (!sysinfo_ehdr) {
|
||||
printf("AT_SYSINFO_EHDR is not present!\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vdso_init_from_sysinfo_ehdr(getauxval(AT_SYSINFO_EHDR));
|
||||
|
||||
/* Find gettimeofday. */
|
||||
typedef long (*gtod_t)(struct timeval *tv, struct timezone *tz);
|
||||
gtod_t gtod = (gtod_t)vdso_sym("LINUX_2.6", "__vdso_gettimeofday");
|
||||
|
||||
if (!gtod) {
|
||||
printf("Could not find __vdso_gettimeofday\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct timeval tv;
|
||||
long ret = gtod(&tv, 0);
|
||||
|
||||
if (ret == 0) {
|
||||
printf("The time is %lld.%06lld\n",
|
||||
(long long)tv.tv_sec, (long long)tv.tv_usec);
|
||||
} else {
|
||||
printf("__vdso_gettimeofday failed\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
subdir-y := src
|
||||
2
Documentation/watchdog/src/.gitignore
vendored
2
Documentation/watchdog/src/.gitignore
vendored
|
|
@ -1,2 +0,0 @@
|
|||
watchdog-simple
|
||||
watchdog-test
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
# List of programs to build
|
||||
hostprogs-y := watchdog-simple watchdog-test
|
||||
|
||||
# Tell kbuild to always build the programs
|
||||
always := $(hostprogs-y)
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int fd = open("/dev/watchdog", O_WRONLY);
|
||||
int ret = 0;
|
||||
if (fd == -1) {
|
||||
perror("watchdog");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
while (1) {
|
||||
ret = write(fd, "\0", 1);
|
||||
if (ret != 1) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
sleep(10);
|
||||
}
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
/*
|
||||
* Watchdog Driver Test Program
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
int fd;
|
||||
const char v = 'V';
|
||||
|
||||
/*
|
||||
* This function simply sends an IOCTL to the driver, which in turn ticks
|
||||
* the PC Watchdog card to reset its internal timer so it doesn't trigger
|
||||
* a computer reset.
|
||||
*/
|
||||
static void keep_alive(void)
|
||||
{
|
||||
int dummy;
|
||||
|
||||
printf(".");
|
||||
ioctl(fd, WDIOC_KEEPALIVE, &dummy);
|
||||
}
|
||||
|
||||
/*
|
||||
* The main program. Run the program with "-d" to disable the card,
|
||||
* or "-e" to enable the card.
|
||||
*/
|
||||
|
||||
static void term(int sig)
|
||||
{
|
||||
int ret = write(fd, &v, 1);
|
||||
|
||||
close(fd);
|
||||
if (ret < 0)
|
||||
printf("\nStopping watchdog ticks failed (%d)...\n", errno);
|
||||
else
|
||||
printf("\nStopping watchdog ticks...\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int flags;
|
||||
unsigned int ping_rate = 1;
|
||||
int ret;
|
||||
|
||||
setbuf(stdout, NULL);
|
||||
|
||||
fd = open("/dev/watchdog", O_WRONLY);
|
||||
|
||||
if (fd == -1) {
|
||||
printf("Watchdog device not enabled.\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (argc > 1) {
|
||||
if (!strncasecmp(argv[1], "-d", 2)) {
|
||||
flags = WDIOS_DISABLECARD;
|
||||
ioctl(fd, WDIOC_SETOPTIONS, &flags);
|
||||
printf("Watchdog card disabled.\n");
|
||||
goto end;
|
||||
} else if (!strncasecmp(argv[1], "-e", 2)) {
|
||||
flags = WDIOS_ENABLECARD;
|
||||
ioctl(fd, WDIOC_SETOPTIONS, &flags);
|
||||
printf("Watchdog card enabled.\n");
|
||||
goto end;
|
||||
} else if (!strncasecmp(argv[1], "-t", 2) && argv[2]) {
|
||||
flags = atoi(argv[2]);
|
||||
ioctl(fd, WDIOC_SETTIMEOUT, &flags);
|
||||
printf("Watchdog timeout set to %u seconds.\n", flags);
|
||||
goto end;
|
||||
} else if (!strncasecmp(argv[1], "-p", 2) && argv[2]) {
|
||||
ping_rate = strtoul(argv[2], NULL, 0);
|
||||
printf("Watchdog ping rate set to %u seconds.\n", ping_rate);
|
||||
} else {
|
||||
printf("-d to disable, -e to enable, -t <n> to set " \
|
||||
"the timeout,\n-p <n> to set the ping rate, and \n");
|
||||
printf("run by itself to tick the card.\n");
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
printf("Watchdog Ticking Away!\n");
|
||||
|
||||
signal(SIGINT, term);
|
||||
|
||||
while(1) {
|
||||
keep_alive();
|
||||
sleep(ping_rate);
|
||||
}
|
||||
end:
|
||||
ret = write(fd, &v, 1);
|
||||
if (ret < 0)
|
||||
printf("Stopping watchdog ticks failed (%d)...\n", errno);
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ activates as soon as /dev/watchdog is opened and will reboot unless
|
|||
the watchdog is pinged within a certain time, this time is called the
|
||||
timeout or margin. The simplest way to ping the watchdog is to write
|
||||
some data to the device. So a very simple watchdog daemon would look
|
||||
like this source file: see Documentation/watchdog/src/watchdog-simple.c
|
||||
like this source file: see samples/watchdog/watchdog-simple.c
|
||||
|
||||
A more advanced driver could for example check that a HTTP server is
|
||||
still responding before doing the write call to ping the watchdog.
|
||||
|
|
|
|||
|
|
@ -47,4 +47,4 @@ The external event interfaces on the WDT boards are not currently supported.
|
|||
Minor numbers are however allocated for it.
|
||||
|
||||
|
||||
Example Watchdog Driver: see Documentation/watchdog/src/watchdog-simple.c
|
||||
Example Watchdog Driver: see samples/watchdog/watchdog-simple.c
|
||||
|
|
|
|||
Loading…
Reference in a new issue