...
 
Commits (13)
......@@ -33,6 +33,7 @@ struct rtdm_gpio_pin {
rtdm_event_t event;
char *name;
struct gpio_desc *desc;
nanosecs_abs_t timestamp;
};
struct rtdm_gpio_chip {
......
......@@ -18,12 +18,18 @@
#ifndef _RTDM_UAPI_GPIO_H
#define _RTDM_UAPI_GPIO_H
#define GPIO_RTIOC_DIR_OUT _IOW(RTDM_CLASS_GPIO, 0, int)
#define GPIO_RTIOC_DIR_IN _IO(RTDM_CLASS_GPIO, 1)
#define GPIO_RTIOC_IRQEN _IOW(RTDM_CLASS_GPIO, 2, int) /* GPIO trigger */
#define GPIO_RTIOC_IRQDIS _IO(RTDM_CLASS_GPIO, 3)
#define GPIO_RTIOC_REQS _IO(RTDM_CLASS_GPIO, 4)
#define GPIO_RTIOC_RELS _IO(RTDM_CLASS_GPIO, 5)
struct rtdm_gpio_readout {
nanosecs_abs_t timestamp;
__s32 value;
};
#define GPIO_RTIOC_DIR_OUT _IOW(RTDM_CLASS_GPIO, 0, int)
#define GPIO_RTIOC_DIR_IN _IO(RTDM_CLASS_GPIO, 1)
#define GPIO_RTIOC_IRQEN _IOW(RTDM_CLASS_GPIO, 2, int) /* GPIO trigger */
#define GPIO_RTIOC_IRQDIS _IO(RTDM_CLASS_GPIO, 3)
#define GPIO_RTIOC_REQS _IO(RTDM_CLASS_GPIO, 4)
#define GPIO_RTIOC_RELS _IO(RTDM_CLASS_GPIO, 5)
#define GPIO_RTIOC_TS _IOR(RTDM_CLASS_GPIO, 7, int)
#define GPIO_TRIGGER_NONE 0x0 /* unspecified */
#define GPIO_TRIGGER_EDGE_RISING 0x1
......
......@@ -28,7 +28,8 @@ struct rtdm_gpio_chan {
int requested : 1,
has_direction : 1,
is_output : 1,
is_interrupt : 1;
is_interrupt : 1,
want_timestamp : 1;
};
static LIST_HEAD(rtdm_gpio_chips);
......@@ -41,6 +42,7 @@ static int gpio_pin_interrupt(rtdm_irq_t *irqh)
pin = rtdm_irq_get_arg(irqh, struct rtdm_gpio_pin);
pin->timestamp = rtdm_clock_read_monotonic();
rtdm_event_signal(&pin->event);
return RTDM_IRQ_HANDLED;
......@@ -187,6 +189,12 @@ static int gpio_pin_ioctl_nrt(struct rtdm_fd *fd,
gpio_free(gpio);
chan->requested = false;
break;
case GPIO_RTIOC_TS:
ret = rtdm_safe_copy_from_user(fd, &val, arg, sizeof(val));
if (ret)
return ret;
chan->want_timestamp = !!val;
break;
default:
return -EINVAL;
}
......@@ -199,11 +207,9 @@ static ssize_t gpio_pin_read_rt(struct rtdm_fd *fd,
{
struct rtdm_gpio_chan *chan = rtdm_fd_to_private(fd);
struct rtdm_device *dev = rtdm_fd_device(fd);
struct rtdm_gpio_readout rdo;
struct rtdm_gpio_pin *pin;
int value, ret;
if (len < sizeof(value))
return -EINVAL;
int ret;
if (!chan->has_direction)
return -EAGAIN;
......@@ -213,16 +219,37 @@ static ssize_t gpio_pin_read_rt(struct rtdm_fd *fd,
pin = container_of(dev, struct rtdm_gpio_pin, dev);
if (!(fd->oflags & O_NONBLOCK)) {
ret = rtdm_event_wait(&pin->event);
if (ret)
return ret;
}
if (chan->want_timestamp) {
if (len < sizeof(rdo))
return -EINVAL;
if (!(fd->oflags & O_NONBLOCK)) {
ret = rtdm_event_wait(&pin->event);
if (ret)
return ret;
rdo.timestamp = pin->timestamp;
} else
rdo.timestamp = rtdm_clock_read_monotonic();
len = sizeof(rdo);
rdo.value = gpiod_get_raw_value(pin->desc);
ret = rtdm_safe_copy_to_user(fd, buf, &rdo, len);
} else {
if (len < sizeof(rdo.value))
return -EINVAL;
value = gpiod_get_raw_value(pin->desc);
ret = rtdm_safe_copy_to_user(fd, buf, &value, sizeof(value));
if (!(fd->oflags & O_NONBLOCK)) {
ret = rtdm_event_wait(&pin->event);
if (ret)
return ret;
}
len = sizeof(rdo.value);
rdo.value = gpiod_get_raw_value(pin->desc);
ret = rtdm_safe_copy_to_user(fd, buf, &rdo.value, len);
}
return ret ?: sizeof(value);
return ret ?: len;
}
static ssize_t gpio_pin_write_rt(struct rtdm_fd *fd,
......@@ -462,6 +489,7 @@ int rtdm_gpiochip_post_event(struct rtdm_gpio_chip *rgc,
return -EINVAL;
pin = rgc->pins + offset;
pin->timestamp = rtdm_clock_read_monotonic();
rtdm_event_signal(&pin->event);
return 0;
......
......@@ -180,12 +180,21 @@ extern struct mutex rtnet_devices_nrt_lock;
extern struct rtnet_device *rtnet_devices[];
int __rt_init_etherdev(struct rtnet_device *rtdev,
unsigned int dev_pool_size,
struct module *module);
#define rt_init_etherdev(__rtdev, __dev_pool_size) \
__rt_init_etherdev(__rtdev, __dev_pool_size, THIS_MODULE)
struct rtnet_device *__rt_alloc_etherdev(unsigned sizeof_priv,
unsigned dev_pool_size,
struct module *module);
#define rt_alloc_etherdev(priv_size, rx_size) \
__rt_alloc_etherdev(priv_size, rx_size, THIS_MODULE)
void rtdev_destroy(struct rtnet_device *rtdev);
void rtdev_free(struct rtnet_device *rtdev);
int rt_register_rtnetdev(struct rtnet_device *rtdev);
......
......@@ -549,25 +549,26 @@ static int rt_udp_getfrag(const void *p, unsigned char *to,
unsigned int offset, unsigned int fraglen)
{
struct udpfakehdr *ufh = (struct udpfakehdr *)p;
int i, ret;
int ret;
// We should optimize this function a bit (copy+csum...)!
if (offset)
return rtnet_read_from_iov(ufh->fd, ufh->iov, ufh->iovlen, to, fraglen);
/* Checksum of the complete data part of the UDP message: */
for (i = 0; i < ufh->iovlen; i++) {
ufh->wcheck = csum_partial(ufh->iov[i].iov_base, ufh->iov[i].iov_len,
ufh->wcheck);
if (offset) {
ret = rtnet_read_from_iov(ufh->fd, ufh->iov, ufh->iovlen, to, fraglen);
return ret < 0 ? ret : 0;
}
ret = rtnet_read_from_iov(ufh->fd, ufh->iov, ufh->iovlen,
to + sizeof(struct udphdr),
fraglen - sizeof(struct udphdr));
if (ret)
if (ret < 0)
return ret;
/* Checksum of the complete data part of the UDP message: */
ufh->wcheck = csum_partial(to + sizeof(struct udphdr),
fraglen - sizeof(struct udphdr),
ufh->wcheck);
/* Checksum of the udp header: */
ufh->wcheck = csum_partial((unsigned char *)ufh,
sizeof(struct udphdr), ufh->wcheck);
......@@ -682,7 +683,7 @@ ssize_t rt_udp_sendmsg(struct rtdm_fd *fd, const struct user_msghdr *msg, int ms
ufh.uh.len = htons(ulen);
ufh.uh.check = 0;
ufh.fd = fd;
ufh.iov = msg->msg_iov;
ufh.iov = iov;
ufh.iovlen = msg->msg_iovlen;
ufh.wcheck = 0;
......
......@@ -45,6 +45,7 @@ struct rtnet_device *rtnet_devices[MAX_RT_DEVICES];
static struct rtnet_device *loopback_device;
static DEFINE_RTDM_LOCK(rtnet_devices_rt_lock);
static LIST_HEAD(rtskb_mapped_list);
static LIST_HEAD(rtskb_mapwait_list);
LIST_HEAD(event_hook_list);
DEFINE_MUTEX(rtnet_devices_nrt_lock);
......@@ -251,6 +252,39 @@ static const struct rtskb_pool_lock_ops rtdev_ops = {
.unlock = rtdev_pool_unlock,
};
int rtdev_init(struct rtnet_device *rtdev, unsigned dev_pool_size)
{
int ret;
ret = rtskb_pool_init(&rtdev->dev_pool, dev_pool_size, &rtdev_ops, rtdev);
if (ret < dev_pool_size) {
printk(KERN_ERR "RTnet: cannot allocate rtnet device pool\n");
rtskb_pool_release(&rtdev->dev_pool);
return -ENOMEM;
}
rtdm_mutex_init(&rtdev->xmit_mutex);
rtdm_lock_init(&rtdev->rtdev_lock);
mutex_init(&rtdev->nrt_lock);
atomic_set(&rtdev->refcount, 0);
/* scale global rtskb pool */
rtdev->add_rtskbs = rtskb_pool_extend(&global_pool, device_rtskbs);
return 0;
}
EXPORT_SYMBOL_GPL(rtdev_init);
void rtdev_destroy(struct rtnet_device *rtdev)
{
rtskb_pool_release(&rtdev->dev_pool);
rtskb_pool_shrink(&global_pool, rtdev->add_rtskbs);
rtdev->stack_event = NULL;
rtdm_mutex_destroy(&rtdev->xmit_mutex);
}
EXPORT_SYMBOL_GPL(rtdev_destroy);
/***
* rtdev_alloc
* @int sizeof_priv:
......@@ -267,70 +301,94 @@ struct rtnet_device *rtdev_alloc(unsigned sizeof_priv, unsigned dev_pool_size)
/* ensure 32-byte alignment of the private area */
alloc_size = sizeof (*rtdev) + sizeof_priv + 31;
rtdev = (struct rtnet_device *)kmalloc(alloc_size, GFP_KERNEL);
rtdev = kzalloc(alloc_size, GFP_KERNEL);
if (rtdev == NULL) {
printk(KERN_ERR "RTnet: cannot allocate rtnet device\n");
return NULL;
}
memset(rtdev, 0, alloc_size);
ret = rtskb_pool_init(&rtdev->dev_pool, dev_pool_size, &rtdev_ops, rtdev);
if (ret < dev_pool_size) {
printk(KERN_ERR "RTnet: cannot allocate rtnet device pool\n");
rtskb_pool_release(&rtdev->dev_pool);
ret = rtdev_init(rtdev, dev_pool_size);
if (ret) {
kfree(rtdev);
return NULL;
}
rtdm_mutex_init(&rtdev->xmit_mutex);
rtdm_lock_init(&rtdev->rtdev_lock);
mutex_init(&rtdev->nrt_lock);
atomic_set(&rtdev->refcount, 0);
/* scale global rtskb pool */
rtdev->add_rtskbs = rtskb_pool_extend(&global_pool, device_rtskbs);
if (sizeof_priv)
rtdev->priv = (void *)(((long)(rtdev + 1) + 31) & ~31);
return rtdev;
}
/***
* rtdev_free
*/
void rtdev_free (struct rtnet_device *rtdev)
{
if (rtdev != NULL) {
rtskb_pool_release(&rtdev->dev_pool);
rtskb_pool_shrink(&global_pool, rtdev->add_rtskbs);
rtdev->stack_event = NULL;
rtdm_mutex_destroy(&rtdev->xmit_mutex);
rtdev_destroy(rtdev);
kfree(rtdev);
}
}
EXPORT_SYMBOL_GPL(rtdev_free);
static void init_etherdev(struct rtnet_device *rtdev,
struct module *module)
{
rtdev->hard_header = rt_eth_header;
rtdev->type = ARPHRD_ETHER;
rtdev->hard_header_len = ETH_HLEN;
rtdev->mtu = 1500; /* eth_mtu */
rtdev->addr_len = ETH_ALEN;
rtdev->flags = IFF_BROADCAST; /* TODO: IFF_MULTICAST; */
rtdev->get_mtu = rt_hard_mtu;
rtdev->rt_owner = module;
memset(rtdev->broadcast, 0xFF, ETH_ALEN);
strcpy(rtdev->name, "rteth%d");
}
/**
* rt_init_etherdev - sets up an ethernet device
* @module: module initializing the device
*
* Fill in the fields of the device structure with ethernet-generic
* values. This routine can be used to set up a pre-allocated device
* structure. The device still needs to be registered afterwards.
*/
int __rt_init_etherdev(struct rtnet_device *rtdev,
unsigned dev_pool_size,
struct module *module)
{
int ret;
ret = rtdev_init(rtdev, dev_pool_size);
if (ret)
return ret;
init_etherdev(rtdev, module);
return 0;
}
EXPORT_SYMBOL_GPL(__rt_init_etherdev);
/**
* rtalloc_etherdev - Allocates and sets up an ethernet device
* rt_alloc_etherdev - Allocates and sets up an ethernet device
* @sizeof_priv: size of additional driver-private structure to
* be allocated for this ethernet device
* @dev_pool_size: size of the rx pool
* @module: module creating the deivce
* @module: module creating the device
*
* Fill in the fields of the device structure with ethernet-generic
* values. Basically does everything except registering the device.
* Allocates then fills in the fields of a new device structure with
* ethernet-generic values. Basically does everything except
* registering the device.
*
* A 32-byte alignment is enforced for the private data area.
*/
struct rtnet_device *__rt_alloc_etherdev(unsigned sizeof_priv,
unsigned dev_pool_size,
struct module *module)
unsigned dev_pool_size,
struct module *module)
{
struct rtnet_device *rtdev;
......@@ -338,21 +396,11 @@ struct rtnet_device *__rt_alloc_etherdev(unsigned sizeof_priv,
if (!rtdev)
return NULL;
rtdev->hard_header = rt_eth_header;
rtdev->type = ARPHRD_ETHER;
rtdev->hard_header_len = ETH_HLEN;
rtdev->mtu = 1500; /* eth_mtu */
rtdev->addr_len = ETH_ALEN;
rtdev->flags = IFF_BROADCAST; /* TODO: IFF_MULTICAST; */
rtdev->get_mtu = rt_hard_mtu;
rtdev->rt_owner = module;
memset(rtdev->broadcast, 0xFF, ETH_ALEN);
strcpy(rtdev->name, "rteth%d");
init_etherdev(rtdev, module);
return rtdev;
}
EXPORT_SYMBOL_GPL(__rt_alloc_etherdev);
static inline int __rtdev_new_index(void)
......@@ -412,8 +460,12 @@ int rtdev_map_rtskb(struct rtskb *skb)
}
}
if (!err && skb->buf_dma_addr != RTSKB_UNMAPPED)
list_add(&skb->entry, &rtskb_mapped_list);
if (!err) {
if (skb->buf_dma_addr != RTSKB_UNMAPPED)
list_add(&skb->entry, &rtskb_mapped_list);
else
list_add(&skb->entry, &rtskb_mapwait_list);
}
mutex_unlock(&rtnet_devices_nrt_lock);
......@@ -424,7 +476,7 @@ int rtdev_map_rtskb(struct rtskb *skb)
static int rtdev_map_all_rtskbs(struct rtnet_device *rtdev)
{
struct rtskb *skb;
struct rtskb *skb, *n;
int err = 0;
if (!rtdev->map_rtskb)
......@@ -436,6 +488,14 @@ static int rtdev_map_all_rtskbs(struct rtnet_device *rtdev)
break;
}
list_for_each_entry_safe(skb, n, &rtskb_mapwait_list, entry) {
err = rtskb_map(rtdev, skb);
if (err)
break;
list_del(&skb->entry);
list_add(&skb->entry, &rtskb_mapped_list);
}
return err;
}
......@@ -533,7 +593,7 @@ int rt_register_rtnetdev(struct rtnet_device *rtdev)
if (err)
goto fail_link;
}
err = rtdev_map_all_rtskbs(rtdev);
if (err)
goto fail_map;
......@@ -907,9 +967,6 @@ unsigned int rt_hard_mtu(struct rtnet_device *rtdev, unsigned int priority)
}
EXPORT_SYMBOL_GPL(__rt_alloc_etherdev);
EXPORT_SYMBOL_GPL(rtdev_free);
EXPORT_SYMBOL_GPL(rtdev_alloc_name);
EXPORT_SYMBOL_GPL(rt_register_rtnetdev);
......
......@@ -156,10 +156,11 @@ static struct rtskb *__rtskb_pool_dequeue(struct rtskb_pool *pool)
struct rtskb_queue *queue = &pool->queue;
struct rtskb *skb;
if (!pool->lock_ops->trylock(pool->lock_cookie))
if (pool->lock_ops &&
!pool->lock_ops->trylock(pool->lock_cookie))
return NULL;
skb = __rtskb_dequeue(queue);
if (skb == NULL)
if (skb == NULL && pool->lock_ops)
pool->lock_ops->unlock(pool->lock_cookie);
return skb;
......@@ -184,7 +185,8 @@ static void __rtskb_pool_queue_tail(struct rtskb_pool *pool, struct rtskb *skb)
struct rtskb_queue *queue = &pool->queue;
__rtskb_queue_tail(queue,skb);
pool->lock_ops->unlock(pool->lock_cookie);
if (pool->lock_ops)
pool->lock_ops->unlock(pool->lock_cookie);
}
void rtskb_pool_queue_tail(struct rtskb_pool *pool, struct rtskb *skb)
......@@ -223,6 +225,7 @@ struct rtskb *alloc_rtskb(unsigned int size, struct rtskb_pool *pool)
skb->len = 0;
skb->pkt_type = PACKET_HOST;
skb->xmit_stamp = NULL;
skb->ip_summed = CHECKSUM_NONE;
#if IS_ENABLED(CONFIG_XENO_DRIVERS_NET_ADDON_RTCAP)
skb->cap_flags = 0;
......@@ -291,21 +294,6 @@ void kfree_rtskb(struct rtskb *skb)
EXPORT_SYMBOL_GPL(kfree_rtskb);
static int rtskb_nop_pool_trylock(void *cookie)
{
return 1;
}
static void rtskb_nop_pool_unlock(void *cookie)
{
}
static const struct rtskb_pool_lock_ops rtskb_nop_pool_lock_ops = {
.trylock = rtskb_nop_pool_trylock,
.unlock = rtskb_nop_pool_unlock,
};
/***
* rtskb_pool_init
* @pool: pool to be initialized
......@@ -327,7 +315,7 @@ unsigned int rtskb_pool_init(struct rtskb_pool *pool,
if (rtskb_pools > rtskb_pools_max)
rtskb_pools_max = rtskb_pools;
pool->lock_ops = lock_ops ?: &rtskb_nop_pool_lock_ops;
pool->lock_ops = lock_ops;
pool->lock_cookie = lock_cookie;
return i;
......
......@@ -1579,8 +1579,8 @@ static int rt_imx_uart_probe(struct platform_device *pdev)
if (IS_ERR(port->clk_per))
return PTR_ERR(port->clk_per);
clk_enable(port->clk_ipg);
clk_enable(port->clk_per);
clk_prepare_enable(port->clk_ipg);
clk_prepare_enable(port->clk_per);
port->uartclk = clk_get_rate(port->clk_per);
port->use_hwflow = 1;
......@@ -1605,6 +1605,8 @@ static int rt_imx_uart_remove(struct platform_device *pdev)
pdata = pdev->dev.platform_data;
platform_set_drvdata(pdev, NULL);
clk_disable_unprepare(port->clk_ipg);
clk_disable_unprepare(port->clk_per);
rtdm_dev_unregister(dev);
return 0;
......
......@@ -28,6 +28,7 @@
#include <fcntl.h>
#include <smokey/smokey.h>
#include <rtdm/gpio.h>
#include <boilerplate/time.h>
smokey_test_plugin(interrupt,
SMOKEY_ARGLIST(
......@@ -39,6 +40,7 @@ smokey_test_plugin(interrupt,
"\tdevice=<device-path>\n"
"\trigger={edge[-rising/falling/both], level[-low/high]}\n"
"\tselect, wait on select(2)."
"\ttimestamp, enable timestamping."
);
smokey_test_plugin(read_value,
......@@ -72,8 +74,10 @@ static int run_interrupt(struct smokey_test *t, int argc, char *const argv[])
{ .name = "level-high", .flag = GPIO_TRIGGER_LEVEL_HIGH },
{ NULL, 0 },
};
int do_select = 0, fd, ret, trigger, n, value;
int do_select = 0, fd, ret, trigger, n, value, do_timestamp = 0;
const char *device = NULL, *trigname;
struct rtdm_gpio_readout rdo;
struct timespec now;
fd_set set;
smokey_parse_args(t, argc, argv);
......@@ -95,6 +99,9 @@ static int run_interrupt(struct smokey_test *t, int argc, char *const argv[])
if (SMOKEY_ARG_ISSET(interrupt, select))
do_select = SMOKEY_ARG_BOOL(interrupt, select);
if (SMOKEY_ARG_ISSET(interrupt, timestamp))
do_timestamp = SMOKEY_ARG_BOOL(interrupt, timestamp);
trigger = GPIO_TRIGGER_NONE;
if (SMOKEY_ARG_ISSET(interrupt, trigger)) {
trigname = SMOKEY_ARG_STRING(interrupt, trigger);
......@@ -131,14 +138,28 @@ static int run_interrupt(struct smokey_test *t, int argc, char *const argv[])
return ret;
}
}
ret = read(fd, &value, sizeof(value));
if (ret < 0) {
ret = -errno;
warning("failed reading from %s [%s]",
device, symerror(ret));
return ret;
if (do_timestamp) {
ret = read(fd, &rdo, sizeof(rdo));
if (ret < 0) {
ret = -errno;
warning("failed reading from %s [%s]",
device, symerror(ret));
return ret;
}
clock_gettime(CLOCK_MONOTONIC, &now);
printf("received irq %llu us from now, GPIO state=%d\n",
(timespec_scalar(&now) - rdo.timestamp) / 1000ULL,
rdo.value);
} else {
ret = read(fd, &value, sizeof(value));
if (ret < 0) {
ret = -errno;
warning("failed reading from %s [%s]",
device, symerror(ret));
return ret;
}
printf("received irq, GPIO state=%d\n", value);
}
printf("received irq, GPIO state=%d\n", value);
}
close(fd);
......
......@@ -17,7 +17,7 @@ static pthread_t tid;
static unsigned long long glost, glate;
static int rcv_packet(struct smokey_net_client *client, int sock, unsigned seq,
struct timespec *next_shot, bool last)
struct timespec *next_shot, bool last, int *linesout)
{
static unsigned long long gmin = ~0ULL, gmax = 0, gsum = 0, gcount = 0;
static unsigned long long min = ~0ULL, max = 0, sum = 0, count = 0,
......@@ -115,16 +115,19 @@ static int rcv_packet(struct smokey_net_client *client, int sock, unsigned seq,
glost += lost - late;
glate += late;
smokey_trace("%g pps\t%Lu\t%Lu\t%.03gus\t%.03gus\t%.03gus\t"
"| %Lu\t%Lu\t%.03gus\t%.03gus\t%.03gus",
if (((*linesout)++ % 20) == 0) {
smokey_trace("\n %-7s%6s%8s%8s%8s%8s%8s%10s",
"PPS", "LOST", "LATE", "MIN", "MAX",
"BEST", "AVG", "WORST");
smokey_trace("------------------------------------------------------------------");
}
smokey_trace("%8.2f %6Ld %6Ld %.03g %.03g %.03g %.03g %.03g",
count / (diff / 1000000000.0),
lost - late,
late,
count ? min / 1000.0 : 0,
count ? (sum / (double)count) / 1000 : 0,
count ? max / 1000.0 : 0,
glost,
glate,
count ? min / 1000.0 : 0,
count ? max / 1000.0 : 0,
gcount ? gmin / 1000.0 : 0,
gcount ? (gsum / (double)gcount) / 1000 : 0,
gcount ? gmax / 1000.0 : 0);
......@@ -143,11 +146,11 @@ static int rcv_packet(struct smokey_net_client *client, int sock, unsigned seq,
static int smokey_net_client_loop(struct smokey_net_client *client)
{
struct smokey_net_payload payload;
int sock, err, linesout = 0;
struct timespec next_shot;
struct sched_param prio;
char packet[256];
long long limit;
int sock, err;
sock = client->create_socket(client);
if (sock < 0)
......@@ -164,6 +167,9 @@ static int smokey_net_client_loop(struct smokey_net_client *client)
if (err < 0)
goto err;
smokey_trace("\nPPS, LOST, LATE: packet count");
smokey_trace("MIN, MAX, BEST, AVG, WORST: microseconds");
limit = (long long)rate * duration;
for (payload.seq = 1;
limit <= 0 || payload.seq < limit + 1; payload.seq++) {
......@@ -192,7 +198,7 @@ static int smokey_net_client_loop(struct smokey_net_client *client)
do {
err = rcv_packet(client, sock, seq, &next_shot,
payload.seq == limit);
payload.seq == limit, &linesout);
if (!err)
seq = 0;
} while (err != -ETIMEDOUT);
......
......@@ -28,6 +28,7 @@
struct module {
int option;
const char *name;
bool loaded;
};
#define TIMEOUT 10
......@@ -35,8 +36,17 @@ struct module {
static struct rtnet_core_cmd cmd;
static int fd;
static pthread_t loopback_server_tid;
static bool loopback_thread_created;
static bool loopback_thread_created, ifup;
static struct module modules[] = {
{
.name = "rtnet",
},
{
.name = "rtipv4",
},
{
.name = "rtcfg",
},
{
.option = _CC_COBALT_NET_UDP,
.name = "rtudp",
......@@ -45,9 +55,19 @@ static struct module modules[] = {
.option = _CC_COBALT_NET_AF_PACKET,
.name = "rtpacket",
},
{
.name = NULL, /* driver */
},
};
static const char *option_to_module(int option)
#define MODID_RTNET 0
#define MODID_IPV4 1
#define MODID_CFG 2
#define MODID_UDP 3
#define MODID_PACKET 4
#define MODID_DRIVER 5
static int option_to_modid(int option)
{
unsigned i;
......@@ -55,10 +75,10 @@ static const char *option_to_module(int option)
if (modules[i].option != option)
continue;
return modules[i].name;
return i;
}
return NULL;
return -1;
}
static int get_info(const char *intf)
......@@ -118,13 +138,37 @@ static int do_down(const char *intf)
return 0;
}
static int smokey_net_modprobe(const char *mod)
static int smokey_net_modprobe(int modid)
{
struct module *m = modules + modid;
char buffer[128];
int err;
int err, len;
FILE *fp;
if (modid < 0)
return -EINVAL;
fp = fopen("/proc/modules", "r");
if (fp == NULL)
return -errno;
len = strlen(m->name);
while (fgets(buffer, sizeof(buffer), fp)) {
if (strncmp(buffer, m->name, len) == 0 &&
len < sizeof(buffer) && buffer[len] == ' ') {
smokey_trace("%s module already loaded", m->name);
fclose(fp);
return 0;
}
}
fclose(fp);
smokey_trace("%s module not there: modprobing", m->name);
err = smokey_check_errno(
snprintf(buffer, sizeof(buffer), "modprobe %s", mod));
snprintf(buffer, sizeof(buffer), "modprobe %s", m->name));
if (err < 0)
return err;
......@@ -137,16 +181,26 @@ static int smokey_net_modprobe(const char *mod)
return -EINVAL;
}
m->loaded = true;
return err;
}
static int smokey_net_rmmod(const char *mod)
static int smokey_net_rmmod(int modid)
{
struct module *m = modules + modid;
char buffer[128];
int err;
if (!m->loaded) {
smokey_trace("%s module was there on entry, keeping it", m->name);
return 0;
}
smokey_trace("unloading %s module", m->name);
err = smokey_check_errno(
snprintf(buffer, sizeof(buffer), "rmmod %s", mod));
snprintf(buffer, sizeof(buffer), "rmmod %s", m->name));
if (err < 0)
return err;
......@@ -170,7 +224,7 @@ static int smokey_net_setup_rtcfg_client(const char *intf, int net_config)
if ((net_config & _CC_COBALT_NET_CFG) == 0)
return -ENOSYS;
err = smokey_net_modprobe("rtcfg");
err = smokey_net_modprobe(MODID_CFG);
if (err < 0)
return err;
......@@ -213,11 +267,13 @@ static int smokey_net_teardown_rtcfg(const char *intf)
if (err < 0)
return err;
err = smokey_check_errno(ioctl(fd, RTCFG_IOC_DETACH, &cmd));
if (err < 0)
return err;
/*
* We may or may not be acting as a server; don't check the
* status.
*/
ioctl(fd, RTCFG_IOC_DETACH, &cmd);
return smokey_net_rmmod("rtcfg");
return smokey_net_rmmod(MODID_CFG);
}
static int find_peer(const char *intf, void *vpeer)
......@@ -366,15 +422,16 @@ int smokey_net_setup(const char *driver, const char *intf, int tested_config,
if ((net_config & tested_config) == 0)
return -ENOSYS;
err = smokey_net_modprobe(driver);
modules[MODID_DRIVER].name = driver;
err = smokey_net_modprobe(MODID_DRIVER);
if (err < 0)
return err;
err = smokey_net_modprobe("rtipv4");
err = smokey_net_modprobe(MODID_IPV4);
if (err < 0)
return err;
err = smokey_net_modprobe(option_to_module(tested_config));
err = smokey_net_modprobe(option_to_modid(tested_config));
if (err < 0)
return err;
......@@ -390,6 +447,7 @@ int smokey_net_setup(const char *driver, const char *intf, int tested_config,
err = do_up(intf);
if (err < 0)
goto err;
ifup = true;
}
smokey_trace("Waiting for interface %s to be running", intf);
......@@ -486,27 +544,29 @@ int smokey_net_teardown(const char *driver, const char *intf, int tested_config)
err = tmp;
}
tmp = do_down(intf);
if (err == 0)
err = tmp;
if (ifup) {
tmp = do_down(intf);
if (err == 0)
err = tmp;
}
close(fd);
} else
err = tmp;
tmp = smokey_net_rmmod(option_to_module(tested_config));
tmp = smokey_net_rmmod(option_to_modid(tested_config));
if (err == 0)
err = tmp;
tmp = smokey_net_rmmod(driver);
tmp = smokey_net_rmmod(MODID_DRIVER);
if (err == 0)
err = tmp;
tmp = smokey_net_rmmod("rtipv4");
tmp = smokey_net_rmmod(MODID_IPV4);
if (err == 0)
err = tmp;
tmp = smokey_net_rmmod("rtnet");
tmp = smokey_net_rmmod(MODID_RTNET);
if (err == 0)
err = tmp;
......
......@@ -417,7 +417,7 @@ static int clock_decrease_after_periodic_timer_first_tick(void)
diff = now.tv_sec * 1000000000ULL + now.tv_nsec -
(timer.it_value.tv_sec * 1000000000ULL + timer.it_value.tv_nsec);
if (!smokey_assert(diff < 1000000000))
if (!smokey_assert(diff < 2000000000))
return -EINVAL;
ret = smokey_check_errno(read(t, &ticks, sizeof(ticks)));
......