2023-06-26 11:44:57 -07:00
|
|
|
// SPDX-License-Identifier: BSD-2-Clause-Views
|
2019-07-19 15:46:56 -07:00
|
|
|
/*
|
2023-06-26 11:44:57 -07:00
|
|
|
* Copyright (c) 2019-2023 The Regents of the University of California
|
|
|
|
*/
|
2019-07-19 15:46:56 -07:00
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
//#include <math.h>
|
|
|
|
//#include <signal.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
//#include <sys/stat.h>
|
|
|
|
//#include <sys/time.h>
|
|
|
|
//#include <sys/timex.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
2019-11-05 16:51:28 -08:00
|
|
|
#include "timespec.h"
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2022-04-19 01:45:01 -07:00
|
|
|
#include <mqnic/mqnic.h>
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2019-11-05 16:51:28 -08:00
|
|
|
#define NSEC_PER_SEC 1000000000
|
2019-07-19 15:46:56 -07:00
|
|
|
|
|
|
|
static void usage(char *name)
|
|
|
|
{
|
|
|
|
fprintf(stderr,
|
|
|
|
"usage: %s [options]\n"
|
|
|
|
" -d name device to open (/dev/mqnic0)\n"
|
|
|
|
" -i number interface\n"
|
|
|
|
" -P number port\n"
|
|
|
|
" -s number TDMA schedule start time (ns)\n"
|
|
|
|
" -p number TDMA schedule period (ns)\n"
|
|
|
|
" -t number TDMA timeslot period (ns)\n"
|
|
|
|
" -a number TDMA active period (ns)\n",
|
|
|
|
name);
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
char *name;
|
|
|
|
int opt;
|
|
|
|
|
|
|
|
char *device = NULL;
|
2019-11-05 16:51:28 -08:00
|
|
|
struct mqnic *dev;
|
2019-07-19 15:46:56 -07:00
|
|
|
int interface = 0;
|
|
|
|
int port = 0;
|
2022-03-28 17:23:27 -07:00
|
|
|
int sched_block = 0;
|
2019-11-05 16:51:28 -08:00
|
|
|
|
2022-04-24 22:51:37 -07:00
|
|
|
struct mqnic_reg_block *rb;
|
2021-12-29 22:31:46 -08:00
|
|
|
|
2019-11-05 16:51:28 -08:00
|
|
|
struct timespec ts_now;
|
|
|
|
struct timespec ts_start;
|
|
|
|
struct timespec ts_period;
|
|
|
|
struct timespec ts_timeslot_period;
|
|
|
|
struct timespec ts_active_period;
|
|
|
|
|
2019-07-19 15:46:56 -07:00
|
|
|
int64_t start_nsec = 0;
|
|
|
|
int64_t period_nsec = 0;
|
|
|
|
int64_t timeslot_period_nsec = 0;
|
|
|
|
int64_t active_period_nsec = 0;
|
|
|
|
|
|
|
|
name = strrchr(argv[0], '/');
|
|
|
|
name = name ? 1+name : argv[0];
|
|
|
|
|
|
|
|
while ((opt = getopt(argc, argv, "d:i:P:s:p:t:a:h?")) != EOF)
|
|
|
|
{
|
|
|
|
switch (opt)
|
|
|
|
{
|
|
|
|
case 'd':
|
|
|
|
device = optarg;
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
interface = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
port = atoi(optarg);
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
start_nsec = atoll(optarg);
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
period_nsec = atoll(optarg);
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
timeslot_period_nsec = atoll(optarg);
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
active_period_nsec = atoll(optarg);
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
case '?':
|
|
|
|
usage(name);
|
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
usage(name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!device)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Device not specified\n");
|
|
|
|
usage(name);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2019-11-05 16:51:28 -08:00
|
|
|
dev = mqnic_open(device);
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2019-11-05 16:51:28 -08:00
|
|
|
if (!dev)
|
2019-07-19 15:46:56 -07:00
|
|
|
{
|
2019-11-05 16:51:28 -08:00
|
|
|
fprintf(stderr, "Failed to open device\n");
|
|
|
|
return -1;
|
2019-07-19 15:46:56 -07:00
|
|
|
}
|
|
|
|
|
2022-07-27 14:26:37 -07:00
|
|
|
if (dev->pci_device_path[0])
|
2022-03-03 22:44:05 -08:00
|
|
|
{
|
|
|
|
char *ptr = strrchr(dev->pci_device_path, '/');
|
|
|
|
if (ptr)
|
|
|
|
printf("PCIe ID: %s\n", ptr+1);
|
|
|
|
}
|
|
|
|
|
2022-04-19 13:37:54 -07:00
|
|
|
mqnic_print_fw_id(dev);
|
2021-12-29 22:31:46 -08:00
|
|
|
|
|
|
|
if (!dev->phc_rb)
|
2019-07-19 15:46:56 -07:00
|
|
|
{
|
|
|
|
fprintf(stderr, "No PHC on card\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2019-11-05 16:51:28 -08:00
|
|
|
if (interface < 0 || interface >= dev->if_count)
|
2019-07-19 15:46:56 -07:00
|
|
|
{
|
|
|
|
fprintf(stderr, "Interface out of range\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2021-12-24 13:49:41 -08:00
|
|
|
struct mqnic_if *dev_interface = dev->interfaces[interface];
|
|
|
|
|
|
|
|
if (!dev_interface)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Invalid interface\n");
|
|
|
|
goto err;
|
|
|
|
}
|
2019-11-05 16:51:28 -08:00
|
|
|
|
2022-01-15 21:53:13 -08:00
|
|
|
printf("IF features: 0x%08x\n", dev_interface->if_features);
|
2022-03-28 17:23:27 -07:00
|
|
|
printf("Port count: %d\n", dev_interface->port_count);
|
|
|
|
printf("Scheduler block count: %d\n", dev_interface->sched_block_count);
|
2021-12-29 22:31:46 -08:00
|
|
|
printf("Max TX MTU: %d\n", dev_interface->max_tx_mtu);
|
|
|
|
printf("Max RX MTU: %d\n", dev_interface->max_rx_mtu);
|
2022-01-15 21:53:13 -08:00
|
|
|
printf("TX MTU: %d\n", mqnic_reg_read32(dev_interface->if_ctrl_rb->regs, MQNIC_RB_IF_CTRL_REG_TX_MTU));
|
|
|
|
printf("RX MTU: %d\n", mqnic_reg_read32(dev_interface->if_ctrl_rb->regs, MQNIC_RB_IF_CTRL_REG_RX_MTU));
|
2021-12-29 22:31:46 -08:00
|
|
|
|
2023-05-01 22:04:43 -07:00
|
|
|
printf("EQ count: %d\n", mqnic_res_get_count(dev_interface->eq_res));
|
2023-07-10 17:52:34 -07:00
|
|
|
printf("CQ count: %d\n", mqnic_res_get_count(dev_interface->cq_res));
|
2023-05-01 22:04:43 -07:00
|
|
|
printf("TXQ count: %d\n", mqnic_res_get_count(dev_interface->txq_res));
|
|
|
|
printf("RXQ count: %d\n", mqnic_res_get_count(dev_interface->rxq_res));
|
2021-12-29 22:31:46 -08:00
|
|
|
|
2019-11-05 16:51:28 -08:00
|
|
|
if (port < 0 || port >= dev_interface->port_count)
|
2019-07-19 15:46:56 -07:00
|
|
|
{
|
|
|
|
fprintf(stderr, "Port out of range\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2022-03-28 17:23:27 -07:00
|
|
|
sched_block = port;
|
|
|
|
|
|
|
|
if (sched_block < 0 || sched_block >= dev_interface->sched_block_count)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "Scheduler block out of range\n");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct mqnic_sched_block *dev_sched_block = dev_interface->sched_blocks[sched_block];
|
2021-12-24 13:49:41 -08:00
|
|
|
|
2022-03-28 17:23:27 -07:00
|
|
|
if (!dev_sched_block)
|
2021-12-24 13:49:41 -08:00
|
|
|
{
|
2022-03-28 17:23:27 -07:00
|
|
|
fprintf(stderr, "Invalid scheduler block\n");
|
2021-12-24 13:49:41 -08:00
|
|
|
goto err;
|
|
|
|
}
|
2019-11-05 16:51:28 -08:00
|
|
|
|
2022-03-28 17:23:27 -07:00
|
|
|
printf("Sched count: %d\n", dev_sched_block->sched_count);
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2022-04-24 22:51:37 -07:00
|
|
|
rb = mqnic_find_reg_block(dev_sched_block->rb_list, MQNIC_RB_TDMA_SCH_TYPE, MQNIC_RB_TDMA_SCH_VER, 0);
|
2019-11-05 18:20:21 -08:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
if (dev->phc_rb && rb)
|
2019-07-19 15:46:56 -07:00
|
|
|
{
|
2021-12-29 22:31:46 -08:00
|
|
|
printf("TDMA timeslot count: %d\n", mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_TS_COUNT));
|
|
|
|
printf("TDMA control: 0x%08x\n", mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_CTRL));
|
|
|
|
printf("TDMA status: 0x%08x\n", mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_STATUS));
|
|
|
|
|
|
|
|
printf("TDMA schedule start: %ld.%09d s\n", mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_START_SEC_L) +
|
|
|
|
(((int64_t)mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_START_SEC_H)) << 32),
|
|
|
|
mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_START_NS));
|
|
|
|
printf("TDMA schedule period: %ld.%09d s\n", mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_SEC_L) +
|
|
|
|
(((int64_t)mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_SEC_H)) << 32),
|
|
|
|
mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_NS));
|
|
|
|
printf("TDMA timeslot period: %ld.%09d s\n", mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_SEC_L) +
|
|
|
|
(((int64_t)mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_SEC_H)) << 32),
|
|
|
|
mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_NS));
|
|
|
|
printf("TDMA active period: %ld.%09d s\n", mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_SEC_L) +
|
|
|
|
(((int64_t)mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_SEC_H)) << 32),
|
|
|
|
mqnic_reg_read32(rb->regs, MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_NS));
|
|
|
|
|
|
|
|
if (period_nsec > 0)
|
|
|
|
{
|
|
|
|
printf("Configure port TDMA schedule\n");
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2023-11-07 21:57:07 -08:00
|
|
|
ts_now.tv_nsec = mqnic_reg_read32(dev->phc_rb->regs, MQNIC_RB_PHC_REG_CUR_TOD_NS);
|
|
|
|
ts_now.tv_sec = mqnic_reg_read32(dev->phc_rb->regs, MQNIC_RB_PHC_REG_CUR_TOD_SEC_L) +
|
|
|
|
(((int64_t)mqnic_reg_read32(dev->phc_rb->regs, MQNIC_RB_PHC_REG_CUR_TOD_SEC_H)) << 32);
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
// normalize start
|
|
|
|
ts_start.tv_sec = start_nsec / NSEC_PER_SEC;
|
|
|
|
ts_start.tv_nsec = start_nsec - ts_start.tv_sec * NSEC_PER_SEC;
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
// normalize period
|
|
|
|
ts_period.tv_sec = period_nsec / NSEC_PER_SEC;
|
|
|
|
ts_period.tv_nsec = period_nsec - ts_period.tv_sec * NSEC_PER_SEC;
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
printf("time %ld.%09ld s\n", ts_now.tv_sec, ts_now.tv_nsec);
|
|
|
|
printf("start %ld.%09ld s\n", ts_start.tv_sec, ts_start.tv_nsec);
|
|
|
|
printf("period %ld.%09ld s\n", ts_period.tv_sec, ts_period.tv_nsec);
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
if (timespec_lt(ts_start, ts_now))
|
|
|
|
{
|
|
|
|
// start time is in the past
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
// modulo start with period
|
|
|
|
ts_start = timespec_mod(ts_start, ts_period);
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
// align time with period
|
|
|
|
struct timespec ts_aligned = timespec_sub(ts_now, timespec_mod(ts_now, ts_period));
|
2019-11-05 16:51:28 -08:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
// add aligned time
|
|
|
|
ts_start = timespec_add(ts_start, ts_aligned);
|
|
|
|
}
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
printf("time %ld.%09ld s\n", ts_now.tv_sec, ts_now.tv_nsec);
|
|
|
|
printf("start %ld.%09ld s\n", ts_start.tv_sec, ts_start.tv_nsec);
|
|
|
|
printf("period %ld.%09ld s\n", ts_period.tv_sec, ts_period.tv_nsec);
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_START_NS, ts_start.tv_nsec);
|
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_START_SEC_L, ts_start.tv_sec & 0xffffffff);
|
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_START_SEC_H, ts_start.tv_sec >> 32);
|
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_NS, ts_period.tv_nsec);
|
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_SEC_L, ts_period.tv_sec & 0xffffffff);
|
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_SCH_PERIOD_SEC_H, ts_period.tv_sec >> 32);
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_CTRL, 0x00000001);
|
|
|
|
}
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
if (timeslot_period_nsec > 0)
|
|
|
|
{
|
|
|
|
printf("Configure port TDMA timeslot period\n");
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
// normalize period
|
|
|
|
ts_timeslot_period.tv_sec = timeslot_period_nsec / NSEC_PER_SEC;
|
|
|
|
ts_timeslot_period.tv_nsec = timeslot_period_nsec - ts_timeslot_period.tv_sec * NSEC_PER_SEC;
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
printf("period %ld.%09ld s\n", ts_timeslot_period.tv_sec, ts_timeslot_period.tv_nsec);
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_NS, ts_timeslot_period.tv_nsec);
|
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_SEC_L, ts_timeslot_period.tv_sec & 0xffffffff);
|
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_TS_PERIOD_SEC_H, ts_timeslot_period.tv_sec >> 32);
|
|
|
|
}
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
if (active_period_nsec > 0)
|
|
|
|
{
|
|
|
|
printf("Configure port TDMA active period\n");
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
// normalize period
|
|
|
|
ts_active_period.tv_sec = active_period_nsec / NSEC_PER_SEC;
|
|
|
|
ts_active_period.tv_nsec = active_period_nsec - ts_active_period.tv_sec * NSEC_PER_SEC;
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
printf("period %ld.%09ld s\n", ts_active_period.tv_sec, ts_active_period.tv_nsec);
|
2019-07-19 15:46:56 -07:00
|
|
|
|
2021-12-29 22:31:46 -08:00
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_NS, ts_active_period.tv_nsec);
|
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_SEC_L, ts_active_period.tv_sec & 0xffffffff);
|
|
|
|
mqnic_reg_write32(rb->regs, MQNIC_RB_TDMA_SCH_REG_ACTIVE_PERIOD_SEC_H, ts_active_period.tv_sec >> 32);
|
|
|
|
}
|
2019-07-19 15:46:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
2019-11-05 16:51:28 -08:00
|
|
|
mqnic_close(dev);
|
2019-07-19 15:46:56 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|