From 6bee835dd54e279f3d3ae2eca92a9c394b4fd028 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 16 Sep 2016 15:53:52 -0600 Subject: samples: move mic/mpssd example code from Documentation Move mic/mpssd examples to samples and remove it from Documentation Makefile. Create a new Makefile to build mic/mpssd. It can be built from top level directory or from mic/mpssd directory: Run make -C samples/mic/mpssd or cd samples/mic/mpssd; make Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- samples/mic/mpssd/.gitignore | 1 + samples/mic/mpssd/Makefile | 27 + samples/mic/mpssd/micctrl | 173 ++++ samples/mic/mpssd/mpss | 200 +++++ samples/mic/mpssd/mpssd.c | 1826 ++++++++++++++++++++++++++++++++++++++++++ samples/mic/mpssd/mpssd.h | 103 +++ samples/mic/mpssd/sysfs.c | 102 +++ 7 files changed, 2432 insertions(+) create mode 100644 samples/mic/mpssd/.gitignore create mode 100644 samples/mic/mpssd/Makefile create mode 100755 samples/mic/mpssd/micctrl create mode 100755 samples/mic/mpssd/mpss create mode 100644 samples/mic/mpssd/mpssd.c create mode 100644 samples/mic/mpssd/mpssd.h create mode 100644 samples/mic/mpssd/sysfs.c (limited to 'samples') diff --git a/samples/mic/mpssd/.gitignore b/samples/mic/mpssd/.gitignore new file mode 100644 index 000000000000..8b7c72f07c92 --- /dev/null +++ b/samples/mic/mpssd/.gitignore @@ -0,0 +1 @@ +mpssd diff --git a/samples/mic/mpssd/Makefile b/samples/mic/mpssd/Makefile new file mode 100644 index 000000000000..3e3ef91fed6b --- /dev/null +++ b/samples/mic/mpssd/Makefile @@ -0,0 +1,27 @@ +ifndef CROSS_COMPILE +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) + +ifeq ($(ARCH),x86) + +PROGS := mpssd +CC = $(CROSS_COMPILE)gcc +CFLAGS := -I../../../usr/include -I../../../tools/include + +ifdef DEBUG +CFLAGS += -DDEBUG=$(DEBUG) +endif + +all: $(PROGS) +mpssd: mpssd.c sysfs.c + $(CC) $(CFLAGS) mpssd.c sysfs.c -o mpssd -lpthread + +install: + install mpssd /usr/sbin/mpssd + install micctrl /usr/sbin/micctrl + +clean: + rm -fr $(PROGS) + +endif +endif diff --git a/samples/mic/mpssd/micctrl b/samples/mic/mpssd/micctrl new file mode 100755 index 000000000000..8f2629b41c5f --- /dev/null +++ b/samples/mic/mpssd/micctrl @@ -0,0 +1,173 @@ +#!/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 $? diff --git a/samples/mic/mpssd/mpss b/samples/mic/mpssd/mpss new file mode 100755 index 000000000000..5fcf9fa4b082 --- /dev/null +++ b/samples/mic/mpssd/mpss @@ -0,0 +1,200 @@ +#!/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 $? diff --git a/samples/mic/mpssd/mpssd.c b/samples/mic/mpssd/mpssd.c new file mode 100644 index 000000000000..49db1def1721 --- /dev/null +++ b/samples/mic/mpssd/mpssd.c @@ -0,0 +1,1826 @@ +/* + * 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. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "mpssd.h" +#include +#include +#include + +static void *init_mic(void *arg); + +static FILE *logfp; +static struct mic_info mic_list; + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +#define min_t(type, x, y) ({ \ + type __min1 = (x); \ + type __min2 = (y); \ + __min1 < __min2 ? __min1 : __min2; }) + +/* align addr on a size boundary - adjust address up/down if needed */ +#define _ALIGN_DOWN(addr, size) ((addr)&(~((size)-1))) +#define _ALIGN_UP(addr, size) _ALIGN_DOWN(addr + size - 1, size) + +/* align addr on a size boundary - adjust address up if needed */ +#define _ALIGN(addr, size) _ALIGN_UP(addr, size) + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) _ALIGN(addr, PAGE_SIZE) + +#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x)) + +#define GSO_ENABLED 1 +#define MAX_GSO_SIZE (64 * 1024) +#define ETH_H_LEN 14 +#define MAX_NET_PKT_SIZE (_ALIGN_UP(MAX_GSO_SIZE + ETH_H_LEN, 64)) +#define MIC_DEVICE_PAGE_END 0x1000 + +#ifndef VIRTIO_NET_HDR_F_DATA_VALID +#define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */ +#endif + +static struct { + struct mic_device_desc dd; + struct mic_vqconfig vqconfig[2]; + __u32 host_features, guest_acknowledgements; + struct virtio_console_config cons_config; +} virtcons_dev_page = { + .dd = { + .type = VIRTIO_ID_CONSOLE, + .num_vq = ARRAY_SIZE(virtcons_dev_page.vqconfig), + .feature_len = sizeof(virtcons_dev_page.host_features), + .config_len = sizeof(virtcons_dev_page.cons_config), + }, + .vqconfig[0] = { + .num = htole16(MIC_VRING_ENTRIES), + }, + .vqconfig[1] = { + .num = htole16(MIC_VRING_ENTRIES), + }, +}; + +static struct { + struct mic_device_desc dd; + struct mic_vqconfig vqconfig[2]; + __u32 host_features, guest_acknowledgements; + struct virtio_net_config net_config; +} virtnet_dev_page = { + .dd = { + .type = VIRTIO_ID_NET, + .num_vq = ARRAY_SIZE(virtnet_dev_page.vqconfig), + .feature_len = sizeof(virtnet_dev_page.host_features), + .config_len = sizeof(virtnet_dev_page.net_config), + }, + .vqconfig[0] = { + .num = htole16(MIC_VRING_ENTRIES), + }, + .vqconfig[1] = { + .num = htole16(MIC_VRING_ENTRIES), + }, +#if GSO_ENABLED + .host_features = htole32( + 1 << VIRTIO_NET_F_CSUM | + 1 << VIRTIO_NET_F_GSO | + 1 << VIRTIO_NET_F_GUEST_TSO4 | + 1 << VIRTIO_NET_F_GUEST_TSO6 | + 1 << VIRTIO_NET_F_GUEST_ECN), +#else + .host_features = 0, +#endif +}; + +static const char *mic_config_dir = "/etc/mpss"; +static const char *virtblk_backend = "VIRTBLK_BACKEND"; +static struct { + struct mic_device_desc dd; + struct mic_vqconfig vqconfig[1]; + __u32 host_features, guest_acknowledgements; + struct virtio_blk_config blk_config; +} virtblk_dev_page = { + .dd = { + .type = VIRTIO_ID_BLOCK, + .num_vq = ARRAY_SIZE(virtblk_dev_page.vqconfig), + .feature_len = sizeof(virtblk_dev_page.host_features), + .config_len = sizeof(virtblk_dev_page.blk_config), + }, + .vqconfig[0] = { + .num = htole16(MIC_VRING_ENTRIES), + }, + .host_features = + htole32(1<name, strerror(errno)); + return ret; + } + } + if (pid < 0) { + mpsslog("%s fork failed errno %s\n", + mic->name, strerror(errno)); + return ret; + } + + ret = waitpid(pid, NULL, 0); + if (ret < 0) { + mpsslog("%s waitpid failed errno %s\n", + mic->name, strerror(errno)); + return ret; + } + + snprintf(ipaddr, IFNAMSIZ, "172.31.%d.254/24", mic->id + 1); + + pid = fork(); + if (pid == 0) { + ifargv[0] = "ip"; + ifargv[1] = "addr"; + ifargv[2] = "add"; + ifargv[3] = ipaddr; + ifargv[4] = "dev"; + ifargv[5] = dev; + ifargv[6] = NULL; + mpsslog("Configuring %s ipaddr %s\n", dev, ipaddr); + ret = execvp("ip", ifargv); + if (ret < 0) { + mpsslog("%s execvp failed errno %s\n", + mic->name, strerror(errno)); + return ret; + } + } + if (pid < 0) { + mpsslog("%s fork failed errno %s\n", + mic->name, strerror(errno)); + return ret; + } + + ret = waitpid(pid, NULL, 0); + if (ret < 0) { + mpsslog("%s waitpid failed errno %s\n", + mic->name, strerror(errno)); + return ret; + } + mpsslog("MIC name %s %s %d DONE!\n", + mic->name, __func__, __LINE__); + return 0; +} + +static int tun_alloc(struct mic_info *mic, char *dev) +{ + struct ifreq ifr; + int fd, err; +#if GSO_ENABLED + unsigned offload; +#endif + fd = open("/dev/net/tun", O_RDWR); + if (fd < 0) { + mpsslog("Could not open /dev/net/tun %s\n", strerror(errno)); + goto done; + } + + memset(&ifr, 0, sizeof(ifr)); + + ifr.ifr_flags = IFF_TAP | IFF_NO_PI | IFF_VNET_HDR; + if (*dev) + strncpy(ifr.ifr_name, dev, IFNAMSIZ); + + err = ioctl(fd, TUNSETIFF, (void *)&ifr); + if (err < 0) { + mpsslog("%s %s %d TUNSETIFF failed %s\n", + mic->name, __func__, __LINE__, strerror(errno)); + close(fd); + return err; + } +#if GSO_ENABLED + offload = TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 | TUN_F_TSO_ECN; + + err = ioctl(fd, TUNSETOFFLOAD, offload); + if (err < 0) { + mpsslog("%s %s %d TUNSETOFFLOAD failed %s\n", + mic->name, __func__, __LINE__, strerror(errno)); + close(fd); + return err; + } +#endif + strcpy(dev, ifr.ifr_name); + mpsslog("Created TAP %s\n", dev); +done: + return fd; +} + +#define NET_FD_VIRTIO_NET 0 +#define NET_FD_TUN 1 +#define MAX_NET_FD 2 + +static void set_dp(struct mic_info *mic, int type, void *dp) +{ + switch (type) { + case VIRTIO_ID_CONSOLE: + mic->mic_console.console_dp = dp; + return; + case VIRTIO_ID_NET: + mic->mic_net.net_dp = dp; + return; + case VIRTIO_ID_BLOCK: + mic->mic_virtblk.block_dp = dp; + return; + } + mpsslog("%s %s %d not found\n", mic->name, __func__, type); + assert(0); +} + +static void *get_dp(struct mic_info *mic, int type) +{ + switch (type) { + case VIRTIO_ID_CONSOLE: + return mic->mic_console.console_dp; + case VIRTIO_ID_NET: + return mic->mic_net.net_dp; + case VIRTIO_ID_BLOCK: + return mic->mic_virtblk.block_dp; + } + mpsslog("%s %s %d not found\n", mic->name, __func__, type); + assert(0); + return NULL; +} + +static struct mic_device_desc *get_device_desc(struct mic_info *mic, int type) +{ + struct mic_device_desc *d; + int i; + void *dp = get_dp(mic, type); + + for (i = sizeof(struct mic_bootparam); i < PAGE_SIZE; + i += mic_total_desc_size(d)) { + d = dp + i; + + /* End of list */ + if (d->type == 0) + break; + + if (d->type == -1) + continue; + + mpsslog("%s %s d-> type %d d %p\n", + mic->name, __func__, d->type, d); + + if (d->type == (__u8)type) + return d; + } + mpsslog("%s %s %d not found\n", mic->name, __func__, type); + return NULL; +} + +/* See comments in vhost.c for explanation of next_desc() */ +static unsigned next_desc(struct vring_desc *desc) +{ + unsigned int next; + + if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT)) + return -1U; + next = le16toh(desc->next); + return next; +} + +/* Sum up all the IOVEC length */ +static ssize_t +sum_iovec_len(struct mic_copy_desc *copy) +{ + ssize_t sum = 0; + unsigned int i; + + for (i = 0; i < copy->iovcnt; i++) + sum += copy->iov[i].iov_len; + return sum; +} + +static inline void verify_out_len(struct mic_info *mic, + struct mic_copy_desc *copy) +{ + if (copy->out_len != sum_iovec_len(copy)) { + mpsslog("%s %s %d BUG copy->out_len 0x%x len 0x%zx\n", + mic->name, __func__, __LINE__, + copy->out_len, sum_iovec_len(copy)); + assert(copy->out_len == sum_iovec_len(copy)); + } +} + +/* Display an iovec */ +static void +disp_iovec(struct mic_info *mic, struct mic_copy_desc *copy, + const char *s, int line) +{ + unsigned int i; + + for (i = 0; i < copy->iovcnt; i++) + mpsslog("%s %s %d copy->iov[%d] addr %p len 0x%zx\n", + mic->name, s, line, i, + copy->iov[i].iov_base, copy->iov[i].iov_len); +} + +static inline __u16 read_avail_idx(struct mic_vring *vr) +{ + return ACCESS_ONCE(vr->info->avail_idx); +} + +static inline void txrx_prepare(int type, bool tx, struct mic_vring *vr, + struct mic_copy_desc *copy, ssize_t len) +{ + copy->vr_idx = tx ? 0 : 1; + copy->update_used = true; + if (type == VIRTIO_ID_NET) + copy->iov[1].iov_len = len - sizeof(struct virtio_net_hdr); + else + copy->iov[0].iov_len = len; +} + +/* Central API which triggers the copies */ +static int +mic_virtio_copy(struct mic_info *mic, int fd, + struct mic_vring *vr, struct mic_copy_desc *copy) +{ + int ret; + + ret = ioctl(fd, MIC_VIRTIO_COPY_DESC, copy); + if (ret) { + mpsslog("%s %s %d errno %s ret %d\n", + mic->name, __func__, __LINE__, + strerror(errno), ret); + } + return ret; +} + +static inline unsigned _vring_size(unsigned int num, unsigned long align) +{ + return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (3 + num) + + align - 1) & ~(align - 1)) + + sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num; +} + +/* + * This initialization routine requires at least one + * vring i.e. vr0. vr1 is optional. + */ +static void * +init_vr(struct mic_info *mic, int fd, int type, + struct mic_vring *vr0, struct mic_vring *vr1, int num_vq) +{ + int vr_size; + char *va; + + vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES, + MIC_VIRTIO_RING_ALIGN) + + sizeof(struct _mic_vring_info)); + va = mmap(NULL, MIC_DEVICE_PAGE_END + vr_size * num_vq, + PROT_READ, MAP_SHARED, fd, 0); + if (MAP_FAILED == va) { + mpsslog("%s %s %d mmap failed errno %s\n", + mic->name, __func__, __LINE__, + strerror(errno)); + goto done; + } + set_dp(mic, type, va); + vr0->va = (struct mic_vring *)&va[MIC_DEVICE_PAGE_END]; + vr0->info = vr0->va + + _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN); + vring_init(&vr0->vr, + MIC_VRING_ENTRIES, vr0->va, MIC_VIRTIO_RING_ALIGN); + mpsslog("%s %s vr0 %p vr0->info %p vr_size 0x%x vring 0x%x ", + __func__, mic->name, vr0->va, vr0->info, vr_size, + _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN)); + mpsslog("magic 0x%x expected 0x%x\n", + le32toh(vr0->info->magic), MIC_MAGIC + type); + assert(le32toh(vr0->info->magic) == MIC_MAGIC + type); + if (vr1) { + vr1->va = (struct mic_vring *) + &va[MIC_DEVICE_PAGE_END + vr_size]; + vr1->info = vr1->va + _vring_size(MIC_VRING_ENTRIES, + MIC_VIRTIO_RING_ALIGN); + vring_init(&vr1->vr, + MIC_VRING_ENTRIES, vr1->va, MIC_VIRTIO_RING_ALIGN); + mpsslog("%s %s vr1 %p vr1->info %p vr_size 0x%x vring 0x%x ", + __func__, mic->name, vr1->va, vr1->info, vr_size, + _vring_size(MIC_VRING_ENTRIES, MIC_VIRTIO_RING_ALIGN)); + mpsslog("magic 0x%x expected 0x%x\n", + le32toh(vr1->info->magic), MIC_MAGIC + type + 1); + assert(le32toh(vr1->info->magic) == MIC_MAGIC + type + 1); + } +done: + return va; +} + +static int +wait_for_card_driver(struct mic_info *mic, int fd, int type) +{ + struct pollfd pollfd; + int err; + struct mic_device_desc *desc = get_device_desc(mic, type); + __u8 prev_status; + + if (!desc) + return -ENODEV; + prev_status = desc->status; + pollfd.fd = fd; + mpsslog("%s %s Waiting .... desc-> type %d status 0x%x\n", + mic->name, __func__, type, desc->status); + + while (1) { + pollfd.events = POLLIN; + pollfd.revents = 0; + err = poll(&pollfd, 1, -1); + if (err < 0) { + mpsslog("%s %s poll failed %s\n", + mic->name, __func__, strerror(errno)); + continue; + } + + if (pollfd.revents) { + if (desc->status != prev_status) { + mpsslog("%s %s Waiting... desc-> type %d " + "status 0x%x\n", + mic->name, __func__, type, + desc->status); + prev_status = desc->status; + } + if (desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { + mpsslog("%s %s poll.revents %d\n", + mic->name, __func__, pollfd.revents); + mpsslog("%s %s desc-> type %d status 0x%x\n", + mic->name, __func__, type, + desc->status); + break; + } + } + } + return 0; +} + +/* Spin till we have some descriptors */ +static void +spin_for_descriptors(struct mic_info *mic, struct mic_vring *vr) +{ + __u16 avail_idx = read_avail_idx(vr); + + while (avail_idx == le16toh(ACCESS_ONCE(vr->vr.avail->idx))) { +#ifdef DEBUG + mpsslog("%s %s waiting for desc avail %d info_avail %d\n", + mic->name, __func__, + le16toh(vr->vr.avail->idx), vr->info->avail_idx); +#endif + sched_yield(); + } +} + +static void * +virtio_net(void *arg) +{ + static __u8 vnet_hdr[2][sizeof(struct virtio_net_hdr)]; + static __u8 vnet_buf[2][MAX_NET_PKT_SIZE] __attribute__ ((aligned(64))); + struct iovec vnet_iov[2][2] = { + { { .iov_base = vnet_hdr[0], .iov_len = sizeof(vnet_hdr[0]) }, + { .iov_base = vnet_buf[0], .iov_len = sizeof(vnet_buf[0]) } }, + { { .iov_base = vnet_hdr[1], .iov_len = sizeof(vnet_hdr[1]) }, + { .iov_base = vnet_buf[1], .iov_len = sizeof(vnet_buf[1]) } }, + }; + struct iovec *iov0 = vnet_iov[0], *iov1 = vnet_iov[1]; + struct mic_info *mic = (struct mic_info *)arg; + char if_name[IFNAMSIZ]; + struct pollfd net_poll[MAX_NET_FD]; + struct mic_vring tx_vr, rx_vr; + struct mic_copy_desc copy; + struct mic_device_desc *desc; + int err; + + snprintf(if_name, IFNAMSIZ, "mic%d", mic->id); + mic->mic_net.tap_fd = tun_alloc(mic, if_name); + if (mic->mic_net.tap_fd < 0) + goto done; + + if (tap_configure(mic, if_name)) + goto done; + mpsslog("MIC name %s id %d\n", mic->name, mic->id); + + net_poll[NET_FD_VIRTIO_NET].fd = mic->mic_net.virtio_net_fd; + net_poll[NET_FD_VIRTIO_NET].events = POLLIN; + net_poll[NET_FD_TUN].fd = mic->mic_net.tap_fd; + net_poll[NET_FD_TUN].events = POLLIN; + + if (MAP_FAILED == init_vr(mic, mic->mic_net.virtio_net_fd, + VIRTIO_ID_NET, &tx_vr, &rx_vr, + virtnet_dev_page.dd.num_vq)) { + mpsslog("%s init_vr failed %s\n", + mic->name, strerror(errno)); + goto done; + } + + copy.iovcnt = 2; + desc = get_device_desc(mic, VIRTIO_ID_NET); + + while (1) { + ssize_t len; + + net_poll[NET_FD_VIRTIO_NET].revents = 0; + net_poll[NET_FD_TUN].revents = 0; + + /* Start polling for data from tap and virtio net */ + err = poll(net_poll, 2, -1); + if (err < 0) { + mpsslog("%s poll failed %s\n", + __func__, strerror(errno)); + continue; + } + if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) { + err = wait_for_card_driver(mic, + mic->mic_net.virtio_net_fd, + VIRTIO_ID_NET); + if (err) { + mpsslog("%s %s %d Exiting...\n", + mic->name, __func__, __LINE__); + break; + } + } + /* + * Check if there is data to be read from TUN and write to + * virtio net fd if there is. + */ + if (net_poll[NET_FD_TUN].revents & POLLIN) { + copy.iov = iov0; + len = readv(net_poll[NET_FD_TUN].fd, + copy.iov, copy.iovcnt); + if (len > 0) { + struct virtio_net_hdr *hdr + = (struct virtio_net_hdr *)vnet_hdr[0]; + + /* Disable checksums on the card since we are on + a reliable PCIe link */ + hdr->flags |= VIRTIO_NET_HDR_F_DATA_VALID; +#ifdef DEBUG + mpsslog("%s %s %d hdr->flags 0x%x ", mic->name, + __func__, __LINE__, hdr->flags); + mpsslog("copy.out_len %d hdr->gso_type 0x%x\n", + copy.out_len, hdr->gso_type); +#endif +#ifdef DEBUG + disp_iovec(mic, copy, __func__, __LINE__); + mpsslog("%s %s %d read from tap 0x%lx\n", + mic->name, __func__, __LINE__, + len); +#endif + spin_for_descriptors(mic, &tx_vr); + txrx_prepare(VIRTIO_ID_NET, 1, &tx_vr, ©, + len); + + err = mic_virtio_copy(mic, + mic->mic_net.virtio_net_fd, &tx_vr, + ©); + if (err < 0) { + mpsslog("%s %s %d mic_virtio_copy %s\n", + mic->name, __func__, __LINE__, + strerror(errno)); + } + if (!err) + verify_out_len(mic, ©); +#ifdef DEBUG + disp_iovec(mic, copy, __func__, __LINE__); + mpsslog("%s %s %d wrote to net 0x%lx\n", + mic->name, __func__, __LINE__, + sum_iovec_len(©)); +#endif + /* Reinitialize IOV for next run */ + iov0[1].iov_len = MAX_NET_PKT_SIZE; + } else if (len < 0) { + disp_iovec(mic, ©, __func__, __LINE__); + mpsslog("%s %s %d read failed %s ", mic->name, + __func__, __LINE__, strerror(errno)); + mpsslog("cnt %d sum %zd\n", + copy.iovcnt, sum_iovec_len(©)); + } + } + + /* + * Check if there is data to be read from virtio net and + * write to TUN if there is. + */ + if (net_poll[NET_FD_VIRTIO_NET].revents & POLLIN) { + while (rx_vr.info->avail_idx != + le16toh(rx_vr.vr.avail->idx)) { + copy.iov = iov1; + txrx_prepare(VIRTIO_ID_NET, 0, &rx_vr, ©, + MAX_NET_PKT_SIZE + + sizeof(struct virtio_net_hdr)); + + err = mic_virtio_copy(mic, + mic->mic_net.virtio_net_fd, &rx_vr, + ©); + if (!err) { +#ifdef DEBUG + struct virtio_net_hdr *hdr + = (struct virtio_net_hdr *) + vnet_hdr[1]; + + mpsslog("%s %s %d hdr->flags 0x%x, ", + mic->name, __func__, __LINE__, + hdr->flags); + mpsslog("out_len %d gso_type 0x%x\n", + copy.out_len, + hdr->gso_type); +#endif + /* Set the correct output iov_len */ + iov1[1].iov_len = copy.out_len - + sizeof(struct virtio_net_hdr); + verify_out_len(mic, ©); +#ifdef DEBUG + disp_iovec(mic, copy, __func__, + __LINE__); + mpsslog("%s %s %d ", + mic->name, __func__, __LINE__); + mpsslog("read from net 0x%lx\n", + sum_iovec_len(copy)); +#endif + len = writev(net_poll[NET_FD_TUN].fd, + copy.iov, copy.iovcnt); + if (len != sum_iovec_len(©)) { + mpsslog("Tun write failed %s ", + strerror(errno)); + mpsslog("len 0x%zx ", len); + mpsslog("read_len 0x%zx\n", + sum_iovec_len(©)); + } else { +#ifdef DEBUG + disp_iovec(mic, ©, __func__, + __LINE__); + mpsslog("%s %s %d ", + mic->name, __func__, + __LINE__); + mpsslog("wrote to tap 0x%lx\n", + len); +#endif + } + } else { + mpsslog("%s %s %d mic_virtio_copy %s\n", + mic->name, __func__, __LINE__, + strerror(errno)); + break; + } + } + } + if (net_poll[NET_FD_VIRTIO_NET].revents & POLLERR) + mpsslog("%s: %s: POLLERR\n", __func__, mic->name); + } +done: + pthread_exit(NULL); +} + +/* virtio_console */ +#define VIRTIO_CONSOLE_FD 0 +#define MONITOR_FD (VIRTIO_CONSOLE_FD + 1) +#define MAX_CONSOLE_FD (MONITOR_FD + 1) /* must be the last one + 1 */ +#define MAX_BUFFER_SIZE PAGE_SIZE + +static void * +virtio_console(void *arg) +{ + static __u8 vcons_buf[2][PAGE_SIZE]; + struct iovec vcons_iov[2] = { + { .iov_base = vcons_buf[0], .iov_len = sizeof(vcons_buf[0]) }, + { .iov_base = vcons_buf[1], .iov_len = sizeof(vcons_buf[1]) }, + }; + struct iovec *iov0 = &vcons_iov[0], *iov1 = &vcons_iov[1]; + struct mic_info *mic = (struct mic_info *)arg; + int err; + struct pollfd console_poll[MAX_CONSOLE_FD]; + int pty_fd; + char *pts_name; + ssize_t len; + struct mic_vring tx_vr, rx_vr; + struct mic_copy_desc copy; + struct mic_device_desc *desc; + + pty_fd = posix_openpt(O_RDWR); + if (pty_fd < 0) { + mpsslog("can't open a pseudoterminal master device: %s\n", + strerror(errno)); + goto _return; + } + pts_name = ptsname(pty_fd); + if (pts_name == NULL) { + mpsslog("can't get pts name\n"); + goto _close_pty; + } + printf("%s console message goes to %s\n", mic->name, pts_name); + mpsslog("%s console message goes to %s\n", mic->name, pts_name); + err = grantpt(pty_fd); + if (err < 0) { + mpsslog("can't grant access: %s %s\n", + pts_name, strerror(errno)); + goto _close_pty; + } + err = unlockpt(pty_fd); + if (err < 0) { + mpsslog("can't unlock a pseudoterminal: %s %s\n", + pts_name, strerror(errno)); + goto _close_pty; + } + console_poll[MONITOR_FD].fd = pty_fd; + console_poll[MONITOR_FD].events = POLLIN; + + console_poll[VIRTIO_CONSOLE_FD].fd = mic->mic_console.virtio_console_fd; + console_poll[VIRTIO_CONSOLE_FD].events = POLLIN; + + if (MAP_FAILED == init_vr(mic, mic->mic_console.virtio_console_fd, + VIRTIO_ID_CONSOLE, &tx_vr, &rx_vr, + virtcons_dev_page.dd.num_vq)) { + mpsslog("%s init_vr failed %s\n", + mic->name, strerror(errno)); + goto _close_pty; + } + + copy.iovcnt = 1; + desc = get_device_desc(mic, VIRTIO_ID_CONSOLE); + + for (;;) { + console_poll[MONITOR_FD].revents = 0; + console_poll[VIRTIO_CONSOLE_FD].revents = 0; + err = poll(console_poll, MAX_CONSOLE_FD, -1); + if (err < 0) { + mpsslog("%s %d: poll failed: %s\n", __func__, __LINE__, + strerror(errno)); + continue; + } + if (!(desc->status & VIRTIO_CONFIG_S_DRIVER_OK)) { + err = wait_for_card_driver(mic, + mic->mic_console.virtio_console_fd, + VIRTIO_ID_CONSOLE); + if (err) { + mpsslog("%s %s %d Exiting...\n", + mic->name, __func__, __LINE__); + break; + } + } + + if (console_poll[MONITOR_FD].revents & POLLIN) { + copy.iov = iov0; + len = readv(pty_fd, copy.iov, copy.iovcnt); + if (len > 0) { +#ifdef DEBUG + disp_iovec(mic, copy, __func__, __LINE__); + mpsslog("%s %s %d read from tap 0x%lx\n", + mic->name, __func__, __LINE__, + len); +#endif + spin_for_descriptors(mic, &tx_vr); + txrx_prepare(VIRTIO_ID_CONSOLE, 1, &tx_vr, + ©, len); + + err = mic_virtio_copy(mic, + mic->mic_console.virtio_console_fd, + &tx_vr, ©); + if (err < 0) { + mpsslog("%s %s %d mic_virtio_copy %s\n", + mic->name, __func__, __LINE__, + strerror(errno)); + } + if (!err) + verify_out_len(mic, ©); +#ifdef DEBUG + disp_iovec(mic, copy, __func__, __LINE__); + mpsslog("%s %s %d wrote to net 0x%lx\n", + mic->name, __func__, __LINE__, + sum_iovec_len(copy)); +#endif + /* Reinitialize IOV for next run */ + iov0->iov_len = PAGE_SIZE; + } else if (len < 0) { + disp_iovec(mic, ©, __func__, __LINE__); + mpsslog("%s %s %d read failed %s ", + mic->name, __func__, __LINE__, + strerror(errno)); + mpsslog("cnt %d sum %zd\n", + copy.iovcnt, sum_iovec_len(©)); + } + } + + if (console_poll[VIRTIO_CONSOLE_FD].revents & POLLIN) { + while (rx_vr.info->avail_idx != + le16toh(rx_vr.vr.avail->idx)) { + copy.iov = iov1; + txrx_prepare(VIRTIO_ID_CONSOLE, 0, &rx_vr, + ©, PAGE_SIZE); + + err = mic_virtio_copy(mic, + mic->mic_console.virtio_console_fd, + &rx_vr, ©); + if (!err) { + /* Set the correct output iov_len */ + iov1->iov_len = copy.out_len; + verify_out_len(mic, ©); +#ifdef DEBUG + disp_iovec(mic, copy, __func__, + __LINE__); + mpsslog("%s %s %d ", + mic->name, __func__, __LINE__); + mpsslog("read from net 0x%lx\n", + sum_iovec_len(copy)); +#endif + len = writev(pty_fd, + copy.iov, copy.iovcnt); + if (len != sum_iovec_len(©)) { + mpsslog("Tun write failed %s ", + strerror(errno)); + mpsslog("len 0x%zx ", len); + mpsslog("read_len 0x%zx\n", + sum_iovec_len(©)); + } else { +#ifdef DEBUG + disp_iovec(mic, copy, __func__, + __LINE__); + mpsslog("%s %s %d ", + mic->name, __func__, + __LINE__); + mpsslog("wrote to tap 0x%lx\n", + len); +#endif + } + } else { + mpsslog("%s %s %d mic_virtio_copy %s\n", + mic->name, __func__, __LINE__, + strerror(errno)); + break; + } + } + } + if (console_poll[NET_FD_VIRTIO_NET].revents & POLLERR) + mpsslog("%s: %s: POLLERR\n", __func__, mic->name); + } +_close_pty: + close(pty_fd); +_return: + pthread_exit(NULL); +} + +static void +add_virtio_device(struct mic_info *mic, struct mic_device_desc *dd) +{ + char path[PATH_MAX]; + int fd, err; + + snprintf(path, PATH_MAX, "/dev/vop_virtio%d", mic->id); + fd = open(path, O_RDWR); + if (fd < 0) { + mpsslog("Could not open %s %s\n", path, strerror(errno)); + return; + } + + err = ioctl(fd, MIC_VIRTIO_ADD_DEVICE, dd); + if (err < 0) { + mpsslog("Could not add %d %s\n", dd->type, strerror(errno)); + close(fd); + return; + } + switch (dd->type) { + case VIRTIO_ID_NET: + mic->mic_net.virtio_net_fd = fd; + mpsslog("Added VIRTIO_ID_NET for %s\n", mic->name); + break; + case VIRTIO_ID_CONSOLE: + mic->mic_console.virtio_console_fd = fd; + mpsslog("Added VIRTIO_ID_CONSOLE for %s\n", mic->name); + break; + case VIRTIO_ID_BLOCK: + mic->mic_virtblk.virtio_block_fd = fd; + mpsslog("Added VIRTIO_ID_BLOCK for %s\n", mic->name); + break; + } +} + +static bool +set_backend_file(struct mic_info *mic) +{ + FILE *config; + char buff[PATH_MAX], *line, *evv, *p; + + snprintf(buff, PATH_MAX, "%s/mpssd%03d.conf", mic_config_dir, mic->id); + config = fopen(buff, "r"); + if (config == NULL) + return false; + do { /* look for "virtblk_backend=XXXX" */ + line = fgets(buff, PATH_MAX, config); + if (line == NULL) + break; + if (*line == '#') + continue; + p = strchr(line, '\n'); + if (p) + *p = '\0'; + } while (strncmp(line, virtblk_backend, strlen(virtblk_backend)) != 0); + fclose(config); + if (line == NULL) + return false; + evv = strchr(line, '='); + if (evv == NULL) + return false; + mic->mic_virtblk.backend_file = malloc(strlen(evv) + 1); + if (mic->mic_virtblk.backend_file == NULL) { + mpsslog("%s %d can't allocate memory\n", mic->name, mic->id); + return false; + } + strcpy(mic->mic_virtblk.backend_file, evv + 1); + return true; +} + +#define SECTOR_SIZE 512 +static bool +set_backend_size(struct mic_info *mic) +{ + mic->mic_virtblk.backend_size = lseek(mic->mic_virtblk.backend, 0, + SEEK_END); + if (mic->mic_virtblk.backend_size < 0) { + mpsslog("%s: can't seek: %s\n", + mic->name, mic->mic_virtblk.backend_file); + return false; + } + virtblk_dev_page.blk_config.capacity = + mic->mic_virtblk.backend_size / SECTOR_SIZE; + if ((mic->mic_virtblk.backend_size % SECTOR_SIZE) != 0) + virtblk_dev_page.blk_config.capacity++; + + virtblk_dev_page.blk_config.capacity = + htole64(virtblk_dev_page.blk_config.capacity); + + return true; +} + +static bool +open_backend(struct mic_info *mic) +{ + if (!set_backend_file(mic)) + goto _error_exit; + mic->mic_virtblk.backend = open(mic->mic_virtblk.backend_file, O_RDWR); + if (mic->mic_virtblk.backend < 0) { + mpsslog("%s: can't open: %s\n", mic->name, + mic->mic_virtblk.backend_file); + goto _error_free; + } + if (!set_backend_size(mic)) + goto _error_close; + mic->mic_virtblk.backend_addr = mmap(NULL, + mic->mic_virtblk.backend_size, + PROT_READ|PROT_WRITE, MAP_SHARED, + mic->mic_virtblk.backend, 0L); + if (mic->mic_virtblk.backend_addr == MAP_FAILED) { + mpsslog("%s: can't map: %s %s\n", + mic->name, mic->mic_virtblk.backend_file, + strerror(errno)); + goto _error_close; + } + return true; + + _error_close: + close(mic->mic_virtblk.backend); + _error_free: + free(mic->mic_virtblk.backend_file); + _error_exit: + return false; +} + +static void +close_backend(struct mic_info *mic) +{ + munmap(mic->mic_virtblk.backend_addr, mic->mic_virtblk.backend_size); + close(mic->mic_virtblk.backend); + free(mic->mic_virtblk.backend_file); +} + +static bool +start_virtblk(struct mic_info *mic, struct mic_vring *vring) +{ + if (((unsigned long)&virtblk_dev_page.blk_config % 8) != 0) { + mpsslog("%s: blk_config is not 8 byte aligned.\n", + mic->name); + return false; + } + add_virtio_device(mic, &virtblk_dev_page.dd); + if (MAP_FAILED == init_vr(mic, mic->mic_virtblk.virtio_block_fd, + VIRTIO_ID_BLOCK, vring, NULL, + virtblk_dev_page.dd.num_vq)) { + mpsslog("%s init_vr failed %s\n", + mic->name, strerror(errno)); + return false; + } + return true; +} + +static void +stop_virtblk(struct mic_info *mic) +{ + int vr_size, ret; + + vr_size = PAGE_ALIGN(_vring_size(MIC_VRING_ENTRIES, + MIC_VIRTIO_RING_ALIGN) + + sizeof(struct _mic_vring_info)); + ret = munmap(mic->mic_virtblk.block_dp, + MIC_DEVICE_PAGE_END + vr_size * virtblk_dev_page.dd.num_vq); + if (ret < 0) + mpsslog("%s munmap errno %d\n", mic->name, errno); + close(mic->mic_virtblk.virtio_block_fd); +} + +static __u8 +header_error_check(struct vring_desc *desc) +{ + if (le32toh(desc->len) != sizeof(struct virtio_blk_outhdr)) { + mpsslog("%s() %d: length is not sizeof(virtio_blk_outhd)\n", + __func__, __LINE__); + return -EIO; + } + if (!(le16toh(desc->flags) & VRING_DESC_F_NEXT)) { + mpsslog("%s() %d: alone\n", + __func__, __LINE__); + return -EIO; + } + if (le16toh(desc->flags) & VRING_DESC_F_WRITE) { + mpsslog("%s() %d: not read\n", + __func__, __LINE__); + return -EIO; + } + return 0; +} + +static int +read_header(int fd, struct virtio_blk_outhdr *hdr, __u32 desc_idx) +{ + struct iovec iovec; + struct mic_copy_desc copy; + + iovec.iov_len = sizeof(*hdr); + iovec.iov_base = hdr; + copy.iov = &iovec; + copy.iovcnt = 1; + copy.vr_idx = 0; /* only one vring on virtio_block */ + copy.update_used = false; /* do not update used index */ + return ioctl(fd, MIC_VIRTIO_COPY_DESC, ©); +} + +static int +transfer_blocks(int fd, struct iovec *iovec, __u32 iovcnt) +{ + struct mic_copy_desc copy; + + copy.iov = iovec; + copy.iovcnt = iovcnt; + copy.vr_idx = 0; /* only one vring on virtio_block */ + copy.update_used = false; /* do not update used index */ + return ioctl(fd, MIC_VIRTIO_COPY_DESC, ©); +} + +static __u8 +status_error_check(struct vring_desc *desc) +{ + if (le32toh(desc->len) != sizeof(__u8)) { + mpsslog("%s() %d: length is not sizeof(status)\n", + __func__, __LINE__); + return -EIO; + } + return 0; +} + +static int +write_status(int fd, __u8 *status) +{ + struct iovec iovec; + struct mic_copy_desc copy; + + iovec.iov_base = status; + iovec.iov_len = sizeof(*status); + copy.iov = &iovec; + copy.iovcnt = 1; + copy.vr_idx = 0; /* only one vring on virtio_block */ + copy.update_used = true; /* Update used index */ + return ioctl(fd, MIC_VIRTIO_COPY_DESC, ©); +} + +#ifndef VIRTIO_BLK_T_GET_ID +#define VIRTIO_BLK_T_GET_ID 8 +#endif + +static void * +virtio_block(void *arg) +{ + struct mic_info *mic = (struct mic_info *)arg; + int ret; + struct pollfd block_poll; + struct mic_vring vring; + __u16 avail_idx; + __u32 desc_idx; + struct vring_desc *desc; + struct iovec *iovec, *piov; + __u8 status; + __u32 buffer_desc_idx; + struct virtio_blk_outhdr hdr; + void *fos; + + for (;;) { /* forever */ + if (!open_backend(mic)) { /* No virtblk */ + for (mic->mic_virtblk.signaled = 0; + !mic->mic_virtblk.signaled;) + sleep(1); + continue; + } + + /* backend file is specified. */ + if (!start_virtblk(mic, &vring)) + goto _close_backend; + iovec = malloc(sizeof(*iovec) * + le32toh(virtblk_dev_page.blk_config.seg_max)); + if (!iovec) { + mpsslog("%s: can't alloc iovec: %s\n", + mic->name, strerror(ENOMEM)); + goto _stop_virtblk; + } + + block_poll.fd = mic->mic_virtblk.virtio_block_fd; + block_poll.events = POLLIN; + for (mic->mic_virtblk.signaled = 0; + !mic->mic_virtblk.signaled;) { + block_poll.revents = 0; + /* timeout in 1 sec to see signaled */ + ret = poll(&block_poll, 1, 1000); + if (ret < 0) { + mpsslog("%s %d: poll failed: %s\n", + __func__, __LINE__, + strerror(errno)); + continue; + } + + if (!(block_poll.revents & POLLIN)) { +#ifdef DEBUG + mpsslog("%s %d: block_poll.revents=0x%x\n", + __func__, __LINE__, block_poll.revents); +#endif + continue; + } + + /* POLLIN */ + while (vring.info->avail_idx != + le16toh(vring.vr.avail->idx)) { + /* read header element */ + avail_idx = + vring.info->avail_idx & + (vring.vr.num - 1); + desc_idx = le16toh( + vring.vr.avail->ring[avail_idx]); + desc = &vring.vr.desc[desc_idx]; +#ifdef DEBUG + mpsslog("%s() %d: avail_idx=%d ", + __func__, __LINE__, + vring.info->avail_idx); + mpsslog("vring.vr.num=%d desc=%p\n", + vring.vr.num, desc); +#endif + status = header_error_check(desc); + ret = read_header( + mic->mic_virtblk.virtio_block_fd, + &hdr, desc_idx); + if (ret < 0) { + mpsslog("%s() %d %s: ret=%d %s\n", + __func__, __LINE__, + mic->name, ret, + strerror(errno)); + break; + } + /* buffer element */ + piov = iovec; + status = 0; + fos = mic->mic_virtblk.backend_addr + + (hdr.sector * SECTOR_SIZE); + buffer_desc_idx = next_desc(desc); + desc_idx = buffer_desc_idx; + for (desc = &vring.vr.desc[buffer_desc_idx]; + desc->flags & VRING_DESC_F_NEXT; + desc_idx = next_desc(desc), + desc = &vring.vr.desc[desc_idx]) { + piov->iov_len = desc->len; + piov->iov_base = fos; + piov++; + fos += desc->len; + } + /* Returning NULLs for VIRTIO_BLK_T_GET_ID. */ + if (hdr.type & ~(VIRTIO_BLK_T_OUT | + VIRTIO_BLK_T_GET_ID)) { + /* + VIRTIO_BLK_T_IN - does not do + anything. Probably for documenting. + VIRTIO_BLK_T_SCSI_CMD - for + virtio_scsi. + VIRTIO_BLK_T_FLUSH - turned off in + config space. + VIRTIO_BLK_T_BARRIER - defined but not + used in anywhere. + */ + mpsslog("%s() %d: type %x ", + __func__, __LINE__, + hdr.type); + mpsslog("is not supported\n"); + status = -ENOTSUP; + + } else { + ret = transfer_blocks( + mic->mic_virtblk.virtio_block_fd, + iovec, + piov - iovec); + if (ret < 0 && + status != 0) + status = ret; + } + /* write status and update used pointer */ + if (status != 0) + status = status_error_check(desc); + ret = write_status( + mic->mic_virtblk.virtio_block_fd, + &status); +#ifdef DEBUG + mpsslog("%s() %d: write status=%d on desc=%p\n", + __func__, __LINE__, + status, desc); +#endif + } + } + free(iovec); +_stop_virtblk: + stop_virtblk(mic); +_close_backend: + close_backend(mic); + } /* forever */ + + pthread_exit(NULL); +} + +static void +reset(struct mic_info *mic) +{ +#define RESET_TIMEOUT 120 + int i = RESET_TIMEOUT; + setsysfs(mic->name, "state", "reset"); + while (i) { + char *state; + state = readsysfs(mic->name, "state"); + if (!state) + goto retry; + mpsslog("%s: %s %d state %s\n", + mic->name, __func__, __LINE__, state); + + if (!strcmp(state, "ready")) { + free(state); + break; + } + free(state); +retry: + sleep(1); + i--; + } +} + +static int +get_mic_shutdown_status(struct mic_info *mic, char *shutdown_status) +{ + if (!strcmp(shutdown_status, "nop")) + return MIC_NOP; + if (!strcmp(shutdown_status, "crashed")) + return MIC_CRASHED; + if (!strcmp(shutdown_status, "halted")) + return MIC_HALTED; + if (!strcmp(shutdown_status, "poweroff")) + return MIC_POWER_OFF; + if (!strcmp(shutdown_status, "restart")) + return MIC_RESTART; + mpsslog("%s: BUG invalid status %s\n", mic->name, shutdown_status); + /* Invalid state */ + assert(0); +}; + +static int get_mic_state(struct mic_info *mic) +{ + char *state = NULL; + enum mic_states mic_state; + + while (!state) { + state = readsysfs(mic->name, "state"); + sleep(1); + } + mpsslog("%s: %s %d state %s\n", + mic->name, __func__, __LINE__, state); + + if (!strcmp(state, "ready")) { + mic_state = MIC_READY; + } else if (!strcmp(state, "booting")) { + mic_state = MIC_BOOTING; + } else if (!strcmp(state, "online")) { + mic_state = MIC_ONLINE; + } else if (!strcmp(state, "shutting_down")) { + mic_state = MIC_SHUTTING_DOWN; + } else if (!strcmp(state, "reset_failed")) { + mic_state = MIC_RESET_FAILED; + } else if (!strcmp(state, "resetting")) { + mic_state = MIC_RESETTING; + } else { + mpsslog("%s: BUG invalid state %s\n", mic->name, state); + assert(0); + } + + free(state); + return mic_state; +}; + +static void mic_handle_shutdown(struct mic_info *mic) +{ +#define SHUTDOWN_TIMEOUT 60 + int i = SHUTDOWN_TIMEOUT; + char *shutdown_status; + while (i) { + shutdown_status = readsysfs(mic->name, "shutdown_status"); + if (!shutdown_status) { + sleep(1); + continue; + } + mpsslog("%s: %s %d shutdown_status %s\n", + mic->name, __func__, __LINE__, shutdown_status); + switch (get_mic_shutdown_status(mic, shutdown_status)) { + case MIC_RESTART: + mic->restart = 1; + case MIC_HALTED: + case MIC_POWER_OFF: + case MIC_CRASHED: + free(shutdown_status); + goto reset; + default: + break; + } + free(shutdown_status); + sleep(1); + i--; + } +reset: + if (!i) + mpsslog("%s: %s %d timing out waiting for shutdown_status %s\n", + mic->name, __func__, __LINE__, shutdown_status); + reset(mic); +} + +static int open_state_fd(struct mic_info *mic) +{ + char pathname[PATH_MAX]; + int fd; + + snprintf(pathname, PATH_MAX - 1, "%s/%s/%s", + MICSYSFSDIR, mic->name, "state"); + + fd = open(pathname, O_RDONLY); + if (fd < 0) + mpsslog("%s: opening file %s failed %s\n", + mic->name, pathname, strerror(errno)); + return fd; +} + +static int block_till_state_change(int fd, struct mic_info *mic) +{ + struct pollfd ufds[1]; + char value[PAGE_SIZE]; + int ret; + + ufds[0].fd = fd; + ufds[0].events = POLLERR | POLLPRI; + ret = poll(ufds, 1, -1); + if (ret < 0) { + mpsslog("%s: %s %d poll failed %s\n", + mic->name, __func__, __LINE__, strerror(errno)); + return ret; + } + + ret = lseek(fd, 0, SEEK_SET); + if (ret < 0) { + mpsslog("%s: %s %d Failed to seek to 0: %s\n", + mic->name, __func__, __LINE__, strerror(errno)); + return ret; + } + + ret = read(fd, value, sizeof(value)); + if (ret < 0) { + mpsslog("%s: %s %d Failed to read sysfs entry: %s\n", + mic->name, __func__, __LINE__, strerror(errno)); + return ret; + } + + return 0; +} + +static void * +mic_config(void *arg) +{ + struct mic_info *mic = (struct mic_info *)arg; + int fd, ret, stat = 0; + + fd = open_state_fd(mic); + if (fd < 0) { + mpsslog("%s: %s %d open state fd failed %s\n", + mic->name, __func__, __LINE__, strerror(errno)); + goto exit; + } + + do { + ret = block_till_state_change(fd, mic); + if (ret < 0) { + mpsslog("%s: %s %d block_till_state_change error %s\n", + mic->name, __func__, __LINE__, strerror(errno)); + goto close_exit; + } + + switch (get_mic_state(mic)) { + case MIC_SHUTTING_DOWN: + mic_handle_shutdown(mic); + break; + case MIC_READY: + case MIC_RESET_FAILED: + ret = kill(mic->pid, SIGTERM); + mpsslog("%s: %s %d kill pid %d ret %d\n", + mic->name, __func__, __LINE__, + mic->pid, ret); + if (!ret) { + ret = waitpid(mic->pid, &stat, + WIFSIGNALED(stat)); + mpsslog("%s: %s %d waitpid ret %d pid %d\n", + mic->name, __func__, __LINE__, + ret, mic->pid); + } + if (mic->boot_on_resume) { + setsysfs(mic->name, "state", "boot"); + mic->boot_on_resume = 0; + } + goto close_exit; + default: + break; + } + } while (1); + +close_exit: + close(fd); +exit: + init_mic(mic); + pthread_exit(NULL); +} + +static void +set_cmdline(struct mic_info *mic) +{ + char buffer[PATH_MAX]; + int len; + + len = snprintf(buffer, PATH_MAX, + "clocksource=tsc highres=off nohz=off "); + len += snprintf(buffer + len, PATH_MAX - len, + "cpufreq_on;corec6_off;pc3_off;pc6_off "); + len += snprintf(buffer + len, PATH_MAX - len, + "ifcfg=static;address,172.31.%d.1;netmask,255.255.255.0", + mic->id + 1); + + setsysfs(mic->name, "cmdline", buffer); + mpsslog("%s: Command line: \"%s\"\n", mic->name, buffer); + snprintf(buffer, PATH_MAX, "172.31.%d.1", mic->id + 1); + mpsslog("%s: IPADDR: \"%s\"\n", mic->name, buffer); +} + +static void +set_log_buf_info(struct mic_info *mic) +{ + int fd; + off_t len; + char system_map[] = "/lib/firmware/mic/System.map"; + char *map, *temp, log_buf[17] = {'\0'}; + + fd = open(system_map, O_RDONLY); + if (fd < 0) { + mpsslog("%s: Opening System.map failed: %d\n", + mic->name, errno); + return; + } + len = lseek(fd, 0, SEEK_END); + if (len < 0) { + mpsslog("%s: Reading System.map size failed: %d\n", + mic->name, errno); + close(fd); + return; + } + map = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); + if (map == MAP_FAILED) { + mpsslog("%s: mmap of System.map failed: %d\n", + mic->name, errno); + close(fd); + return; + } + temp = strstr(map, "__log_buf"); + if (!temp) { + mpsslog("%s: __log_buf not found: %d\n", mic->name, errno); + munmap(map, len); + close(fd); + return; + } + strncpy(log_buf, temp - 19, 16); + setsysfs(mic->name, "log_buf_addr", log_buf); + mpsslog("%s: log_buf_addr: %s\n", mic->name, log_buf); + temp = strstr(map, "log_buf_len"); + if (!temp) { + mpsslog("%s: log_buf_len not found: %d\n", mic->name, errno); + munmap(map, len); + close(fd); + return; + } + strncpy(log_buf, temp - 19, 16); + setsysfs(mic->name, "log_buf_len", log_buf); + mpsslog("%s: log_buf_len: %s\n", mic->name, log_buf); + munmap(map, len); + close(fd); +} + +static void +change_virtblk_backend(int x, siginfo_t *siginfo, void *p) +{ + struct mic_info *mic; + + for (mic = mic_list.next; mic != NULL; mic = mic->next) + mic->mic_virtblk.signaled = 1/* true */; +} + +static void +set_mic_boot_params(struct mic_info *mic) +{ + set_log_buf_info(mic); + set_cmdline(mic); +} + +static void * +init_mic(void *arg) +{ + struct mic_info *mic = (struct mic_info *)arg; + struct sigaction ignore = { + .sa_flags = 0, + .sa_handler = SIG_IGN + }; + struct sigaction act = { + .sa_flags = SA_SIGINFO, + .sa_sigaction = change_virtblk_backend, + }; + char buffer[PATH_MAX]; + int err, fd; + + /* + * Currently, one virtio block device is supported for each MIC card + * at a time. Any user (or test) can send a SIGUSR1 to the MIC daemon. + * The signal informs the virtio block backend about a change in the + * configuration file which specifies the virtio backend file name on + * the host. Virtio block backend then re-reads the configuration file + * and switches to the new block device. This signalling mechanism may + * not be required once multiple virtio block devices are supported by + * the MIC daemon. + */ + sigaction(SIGUSR1, &ignore, NULL); +retry: + fd = open_state_fd(mic); + if (fd < 0) { + mpsslog("%s: %s %d open state fd failed %s\n", + mic->name, __func__, __LINE__, strerror(errno)); + sleep(2); + goto retry; + } + + if (mic->restart) { + snprintf(buffer, PATH_MAX, "boot"); + setsysfs(mic->name, "state", buffer); + mpsslog("%s restarting mic %d\n", + mic->name, mic->restart); + mic->restart = 0; + } + + while (1) { + while (block_till_state_change(fd, mic)) { + mpsslog("%s: %s %d block_till_state_change error %s\n", + mic->name, __func__, __LINE__, strerror(errno)); + sleep(2); + continue; + } + + if (get_mic_state(mic) == MIC_BOOTING) + break; + } + + mic->pid = fork(); + switch (mic->pid) { + case 0: + add_virtio_device(mic, &virtcons_dev_page.dd); + add_virtio_device(mic, &virtnet_dev_page.dd); + err = pthread_create(&mic->mic_console.console_thread, NULL, + virtio_console, mic); + if (err) + mpsslog("%s virtcons pthread_create failed %s\n", + mic->name, strerror(err)); + err = pthread_create(&mic->mic_net.net_thread, NULL, + virtio_net, mic); + if (err) + mpsslog("%s virtnet pthread_create failed %s\n", + mic->name, strerror(err)); + err = pthread_create(&mic->mic_virtblk.block_thread, NULL, + virtio_block, mic); + if (err) + mpsslog("%s virtblk pthread_create failed %s\n", + mic->name, strerror(err)); + sigemptyset(&act.sa_mask); + err = sigaction(SIGUSR1, &act, NULL); + if (err) + mpsslog("%s sigaction SIGUSR1 failed %s\n", + mic->name, strerror(errno)); + while (1) + sleep(60); + case -1: + mpsslog("fork failed MIC name %s id %d errno %d\n", + mic->name, mic->id, errno); + break; + default: + err = pthread_create(&mic->config_thread, NULL, + mic_config, mic); + if (err) + mpsslog("%s mic_config pthread_create failed %s\n", + mic->name, strerror(err)); + } + + return NULL; +} + +static void +start_daemon(void) +{ + struct mic_info *mic; + int err; + + for (mic = mic_list.next; mic; mic = mic->next) { + set_mic_boot_params(mic); + err = pthread_create(&mic->init_thread, NULL, init_mic, mic); + if (err) + mpsslog("%s init_mic pthread_create failed %s\n", + mic->name, strerror(err)); + } + + while (1) + sleep(60); +} + +static int +init_mic_list(void) +{ + struct mic_info *mic = &mic_list; + struct dirent *file; + DIR *dp; + int cnt = 0; + + dp = opendir(MICSYSFSDIR); + if (!dp) + return 0; + + while ((file = readdir(dp)) != NULL) { + if (!strncmp(file->d_name, "mic", 3)) { + mic->next = calloc(1, sizeof(struct mic_info)); + if (mic->next) { + mic = mic->next; + mic->id = atoi(&file->d_name[3]); + mic->name = malloc(strlen(file->d_name) + 16); + if (mic->name) + strcpy(mic->name, file->d_name); + mpsslog("MIC name %s id %d\n", mic->name, + mic->id); + cnt++; + } + } + } + + closedir(dp); + return cnt; +} + +void +mpsslog(char *format, ...) +{ + va_list args; + char buffer[4096]; + char ts[52], *ts1; + time_t t; + + if (logfp == NULL) + return; + + va_start(args, format); + vsprintf(buffer, format, args); + va_end(args); + + time(&t); + ts1 = ctime_r(&t, ts); + ts1[strlen(ts1) - 1] = '\0'; + fprintf(logfp, "%s: %s", ts1, buffer); + + fflush(logfp); +} + +int +main(int argc, char *argv[]) +{ + int cnt; + pid_t pid; + + myname = argv[0]; + + logfp = fopen(LOGFILE_NAME, "a+"); + if (!logfp) { + fprintf(stderr, "cannot open logfile '%s'\n", LOGFILE_NAME); + exit(1); + } + pid = fork(); + switch (pid) { + case 0: + break; + case -1: + exit(2); + default: + exit(0); + } + + mpsslog("MIC Daemon start\n"); + + cnt = init_mic_list(); + if (cnt == 0) { + mpsslog("MIC module not loaded\n"); + exit(3); + } + mpsslog("MIC found %d devices\n", cnt); + + start_daemon(); + + exit(0); +} diff --git a/samples/mic/mpssd/mpssd.h b/samples/mic/mpssd/mpssd.h new file mode 100644 index 000000000000..8bd64944aacc --- /dev/null +++ b/samples/mic/mpssd/mpssd.h @@ -0,0 +1,103 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 diff --git a/samples/mic/mpssd/sysfs.c b/samples/mic/mpssd/sysfs.c new file mode 100644 index 000000000000..8dd326936083 --- /dev/null +++ b/samples/mic/mpssd/sysfs.c @@ -0,0 +1,102 @@ +/* + * 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; +} -- cgit v1.2.3 From 986b891ad121c61200d3dffcc8ed128a1397682e Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 16 Sep 2016 16:07:20 -0600 Subject: samples: move misc-devices/mei example code from Documentation Move misc-devices/mei examples to samples/mei and remove it from Documentation Makefile. Delete misc-devices/Makefile. Create a new Makefile to build samples/mei. It can be built from top level directory or from mei directory: Run make -C samples/mei or cd samples/mei; make Acked-by: Jonathan Corbet Acked-by: Greg Kroah-Hartman Acked-by: Tomas Winkler Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/misc-devices/Makefile | 1 - Documentation/misc-devices/mei/.gitignore | 1 - Documentation/misc-devices/mei/Makefile | 5 - Documentation/misc-devices/mei/TODO | 2 - Documentation/misc-devices/mei/mei-amt-version.c | 479 ----------------------- MAINTAINERS | 1 + samples/mei/.gitignore | 1 + samples/mei/Makefile | 9 + samples/mei/TODO | 2 + samples/mei/mei-amt-version.c | 479 +++++++++++++++++++++++ 11 files changed, 493 insertions(+), 489 deletions(-) delete mode 100644 Documentation/misc-devices/Makefile delete mode 100644 Documentation/misc-devices/mei/.gitignore delete mode 100644 Documentation/misc-devices/mei/Makefile delete mode 100644 Documentation/misc-devices/mei/TODO delete mode 100644 Documentation/misc-devices/mei/mei-amt-version.c create mode 100644 samples/mei/.gitignore create mode 100644 samples/mei/Makefile create mode 100644 samples/mei/TODO create mode 100644 samples/mei/mei-amt-version.c (limited to 'samples') diff --git a/Documentation/Makefile b/Documentation/Makefile index 80b5bdc65055..3c2a207a7c40 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ subdir-y := accounting auxdisplay blackfin \ - laptops misc-devices pcmcia timers watchdog + laptops pcmcia timers watchdog diff --git a/Documentation/misc-devices/Makefile b/Documentation/misc-devices/Makefile deleted file mode 100644 index e2b7aa4c9e21..000000000000 --- a/Documentation/misc-devices/Makefile +++ /dev/null @@ -1 +0,0 @@ -subdir-y := mei diff --git a/Documentation/misc-devices/mei/.gitignore b/Documentation/misc-devices/mei/.gitignore deleted file mode 100644 index f356b81ca1ec..000000000000 --- a/Documentation/misc-devices/mei/.gitignore +++ /dev/null @@ -1 +0,0 @@ -mei-amt-version diff --git a/Documentation/misc-devices/mei/Makefile b/Documentation/misc-devices/mei/Makefile deleted file mode 100644 index d758047d1b6d..000000000000 --- a/Documentation/misc-devices/mei/Makefile +++ /dev/null @@ -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) diff --git a/Documentation/misc-devices/mei/TODO b/Documentation/misc-devices/mei/TODO deleted file mode 100644 index 6b3625d3058c..000000000000 --- a/Documentation/misc-devices/mei/TODO +++ /dev/null @@ -1,2 +0,0 @@ -TODO: - - Cleanup and split the timer function diff --git a/Documentation/misc-devices/mei/mei-amt-version.c b/Documentation/misc-devices/mei/mei-amt-version.c deleted file mode 100644 index 57d0d871dcf7..000000000000 --- a/Documentation/misc-devices/mei/mei-amt-version.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/***************************************************************************** - * 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; -} diff --git a/MAINTAINERS b/MAINTAINERS index 20bb1d00098c..b76872ace843 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6244,6 +6244,7 @@ F: include/linux/mei_cl_bus.h F: drivers/misc/mei/* F: drivers/watchdog/mei_wdt.c F: Documentation/misc-devices/mei/* +F: samples/mei/* INTEL MIC DRIVERS (mic) M: Sudeep Dutt diff --git a/samples/mei/.gitignore b/samples/mei/.gitignore new file mode 100644 index 000000000000..f356b81ca1ec --- /dev/null +++ b/samples/mei/.gitignore @@ -0,0 +1 @@ +mei-amt-version diff --git a/samples/mei/Makefile b/samples/mei/Makefile new file mode 100644 index 000000000000..7aac216dc420 --- /dev/null +++ b/samples/mei/Makefile @@ -0,0 +1,9 @@ +CC := $(CROSS_COMPILE)gcc +CFLAGS := -I../../usr/include + +PROGS := mei-amt-version + +all: $(PROGS) + +clean: + rm -fr $(PROGS) diff --git a/samples/mei/TODO b/samples/mei/TODO new file mode 100644 index 000000000000..6b3625d3058c --- /dev/null +++ b/samples/mei/TODO @@ -0,0 +1,2 @@ +TODO: + - Cleanup and split the timer function diff --git a/samples/mei/mei-amt-version.c b/samples/mei/mei-amt-version.c new file mode 100644 index 000000000000..57d0d871dcf7 --- /dev/null +++ b/samples/mei/mei-amt-version.c @@ -0,0 +1,479 @@ +/****************************************************************************** + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/***************************************************************************** + * 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; +} -- cgit v1.2.3 From 155fe001c6cd840c1cef3a8c42a8f14296a47c57 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 16 Sep 2016 17:20:42 -0600 Subject: samples: move timers example code from Documentation Move timers examples to samples and remove it from Documentation Makefile. Create a new Makefile to build timers. It can be built from top level directory or from timers directory: Run make -C samples/timers or cd samples/timers; make Acked-by: Jonathan Corbet Acked-by: Clemens Ladisch Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/timers/.gitignore | 1 - Documentation/timers/Makefile | 5 - Documentation/timers/hpet.txt | 2 +- Documentation/timers/hpet_example.c | 294 ------------------------------------ samples/timers/.gitignore | 1 + samples/timers/Makefile | 15 ++ samples/timers/hpet_example.c | 294 ++++++++++++++++++++++++++++++++++++ 8 files changed, 312 insertions(+), 302 deletions(-) delete mode 100644 Documentation/timers/.gitignore delete mode 100644 Documentation/timers/Makefile delete mode 100644 Documentation/timers/hpet_example.c create mode 100644 samples/timers/.gitignore create mode 100644 samples/timers/Makefile create mode 100644 samples/timers/hpet_example.c (limited to 'samples') diff --git a/Documentation/Makefile b/Documentation/Makefile index 3c2a207a7c40..fc386b7a01b2 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ subdir-y := accounting auxdisplay blackfin \ - laptops pcmcia timers watchdog + laptops pcmcia watchdog diff --git a/Documentation/timers/.gitignore b/Documentation/timers/.gitignore deleted file mode 100644 index c5c45d7ec0df..000000000000 --- a/Documentation/timers/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hpet_example diff --git a/Documentation/timers/Makefile b/Documentation/timers/Makefile deleted file mode 100644 index 6c09ee6ca721..000000000000 --- a/Documentation/timers/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# List of programs to build -hostprogs-$(CONFIG_X86) := hpet_example - -# Tell kbuild to always build the programs -always := $(hostprogs-y) diff --git a/Documentation/timers/hpet.txt b/Documentation/timers/hpet.txt index a484d2c109d7..895345ec513b 100644 --- a/Documentation/timers/hpet.txt +++ b/Documentation/timers/hpet.txt @@ -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 diff --git a/Documentation/timers/hpet_example.c b/Documentation/timers/hpet_example.c deleted file mode 100644 index 3ab4993d85e0..000000000000 --- a/Documentation/timers/hpet_example.c +++ /dev/null @@ -1,294 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -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 -#include - -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; -} diff --git a/samples/timers/.gitignore b/samples/timers/.gitignore new file mode 100644 index 000000000000..c5c45d7ec0df --- /dev/null +++ b/samples/timers/.gitignore @@ -0,0 +1 @@ +hpet_example diff --git a/samples/timers/Makefile b/samples/timers/Makefile new file mode 100644 index 000000000000..a5c3c4a35ca1 --- /dev/null +++ b/samples/timers/Makefile @@ -0,0 +1,15 @@ +ifndef CROSS_COMPILE +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) + +ifeq ($(ARCH),x86) +CC := $(CROSS_COMPILE)gcc +PROGS := hpet_example + +all: $(PROGS) + +clean: + rm -fr $(PROGS) + +endif +endif diff --git a/samples/timers/hpet_example.c b/samples/timers/hpet_example.c new file mode 100644 index 000000000000..3ab4993d85e0 --- /dev/null +++ b/samples/timers/hpet_example.c @@ -0,0 +1,294 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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 +#include + +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; +} -- cgit v1.2.3 From 071bf69a0220253a44acb8b2a27f7a262b9a46bf Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 16 Sep 2016 17:40:40 -0600 Subject: samples: move watchdog example code from Documentation Move watchdog examples to samples and remove it from Documentation Makefile. Create a new Makefile to build watchdog. It can be built from top level directory or from watchdog directory: Run make -C samples/watchdog or cd samples/watchdog; make Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/watchdog/Makefile | 1 - Documentation/watchdog/src/.gitignore | 1 - Documentation/watchdog/src/Makefile | 5 ----- Documentation/watchdog/src/watchdog-simple.c | 24 ------------------------ Documentation/watchdog/watchdog-api.txt | 2 +- Documentation/watchdog/wdt.txt | 2 +- samples/watchdog/.gitignore | 1 + samples/watchdog/Makefile | 8 ++++++++ samples/watchdog/watchdog-simple.c | 24 ++++++++++++++++++++++++ 10 files changed, 36 insertions(+), 34 deletions(-) delete mode 100644 Documentation/watchdog/Makefile delete mode 100644 Documentation/watchdog/src/.gitignore delete mode 100644 Documentation/watchdog/src/Makefile delete mode 100644 Documentation/watchdog/src/watchdog-simple.c create mode 100644 samples/watchdog/.gitignore create mode 100644 samples/watchdog/Makefile create mode 100644 samples/watchdog/watchdog-simple.c (limited to 'samples') diff --git a/Documentation/Makefile b/Documentation/Makefile index fc386b7a01b2..b2210b7af2e5 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ subdir-y := accounting auxdisplay blackfin \ - laptops pcmcia watchdog + laptops pcmcia diff --git a/Documentation/watchdog/Makefile b/Documentation/watchdog/Makefile deleted file mode 100644 index 6018f45f2471..000000000000 --- a/Documentation/watchdog/Makefile +++ /dev/null @@ -1 +0,0 @@ -subdir-y := src diff --git a/Documentation/watchdog/src/.gitignore b/Documentation/watchdog/src/.gitignore deleted file mode 100644 index ff0ebb540333..000000000000 --- a/Documentation/watchdog/src/.gitignore +++ /dev/null @@ -1 +0,0 @@ -watchdog-simple diff --git a/Documentation/watchdog/src/Makefile b/Documentation/watchdog/src/Makefile deleted file mode 100644 index 47be791827d4..000000000000 --- a/Documentation/watchdog/src/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# List of programs to build -hostprogs-y := watchdog-simple - -# Tell kbuild to always build the programs -always := $(hostprogs-y) diff --git a/Documentation/watchdog/src/watchdog-simple.c b/Documentation/watchdog/src/watchdog-simple.c deleted file mode 100644 index ba45803a2216..000000000000 --- a/Documentation/watchdog/src/watchdog-simple.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include -#include - -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; -} diff --git a/Documentation/watchdog/watchdog-api.txt b/Documentation/watchdog/watchdog-api.txt index b3a701f48118..0e62ba33b7fb 100644 --- a/Documentation/watchdog/watchdog-api.txt +++ b/Documentation/watchdog/watchdog-api.txt @@ -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. diff --git a/Documentation/watchdog/wdt.txt b/Documentation/watchdog/wdt.txt index 061c2e35384f..ed2f0b860869 100644 --- a/Documentation/watchdog/wdt.txt +++ b/Documentation/watchdog/wdt.txt @@ -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 diff --git a/samples/watchdog/.gitignore b/samples/watchdog/.gitignore new file mode 100644 index 000000000000..ff0ebb540333 --- /dev/null +++ b/samples/watchdog/.gitignore @@ -0,0 +1 @@ +watchdog-simple diff --git a/samples/watchdog/Makefile b/samples/watchdog/Makefile new file mode 100644 index 000000000000..9b53d89b1ccf --- /dev/null +++ b/samples/watchdog/Makefile @@ -0,0 +1,8 @@ +CC := $(CROSS_COMPILE)gcc +PROGS := watchdog-simple + +all: $(PROGS) + +clean: + rm -fr $(PROGS) + diff --git a/samples/watchdog/watchdog-simple.c b/samples/watchdog/watchdog-simple.c new file mode 100644 index 000000000000..ba45803a2216 --- /dev/null +++ b/samples/watchdog/watchdog-simple.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +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; +} -- cgit v1.2.3 From 8fc07ebe63a40c312730da28e54dbb4fc6029ca3 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Fri, 16 Sep 2016 07:36:21 -0600 Subject: samples: move auxdisplay example code from Documentation Move auxdisplay examples to samples and remove it from Documentation Makefile. Create a new Makefile to build auxdisplay. It can be built from top level directory or from auxdisplay directory: Run make -C samples/auxdisplay or cd samples/auxdisplay; make Acked-by: Jonathan Corbet Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/auxdisplay/.gitignore | 1 - Documentation/auxdisplay/Makefile | 7 - Documentation/auxdisplay/cfag12864b | 2 +- Documentation/auxdisplay/cfag12864b-example.c | 281 -------------------------- samples/auxdisplay/.gitignore | 1 + samples/auxdisplay/Makefile | 9 + samples/auxdisplay/cfag12864b-example.c | 281 ++++++++++++++++++++++++++ 8 files changed, 293 insertions(+), 291 deletions(-) delete mode 100644 Documentation/auxdisplay/.gitignore delete mode 100644 Documentation/auxdisplay/Makefile delete mode 100644 Documentation/auxdisplay/cfag12864b-example.c create mode 100644 samples/auxdisplay/.gitignore create mode 100644 samples/auxdisplay/Makefile create mode 100644 samples/auxdisplay/cfag12864b-example.c (limited to 'samples') diff --git a/Documentation/Makefile b/Documentation/Makefile index b2210b7af2e5..0b8cd503224c 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1,2 +1,2 @@ -subdir-y := accounting auxdisplay blackfin \ +subdir-y := accounting blackfin \ laptops pcmcia diff --git a/Documentation/auxdisplay/.gitignore b/Documentation/auxdisplay/.gitignore deleted file mode 100644 index 7af222860a96..000000000000 --- a/Documentation/auxdisplay/.gitignore +++ /dev/null @@ -1 +0,0 @@ -cfag12864b-example diff --git a/Documentation/auxdisplay/Makefile b/Documentation/auxdisplay/Makefile deleted file mode 100644 index ada4dac99ef4..000000000000 --- a/Documentation/auxdisplay/Makefile +++ /dev/null @@ -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 diff --git a/Documentation/auxdisplay/cfag12864b b/Documentation/auxdisplay/cfag12864b index eb7be393a510..12fd51b8de75 100644 --- a/Documentation/auxdisplay/cfag12864b +++ b/Documentation/auxdisplay/cfag12864b @@ -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. diff --git a/Documentation/auxdisplay/cfag12864b-example.c b/Documentation/auxdisplay/cfag12864b-example.c deleted file mode 100644 index e7823ffb1ca0..000000000000 --- a/Documentation/auxdisplay/cfag12864b-example.c +++ /dev/null @@ -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 -#include -#include -#include -#include -#include - -#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 - -#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; -} diff --git a/samples/auxdisplay/.gitignore b/samples/auxdisplay/.gitignore new file mode 100644 index 000000000000..7af222860a96 --- /dev/null +++ b/samples/auxdisplay/.gitignore @@ -0,0 +1 @@ +cfag12864b-example diff --git a/samples/auxdisplay/Makefile b/samples/auxdisplay/Makefile new file mode 100644 index 000000000000..05e471feb6e5 --- /dev/null +++ b/samples/auxdisplay/Makefile @@ -0,0 +1,9 @@ +CC := $(CROSS_COMPILE)gcc +CFLAGS := -I../../usr/include + +PROGS := cfag12864b-example + +all: $(PROGS) + +clean: + rm -fr $(PROGS) diff --git a/samples/auxdisplay/cfag12864b-example.c b/samples/auxdisplay/cfag12864b-example.c new file mode 100644 index 000000000000..e7823ffb1ca0 --- /dev/null +++ b/samples/auxdisplay/cfag12864b-example.c @@ -0,0 +1,281 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#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 + +#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; +} -- cgit v1.2.3 From 184892925118d924aa9304b466946ae18c029932 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Thu, 6 Oct 2016 16:00:50 -0600 Subject: samples: move blackfin gptimers-example from Documentation Move blackfin gptimers-example to samples and remove it from Documentation Makefile. Update samples Kconfig and Makefile to build gptimers-example. blackfin is the last CONFIG_BUILD_DOCSRC target in Documentation/Makefile. Hence this patch also includes changes to remove CONFIG_BUILD_DOCSRC from Makefile and lib/Kconfig.debug and updates VIDEO_PCI_SKELETON dependency on BUILD_DOCSRC. Documentation/Makefile is not deleted to avoid braking make htmldocs and make distclean. Acked-by: Michal Marek Acked-by: Jonathan Corbet Reviewed-by: Kees Cook Reported-by: Valentin Rothberg Reported-by: Paul Gortmaker Signed-off-by: Shuah Khan --- Documentation/Makefile | 2 +- Documentation/blackfin/00-INDEX | 4 -- Documentation/blackfin/Makefile | 5 -- Documentation/blackfin/gptimers-example.c | 91 ------------------------------- Makefile | 3 - drivers/media/v4l2-core/Kconfig | 2 +- lib/Kconfig.debug | 9 --- samples/Kconfig | 6 ++ samples/Makefile | 2 +- samples/blackfin/Makefile | 1 + samples/blackfin/gptimers-example.c | 91 +++++++++++++++++++++++++++++++ 11 files changed, 101 insertions(+), 115 deletions(-) delete mode 100644 Documentation/blackfin/Makefile delete mode 100644 Documentation/blackfin/gptimers-example.c create mode 100644 samples/blackfin/Makefile create mode 100644 samples/blackfin/gptimers-example.c (limited to 'samples') diff --git a/Documentation/Makefile b/Documentation/Makefile index 84359654cfcb..c2a469112c37 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -1 +1 @@ -subdir-y := blackfin +subdir-y := diff --git a/Documentation/blackfin/00-INDEX b/Documentation/blackfin/00-INDEX index c54fcdd4ae9f..265a1effebde 100644 --- a/Documentation/blackfin/00-INDEX +++ b/Documentation/blackfin/00-INDEX @@ -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 diff --git a/Documentation/blackfin/Makefile b/Documentation/blackfin/Makefile deleted file mode 100644 index 6782c58fbc29..000000000000 --- a/Documentation/blackfin/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -ifneq ($(CONFIG_BLACKFIN),) -ifneq ($(CONFIG_BFIN_GPTIMERS),) -obj-m := gptimers-example.o -endif -endif diff --git a/Documentation/blackfin/gptimers-example.c b/Documentation/blackfin/gptimers-example.c deleted file mode 100644 index 283eba993d9d..000000000000 --- a/Documentation/blackfin/gptimers-example.c +++ /dev/null @@ -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 -#include - -#include -#include - -/* ... 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"); diff --git a/Makefile b/Makefile index 70de1448c571..92b38ac151a2 100644 --- a/Makefile +++ b/Makefile @@ -933,9 +933,6 @@ vmlinux_prereq: $(vmlinux-deps) FORCE ifdef CONFIG_HEADERS_CHECK $(Q)$(MAKE) -f $(srctree)/Makefile headers_check endif -ifdef CONFIG_BUILD_DOCSRC - $(Q)$(MAKE) $(build)=Documentation -endif ifdef CONFIG_GDB_SCRIPTS $(Q)ln -fsn `cd $(srctree) && /bin/pwd`/scripts/gdb/vmlinux-gdb.py endif diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 29b3436d0910..367523a3c774 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -27,7 +27,7 @@ config VIDEO_FIXED_MINOR_RANGES config VIDEO_PCI_SKELETON tristate "Skeleton PCI V4L2 driver" - depends on PCI && BUILD_DOCSRC + depends on PCI depends on VIDEO_V4L2 && VIDEOBUF2_CORE depends on VIDEOBUF2_MEMOPS && VIDEOBUF2_DMA_CONTIG ---help--- diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 2307d7c89dac..a6620838afc3 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1875,15 +1875,6 @@ config PROVIDE_OHCI1394_DMA_INIT See Documentation/debugging-via-ohci1394.txt for more information. -config BUILD_DOCSRC - bool "Build targets in Documentation/ tree" - depends on HEADERS_CHECK - help - This option attempts to build objects from the source files in the - kernel Documentation/ tree. - - Say N if you are unsure. - config DMA_API_DEBUG bool "Enable debugging of DMA-API usage" depends on HAVE_DMA_API_DEBUG diff --git a/samples/Kconfig b/samples/Kconfig index 85c405fcccb0..a6d2a43bbf2e 100644 --- a/samples/Kconfig +++ b/samples/Kconfig @@ -99,4 +99,10 @@ config SAMPLE_SECCOMP Build samples of seccomp filters using various methods of BPF filter construction. +config SAMPLE_BLACKFIN_GPTIMERS + tristate "Build blackfin gptimers sample code -- loadable modules only" + depends on BLACKFIN && BFIN_GPTIMERS && m + help + Build samples of blackfin gptimers sample module. + endif # SAMPLES diff --git a/samples/Makefile b/samples/Makefile index 1a20169d85ac..e17d66d77f09 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -2,4 +2,4 @@ obj-$(CONFIG_SAMPLES) += kobject/ kprobes/ trace_events/ livepatch/ \ hw_breakpoint/ kfifo/ kdb/ hidraw/ rpmsg/ seccomp/ \ - configfs/ connector/ v4l/ trace_printk/ + configfs/ connector/ v4l/ trace_printk/ blackfin/ diff --git a/samples/blackfin/Makefile b/samples/blackfin/Makefile new file mode 100644 index 000000000000..89b86cfd83a2 --- /dev/null +++ b/samples/blackfin/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_SAMPLE_BLACKFIN_GPTIMERS) += gptimers-example.o diff --git a/samples/blackfin/gptimers-example.c b/samples/blackfin/gptimers-example.c new file mode 100644 index 000000000000..283eba993d9d --- /dev/null +++ b/samples/blackfin/gptimers-example.c @@ -0,0 +1,91 @@ +/* + * 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 +#include + +#include +#include + +/* ... 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"); -- cgit v1.2.3 From 96a8eb1eeed2c3485cdba198fab3a2faaec386d3 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 26 Oct 2016 00:37:53 +0200 Subject: bpf: fix samples to add fake KBUILD_MODNAME Some of the sample files are causing issues when they are loaded with tc and cls_bpf, meaning tc bails out while trying to parse the resulting ELF file as program/map/etc sections are not present, which can be easily spotted with readelf(1). Currently, BPF samples are including some of the kernel headers and mid term we should change them to refrain from this, really. When dynamic debugging is enabled, we bail out due to undeclared KBUILD_MODNAME, which is easily overlooked in the build as clang spills this along with other noisy warnings from various header includes, and llc still generates an ELF file with mentioned characteristics. For just playing around with BPF examples, this can be a bit of a hurdle to take. Just add a fake KBUILD_MODNAME as a band-aid to fix the issue, same is done in xdp*_kern samples already. Fixes: 65d472fb007d ("samples/bpf: add 'pointer to packet' tests") Fixes: 6afb1e28b859 ("samples/bpf: Add tunnel set/get tests.") Fixes: a3f74617340b ("cgroup: bpf: Add an example to do cgroup checking in BPF") Reported-by: Chandrasekar Kannan Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- samples/bpf/parse_ldabs.c | 1 + samples/bpf/parse_simple.c | 1 + samples/bpf/parse_varlen.c | 1 + samples/bpf/tcbpf1_kern.c | 1 + samples/bpf/tcbpf2_kern.c | 1 + samples/bpf/test_cgrp2_tc_kern.c | 1 + 6 files changed, 6 insertions(+) (limited to 'samples') diff --git a/samples/bpf/parse_ldabs.c b/samples/bpf/parse_ldabs.c index d17550198d06..6db6b21fdc6d 100644 --- a/samples/bpf/parse_ldabs.c +++ b/samples/bpf/parse_ldabs.c @@ -4,6 +4,7 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ +#define KBUILD_MODNAME "foo" #include #include #include diff --git a/samples/bpf/parse_simple.c b/samples/bpf/parse_simple.c index cf2511c33905..10af53d33cc2 100644 --- a/samples/bpf/parse_simple.c +++ b/samples/bpf/parse_simple.c @@ -4,6 +4,7 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ +#define KBUILD_MODNAME "foo" #include #include #include diff --git a/samples/bpf/parse_varlen.c b/samples/bpf/parse_varlen.c index edab34dce79b..95c16324760c 100644 --- a/samples/bpf/parse_varlen.c +++ b/samples/bpf/parse_varlen.c @@ -4,6 +4,7 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ +#define KBUILD_MODNAME "foo" #include #include #include diff --git a/samples/bpf/tcbpf1_kern.c b/samples/bpf/tcbpf1_kern.c index fa051b3d53ee..274c884c87fe 100644 --- a/samples/bpf/tcbpf1_kern.c +++ b/samples/bpf/tcbpf1_kern.c @@ -1,3 +1,4 @@ +#define KBUILD_MODNAME "foo" #include #include #include diff --git a/samples/bpf/tcbpf2_kern.c b/samples/bpf/tcbpf2_kern.c index 3303bb85593b..9c823a609e75 100644 --- a/samples/bpf/tcbpf2_kern.c +++ b/samples/bpf/tcbpf2_kern.c @@ -5,6 +5,7 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ +#define KBUILD_MODNAME "foo" #include #include #include diff --git a/samples/bpf/test_cgrp2_tc_kern.c b/samples/bpf/test_cgrp2_tc_kern.c index 10ff73404e3a..1547b36a7b7b 100644 --- a/samples/bpf/test_cgrp2_tc_kern.c +++ b/samples/bpf/test_cgrp2_tc_kern.c @@ -4,6 +4,7 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ +#define KBUILD_MODNAME "foo" #include #include #include -- cgit v1.2.3