Commit 79672157 authored by Tomasz Wlostowski's avatar Tomasz Wlostowski

software: fdelay library: remote operation via Ethernet

parent 3e17d062
CFLAGS = -I/home/slayer/rr/gnurabbit/kernel -Iinclude -g
OBJS = fdelay_lib.o fdelay_test.o rr_io.o
all: $(OBJS)
gcc -o fd_test $(OBJS) -lm
clean:
rm -f fd_test $(OBJS)
\ No newline at end of file
/*
FmcDelay1ns4Cha (a.k.a. The Fine Delay Card)
User-space driver/library
Private includes
Tomasz Włostowski/BE-CO-HT, 2011
(c) Copyright CERN 2011
Licensed under LGPL 2.1
*/
#ifndef __FDELAY_PRIVATE_H
#define __FDELAY_PRIVATE_H
#include <stdint.h>
/* SPI Bus chip selects */
#define CS_PLL 1 /* AD9516 PLL */
#define CS_GPIO 2 /* MCP23S17 GPIO */
/* MCP23S17 GPIO expander pin locations: bit 8 = select bank 2, bits 7..0 = mask of the pin in the selected bank */
#define SGPIO_TERM_EN (0x100 | (1<<7)) /* Input termination enable (1 = on) */
#define SGPIO_LED_TERM (0x100 | (1<<2)) /* Termination enable LED (1 = on) */
#define SGPIO_DRV_OEN (0x100 | (1<<0)) /* Output driver enable (0 = on) */
#define SGPIO_TRIG_SEL (0x100 | (1<<3)) /* TDC trigger select (0 = trigger input, 1 = FPGA) */
/* ACAM TDC operation modes */
#define ACAM_RMODE 0
#define ACAM_IMODE 1
/* MCP23S17 register addresses (only ones which are used by the lib) */
#define MCP_IODIR 0x0
#define MCP_GPIO 0x12
#define MCP_IOCON 0x0a
/* Number of fractional bits in the timestamps/time definitions. Must be consistent with the HDL bitstream. */
#define FDELAY_FRAC_BITS 12
/* Fractional bits shifted away when converting the fine (< 8ns) part to fit the range of SY89295 delay line. */
#define FDELAY_SCALER_SHIFT 12
/* Number of delay line taps */
#define FDELAY_NUM_TAPS 1024
/* How many times each calibration measurement will be averaged */
#define FDELAY_CAL_AVG_STEPS 1024
/* Fine Delay Card Magic ID */
#define FDELAY_MAGIC_ID 0xf19ede1a
/* RSTR Register value which triggers a reset of the FD Core */
#define FDELAY_RSTR_TRIGGER 0xdeadbeef
/* Calibration eeprom I2C address */
#define EEPROM_ADDR 0x50
/* ACAM Calibration parameters */
struct fine_delay_calibration {
uint32_t magic; /* magic ID: 0xf19ede1a */
uint32_t zero_offset[4]; /* Output zero offset, in nsec << FDELAY_FRAC_BITS */
uint32_t adsfr_val; /* ADSFR register value */
uint32_t acam_start_offset; /* ACAM Start offset value */
uint32_t atmcr_val; /* ATMCR register value */
int32_t dly_tempco[4]; /* SY89295 delay/temperature coefficient in ps/degC << FDELAY_FRAC_BITS */
int32_t zero_tempco[4]; /* Zero offset/temperature coefficient in ps/degC << FDELAY_FRAC_BITS */
int32_t cal_temp; /* Calibration temperature in 0.1 degC */
uint32_t tdc_zero_offset; /* Zero offset of the TDC, in picoseconds */
} __attribute__((packed));
/* Internal state of the fine delay card */
struct fine_delay_hw
{
uint32_t base_addr; /* Base address of the core */
uint32_t base_onewire; /* Base address of the core */
uint32_t base_i2c; /* SPI Controller offset */
double acam_bin; /* bin size of the ACAM TDC - calculated for */
uint32_t frr[4]; /* Fine range register for each output, determi*/
int32_t board_temp; /* Current temperature of the board in 0.1 degC */
int wr_enabled;
int wr_state;
struct fine_delay_calibration calib;
};
/* some useful access/declaration macros */
#define fd_writel(data, addr) dev->writel(dev->priv_io, data, (dev->base_addr + (addr)))
#define fd_readl(addr) dev->readl(dev->priv_io, (dev->base_addr + (addr)))
#define fd_decl_private(dev) struct fine_delay_hw *hw = (struct fine_delay_hw *) dev->priv_fd;
#endif
#ifndef __I2C_MASTER_H
#define __I2C_MASTER_H
#include <stdint.h>
#include "fdelay_lib.h"
void mi2c_init(fdelay_device_t *dev);
int eeprom_read(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size);
int eeprom_write(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size);
#endif
#ifndef __OPENCORES_SPI_H
#define __OPENCORES_SPI_H
#include <stdint.h>
#define OCSPI_REG_RX0 0
#define OCSPI_REG_RX1 4
#define OCSPI_REG_RX2 8
#define OCSPI_REG_RX3 12
#define OCSPI_REG_TX0 0
#define OCSPI_REG_TX1 4
#define OCSPI_REG_TX2 8
#define OCSPI_REG_TX3 12
#define OCSPI_REG_CTRL 16
#define OCSPI_REG_DIVIDER 20
#define OCSPI_REG_SS 24
#define OCSPI_CTRL_ASS (1<<13)
#define OCSPI_CTRL_IE (1<<12)
#define OCSPI_CTRL_LSB (1<<11)
#define OCSPI_CTRL_TXNEG (1<<10)
#define OCSPI_CTRL_RXNEG (1<<9)
#define OCSPI_CTRL_GO_BSY (1<<8)
#define OCSPI_CTRL_CHAR_LEN(x) ((x) & 0x7f)
#endif
/*
* Public header for the raw I/O interface for PCI or PCI express interfaces
*
* Copyright (C) 2010 CERN (www.cern.ch)
* Author: Alessandro Rubini <rubini@gnudd.com>
*
* Released according to the GNU GPL, version 2 or any later version.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __RAWRABBIT_H__
#define __RAWRABBIT_H__
#include <linux/types.h>
#include <linux/ioctl.h>
#ifdef __KERNEL__ /* The initial part of the file is driver-internal stuff */
#include <linux/pci.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
#include <linux/wait.h>
#include <linux/completion.h>
struct rr_devsel;
struct rr_dev {
struct rr_devsel *devsel;
struct pci_driver *pci_driver;
struct pci_device_id *id_table;
struct pci_dev *pdev; /* non-null after pciprobe */
struct mutex mutex;
wait_queue_head_t q;
void *dmabuf;
char *fwname;
struct timespec irqtime;
unsigned long irqcount;
struct completion complete;
struct resource *area[3]; /* bar 0, 2, 4 */
void *remap[3]; /* ioremap of bar 0, 2, 4 */
unsigned long flags;
struct work_struct work;
const struct firmware *fw;
struct completion fw_load;
void (*load_program)(struct rr_dev *); /* lm32 */
int usecount;
#ifdef IS_SPEC_DEMO
struct miscdevice misc;
char miscname[32]; /* "spec-demo-<bus>-<slot> */
struct list_head list;
#endif
};
extern char *rr_fwname; /* module parameter. If "" then defaults apply */
#define RR_FLAG_REGISTERED 0x00000001
#define RR_FLAG_IRQDISABLE 0x00000002
#define RR_FLAG_IRQREQUEST 0x00000002
#define RR_PROBE_TIMEOUT (HZ) /* for pci_register_drv */
/* These two live in ./loader.c */
extern void rr_ask_firmware(struct rr_dev *dev);
extern void rr_load_firmware(struct work_struct *work);
/* And, for the spec only, this is in ./spec-loader.c */
extern void spec_ask_program(struct rr_dev *dev);
#endif /* __KERNEL__ */
/* By default, the driver registers for this vendor/devid */
#define RR_DEFAULT_VENDOR 0x1a39
#define RR_DEFAULT_DEVICE 0x0004
#define RR_DEFAULT_FWNAME "rrabbit-%P-%p@%b"
#define RR_MAX_FWNAME_SIZE 64
#define RR_DEFAULT_BUFSIZE (1<<20) /* 1MB */
#define RR_PLIST_SIZE 4096 /* no PAGE_SIZE in user space */
#define RR_PLIST_LEN (RR_PLIST_SIZE / sizeof(void *))
#define RR_MAX_BUFSIZE (RR_PLIST_SIZE * RR_PLIST_LEN)
/* This structure is used to select the device to be accessed, via ioctl */
struct rr_devsel {
__u16 vendor;
__u16 device;
__u16 subvendor; /* RR_DEVSEL_UNUSED to ignore subvendor/dev */
__u16 subdevice;
__u16 bus; /* RR_DEVSEL_UNUSED to ignore bus and devfn */
__u16 devfn;
};
#define RR_DEVSEL_UNUSED 0xffff
/* Offsets for BAR areas in llseek() and/or ioctl */
#define RR_BAR_0 0x00000000
#define RR_BAR_2 0x20000000
#define RR_BAR_4 0x40000000
#define RR_BAR_BUF 0xc0000000 /* The DMA buffer */
#define RR_IS_DMABUF(addr) ((addr) >= RR_BAR_BUF)
#define __RR_GET_BAR(x) ((x) >> 28)
#define __RR_SET_BAR(x) ((x) << 28)
#define __RR_GET_OFF(x) ((x) & 0x0fffffff)
static inline int rr_is_valid_bar(unsigned long address)
{
int bar = __RR_GET_BAR(address);
return bar == 0 || bar == 2 || bar == 4 || bar == 0x0c;
}
static inline int rr_is_dmabuf_bar(unsigned long address)
{
int bar = __RR_GET_BAR(address);
return bar == 0x0c;
}
struct rr_iocmd {
__u32 address; /* bar and offset */
__u32 datasize; /* 1 or 2 or 4 or 8 */
union {
__u8 data8;
__u16 data16;
__u32 data32;
__u64 data64;
};
};
/* ioctl commands */
#define __RR_IOC_MAGIC '4' /* random or so */
#define RR_DEVSEL _IOW(__RR_IOC_MAGIC, 0, struct rr_devsel)
#define RR_DEVGET _IOR(__RR_IOC_MAGIC, 1, struct rr_devsel)
#define RR_READ _IOWR(__RR_IOC_MAGIC, 2, struct rr_iocmd)
#define RR_WRITE _IOW(__RR_IOC_MAGIC, 3, struct rr_iocmd)
#define RR_IRQWAIT _IO(__RR_IOC_MAGIC, 4)
#define RR_IRQENA _IO(__RR_IOC_MAGIC, 5)
#define RR_GETDMASIZE _IO(__RR_IOC_MAGIC, 6)
/* #define RR_SETDMASIZE _IO(__RR_IOC_MAGIC, 7, unsigned long) */
#define RR_GETPLIST _IO(__RR_IOC_MAGIC, 8) /* returns a whole page */
#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct dirent [2])
/* Registers from the gennum header files */
enum {
GNGPIO_BASE = 0xA00,
GNGPIO_DIRECTION_MODE = GNGPIO_BASE + 0x4,
GNGPIO_OUTPUT_ENABLE = GNGPIO_BASE + 0x8,
GNGPIO_OUTPUT_VALUE = GNGPIO_BASE + 0xC,
GNGPIO_INPUT_VALUE = GNGPIO_BASE + 0x10,
FCL_BASE = 0xB00,
FCL_CTRL = FCL_BASE,
FCL_STATUS = FCL_BASE + 0x4,
FCL_IODATA_IN = FCL_BASE + 0x8,
FCL_IODATA_OUT = FCL_BASE + 0xC,
FCL_EN = FCL_BASE + 0x10,
FCL_TIMER_0 = FCL_BASE + 0x14,
FCL_TIMER_1 = FCL_BASE + 0x18,
FCL_CLK_DIV = FCL_BASE + 0x1C,
FCL_IRQ = FCL_BASE + 0x20,
FCL_TIMER_CTRL = FCL_BASE + 0x24,
FCL_IM = FCL_BASE + 0x28,
FCL_TIMER2_0 = FCL_BASE + 0x2C,
FCL_TIMER2_1 = FCL_BASE + 0x30,
FCL_DBG_STS = FCL_BASE + 0x34,
FCL_FIFO = 0xE00,
PCI_SYS_CFG_SYSTEM = 0x800
};
#endif /* __RAWRABBIT_H__ */
CFLAGS = -I../include -g -Imini_bone
OBJS_LIB = fdelay_lib.o rr_io.o i2c_master.o mini_bone/minibone_lib.o mini_bone/ptpd_netif.o fdelay_bus.o
all: $(OBJS_LIB)
gcc -shared -o libfinedelay.so $(OBJS_LIB)
clean:
rm -f libfinedelay.so $(OBJS_LIB)
\ No newline at end of file
/*
FmcDelay1ns4Cha (a.k.a. The Fine Delay Card)
User-space driver/library - bus API creation functions
Tomasz Włostowski/BE-CO-HT, 2011
(c) Copyright CERN 2011
Licensed under LGPL 2.1
*/
#include <stdio.h>
#include <stdlib.h>
#include "rr_io.h"
#include "minibone_lib.h"
#include "fdelay_lib.h"
static void my_rr_writel(void *priv, uint32_t data, uint32_t addr)
{
rr_writel(data, addr);
}
static uint32_t my_rr_readl(void *priv, uint32_t addr)
{
uint32_t d = rr_readl(addr);
return d;
}
static void my_mb_writel(void *priv, uint32_t data, uint32_t addr)
{
mbn_writel(priv, data, addr >> 2);
}
static uint32_t my_mb_readl(void *priv, uint32_t addr)
{
uint32_t d = mbn_readl(priv, addr >> 2);
return d;
}
fdelay_device_t *fdelay_create_rawrabbit(uint32_t base_addr)
{
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
rr_init();
dev->writel = my_rr_writel;
dev->readl = my_rr_readl;
dev->base_addr = base_addr;
return dev;
}
fdelay_device_t *fdelay_create_minibone(char *iface, char *mac_addr, uint32_t base_addr)
{
void *handle;
uint8_t target_mac[6];
fdelay_device_t *dev = malloc(sizeof(fdelay_device_t));
sscanf(mac_addr, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", &target_mac[0], &target_mac[1], &target_mac[2], &target_mac[3], &target_mac[4], &target_mac[5]);
handle = mbn_open(iface, target_mac);
if(handle == NULL)
return NULL;
// dbg("%s: remote @ %s [%02x:%02x:%02x:%02x:%02x:%02x], base 0x%08x\n",__FUNCTION__, iface,
// target_mac[0], target_mac[1], target_mac[2], target_mac[3], target_mac[4], target_mac[5], base_addr);
dev->writel = my_mb_writel;
dev->readl = my_mb_readl;
dev->base_addr = base_addr;
dev->priv_io = handle;
return dev;
}
......@@ -16,73 +16,13 @@
#include <sys/time.h>
#include <math.h>
#include "rr_io.h"
#include "fdelay_regs.h"
#include "pll_config.h"
#include "acam_gpx.h"
#include "fdelay_lib.h"
#include "fdelay_private.h"
/* SPI Bus chip selects */
#define CS_PLL 1 /* AD9516 PLL */
#define CS_GPIO 2 /* MCP23S17 GPIO */
/* MCP23S17 GPIO expander pin locations: bit 8 = select bank 2, bits 7..0 = mask of the pin in the selected bank */
#define SGPIO_TERM_EN (0x100 | (1<<7)) /* Input termination enable (1 = on) */
#define SGPIO_LED_TERM (0x100 | (1<<2)) /* Termination enable LED (1 = on) */
#define SGPIO_DRV_OEN (0x100 | (1<<0)) /* Output driver enable (0 = on) */
#define SGPIO_TRIG_SEL (0x100 | (1<<3)) /* TDC trigger select (0 = trigger input, 1 = FPGA) */
/* ACAM TDC operation modes */
#define ACAM_RMODE 0
#define ACAM_IMODE 1
/* MCP23S17 register addresses (only ones which are used by the lib) */
#define MCP_IODIR 0x0
#define MCP_GPIO 0x12
#define MCP_IOCON 0x0a
/* Number of fractional bits in the timestamps/time definitions. Must be consistent with the HDL bitstream. */
#define FDELAY_FRAC_BITS 12
/* Fractional bits shifted away when converting the fine (< 8ns) part to fit the range of SY89295 delay line. */
#define FDELAY_SCALER_SHIFT 12
/* Number of delay line taps */
#define FDELAY_NUM_TAPS 1024
/* How many times each calibration measurement will be averaged */
#define FDELAY_CAL_AVG_STEPS 1024
/* Fine Delay Card Magic ID */
#define FDELAY_MAGIC_ID 0xf19ede1a
/* RSTR Register value which triggers a reset of the FD Core */
#define FDELAY_RSTR_TRIGGER 0xdeadbeef
/* ACAM Calibration parameters */
struct fine_delay_calibration {
uint32_t magic; /* magic ID: 0xf19ede1a */
uint32_t zero_offset[4]; /* Output zero offset, in nsec << FDELAY_FRAC_BITS */
uint32_t adsfr_val; /* ADSFR register value */
uint32_t acam_start_offset; /* ACAM Start offset value */
uint32_t atmcr_val; /* ATMCR register value */
int32_t dly_tempco[4]; /* SY89295 delay/temperature coefficient in ps/degC << FDELAY_FRAC_BITS */
int32_t zero_tempco[4]; /* Zero offset/temperature coefficient in ps/degC << FDELAY_FRAC_BITS */
int32_t cal_temp; /* Calibration temperature in 0.1 degC */
} __attribute__((packed));
/* Internal state of the fine delay card */
struct fine_delay_hw
{
uint32_t base_addr; /* Base address of the core */
uint32_t base_spi; /* SPI Controller offset */
double acam_bin; /* bin size of the ACAM TDC - calculated for */
uint32_t frr[4]; /* Fine range register for each output, determi*/
int32_t board_temp; /* Current temperature of the board in 0.1 degC */
struct fine_delay_calibration calib;
};
/*
----------------------
......@@ -111,20 +51,13 @@ static inline int64_t get_tics()
}
/* Microsecond-accurate delay */
static void udelay(uint32_t usecs)
void udelay(uint32_t usecs)
{
int64_t ts = get_tics();
while(get_tics() - ts < (int64_t)usecs);
}
/* useful declaration/wrapper macros */
#define fd_writel(data, addr) dev->writel(dev->priv_io, data, (dev->base_addr + (addr)))
#define fd_readl(addr) dev->readl(dev->priv_io, (dev->base_addr + (addr)))
#define fd_decl_private(dev) struct fine_delay_hw *hw = (struct fine_delay_hw *) dev->priv_fd;
/*
----------------------------------
Simple SPI Master driver
......@@ -142,7 +75,7 @@ static void oc_spi_init(fdelay_device_t *dev)
static void oc_spi_txrx(fdelay_device_t *dev, int ss, int num_bits, uint32_t in, uint32_t *out)
{
fd_decl_private(dev);
uint32_t scr;
uint32_t scr = 0, r;
scr = FD_SCR_DATA_W(in) | FD_SCR_CPOL;
if(ss == CS_PLL)
......@@ -152,11 +85,14 @@ static void oc_spi_txrx(fdelay_device_t *dev, int ss, int num_bits, uint32_t in,
fd_writel(scr, FD_REG_SCR);
fd_writel(scr | FD_SCR_START, FD_REG_SCR);
while(! (fd_readl(FD_REG_SCR) & FD_SCR_READY))
while(! (fd_readl(FD_REG_SCR) & FD_SCR_READY));
scr = fd_readl(FD_REG_SCR);
if(out) *out = FD_SCR_DATA_R(scr);
r = FD_SCR_DATA_R(scr);
// if(ss==CS_PLL)
// printf("IN %x OUT %x\n", in, scr);
if(out) *out=r;
udelay(100);
}
/*
......@@ -176,6 +112,7 @@ static inline uint8_t ad9516_read_reg(fdelay_device_t *dev, uint16_t reg)
{
uint32_t rval;
oc_spi_txrx(dev, CS_PLL, 24, ((uint32_t)(reg & 0xfff) << 8) | (1<<23), &rval);
printf("ReadReg: %x %x\n", reg, rval);
return rval & 0xff;
}
......@@ -190,6 +127,7 @@ static int ad9516_init(fdelay_device_t *dev)
dbg("%s: Initializing AD9516 PLL...\n", __FUNCTION__);
ad9516_write_reg(dev, 0, 0x99);
//xit(-1);
ad9516_write_reg(dev, 0x232, 1);
/* Check if the chip is present by reading its ID register */
......@@ -203,6 +141,9 @@ static int ad9516_init(fdelay_device_t *dev)
for(i=0;ad9516_regs[i].reg >=0 ;i++)
ad9516_write_reg (dev, ad9516_regs[i].reg, ad9516_regs[i].val);
ad9516_write_reg(dev, 0x232, 1);
/* Wait until the PLL has locked */
start_tics = get_tics();
......@@ -257,6 +198,7 @@ static void sgpio_set_dir(fdelay_device_t *dev, int pin, int dir)
uint8_t x;
x = mcp_read(dev, iodir);
if(dir) x &= ~(pin); else x |= (pin);
mcp_write(dev, iodir, x);
......@@ -269,6 +211,7 @@ static void sgpio_set_pin(fdelay_device_t *dev, int pin, int val)
uint8_t x;
x = mcp_read(dev, gpio);
if(!val) x &= ~(pin); else x |= (pin);
mcp_write(dev, gpio, x);
}
......@@ -584,6 +527,22 @@ void poll_stats()
}
#endif
static int read_calibration_eeprom(fdelay_device_t *dev, struct fine_delay_calibration *d_cal)
{
struct fine_delay_calibration cal;
mi2c_init(dev);
if(eeprom_read(dev, EEPROM_ADDR, 0, (uint8_t *) &cal, sizeof(struct fine_delay_calibration)) != sizeof(struct fine_delay_calibration))
return -1;
if(cal.magic != FDELAY_MAGIC_ID)
return -1;
memcpy(d_cal, &cal, sizeof(cal));
return 0;
}
/*
-------------------------------------
Public API
......@@ -595,6 +554,7 @@ int fdelay_init(fdelay_device_t *dev)
{
struct fine_delay_hw *hw;
dbg("Init: dev %x\n", dev);
hw = (struct fine_delay_hw *) malloc(sizeof(struct fine_delay_hw));
if(! hw)
return -1;
......@@ -602,12 +562,11 @@ int fdelay_init(fdelay_device_t *dev)
dev->priv_fd = (void *) hw;
hw->base_addr = dev->base_addr;
hw->base_spi = 0x100;
hw->base_i2c = 0x100;
hw->base_onewire = 0x200;
hw->wr_enabled = 0;
hw->wr_state = FDELAY_FREE_RUNNING;
/* Fixme: read these from the calibration EEPROM */
hw->calib.atmcr_val = 1 | (2000 << 4);
hw->calib.adsfr_val = 56648;
hw->calib.acam_start_offset = 10000;
dbg("%s: Initializing the Fine Delay Card\n", __FUNCTION__);
......@@ -618,6 +577,22 @@ int fdelay_init(fdelay_device_t *dev)
return -1;
}
//if(read_calibration_eeprom(dev, &hw->calib) < 0)
{
int i;
dbg("%s: Calibration EEPROM not found or unreadable. Using default calibration values\n", __FUNCTION__);
hw->calib.tdc_zero_offset = 35600;
hw->calib.atmcr_val = 1 | (2000 << 4);
hw->calib.adsfr_val = 56648;
hw->calib.acam_start_offset = 10000;
for(i=0;i<4;i++)
hw->calib.zero_offset[i] = 50000;
}
// exit(-1);
/* Initialize the clock system - AD9516 PLL */
oc_spi_init(dev);
......@@ -642,7 +617,7 @@ int fdelay_init(fdelay_device_t *dev)
fd_writel( FD_GCR_BYPASS, FD_REG_GCR);
/* Calibrate the output delay lines */
calibrate_outputs(dev);
// calibrate_outputs(dev);
/* Switch to the R-MODE (more precise) */
acam_configure(dev, ACAM_RMODE);
......@@ -665,7 +640,11 @@ int fdelay_init(fdelay_device_t *dev)
all the time counters inside the FD Core are in sync */
fd_writel(FD_GCR_CSYNC_INT, FD_REG_GCR);
/* Enable outputs */
/* Enable input */
udelay(1);
fd_writel(FD_GCR_INPUT_EN, FD_REG_GCR);
/* Enable output driver */
sgpio_set_pin(dev, SGPIO_DRV_OEN, 1);
dbg("FD initialized\n");
......@@ -689,15 +668,19 @@ int fdelay_configure_trigger(fdelay_device_t *dev, int enable, int termination)
};
if(enable)
fd_writel(FD_GCR_INPUT_EN, FD_REG_GCR);
else
fd_writel(0, FD_REG_GCR);
{
// fd_writel(FD_GCR_BYPASS, FD_REG_GCR);
// dbg("EF %d\n", fd_readl(FD_REG_TDCSR) & FD_TDCSR_EMPTY ? 1: 0);
// fd_writel(0, FD_REG_GCR);
fd_writel(fd_readl(FD_REG_GCR) | FD_GCR_INPUT_EN, FD_REG_GCR);
} else
fd_writel(fd_readl(FD_REG_GCR) & (~FD_GCR_INPUT_EN) , FD_REG_GCR);
return 0;
}
/* Converts a positive time interval expressed in picoseconds to the timestamp format used in the Fine Delay core */
fdelay_time_t fdelay_from_picos(const uint64_t ps)
/*fdelay_time_t fdelay_from_picos(const uint64_t ps)
{
fdelay_time_t t;
int64_t rescaled;
......@@ -707,13 +690,51 @@ fdelay_time_t fdelay_from_picos(const uint64_t ps)
t.frac = rescaled % 4096;
rescaled -= t.frac;
rescaled /= 4096;
t.coarse = rescaled % 125000000;
t.coarse = rescaled % 125000000ULL;
rescaled -= t.coarse;
rescaled /= 125000000;
rescaled /= 125000000ULL;
t.utc = rescaled;
//dbg("fdelay_from_picos: %d:%d:%d\n", t.utc, t.coarse, t.frac);
dbg("fdelay_from_picos: %d:%d:%d\n", t.utc, t.coarse, t.frac);
return t;
}*/
fdelay_time_t fdelay_from_picos(const uint64_t ps)
{
fdelay_time_t t;
uint64_t tmp = ps;
// int64_t rescaled;
// rescaled = (int64_t) ((long double) ps * (long double)4096 / (long double)8000);
t.frac = (tmp % 8000ULL) * 4096ULL / 8000ULL;
tmp -= (tmp % 8000ULL);
tmp /= 8000ULL;
t.coarse = tmp % 125000000ULL;
tmp -= (tmp % 125000000ULL);
tmp /= 125000000ULL;
t.utc = tmp;
dbg("fdelay_from_picos: %d:%d:%d\n", t.utc, t.coarse, t.frac);
return t;
}
/* Substract two timestamps */
static fdelay_time_t ts_sub(fdelay_time_t a, fdelay_time_t b)
{
a.frac -= b.frac;
if(a.frac < 0)
{
a.frac += 4096;
a.coarse--;
}
a.coarse -= b.coarse;
if(a.coarse < 0)
{
a.coarse += 125000000;
a.utc ++;
}
return a;
}
/* Converts a Fine Delay time stamp to plain picoseconds */
......@@ -730,11 +751,26 @@ static int poll_rbuf(fdelay_device_t *dev)
return 0;
}
int fdelay_configure_readout(fdelay_device_t *dev, int enable)
{
if(enable)
{
fd_writel( FD_TSBCR_PURGE | FD_TSBCR_RST_SEQ, FD_REG_TSBCR);
fd_writel( FD_TSBCR_ENABLE, FD_REG_TSBCR);
} else
fd_writel( FD_TSBCR_PURGE | FD_TSBCR_RST_SEQ, FD_REG_TSBCR);
return 0;
}
/* Reads up to (how_many) timestamps from the FD ring buffer and stores them in (timestamps).
Returns the number of read timestamps. */
int fdelay_read(fdelay_device_t *dev, fdelay_time_t *timestamps, int how_many)
{
fd_decl_private(dev)
int n_read = 0;
while(poll_rbuf(dev))
{
fdelay_time_t ts;
......@@ -746,11 +782,13 @@ int fdelay_read(fdelay_device_t *dev, fdelay_time_t *timestamps, int how_many)
seq_frac = fd_readl(FD_REG_TSBR_FID);
ts.frac = seq_frac & 0xfff;
ts.seq_id = seq_frac >> 16;
*timestamps++ = ts;
*timestamps++ = ts_sub(ts, fdelay_from_picos(hw->calib.tdc_zero_offset));
how_many--;
n_read++;
}
// printf("read %d\n", how_many, n_read);
return n_read;
}
......@@ -766,9 +804,11 @@ int fdelay_configure_output(fdelay_device_t *dev, int channel, int enable, int64
if(channel < 1 || channel > 4)
return -1;
delay_ps -= hw->calib.zero_offset[channel-1];
start = fdelay_from_picos(delay_ps);
end = fdelay_from_picos(delay_ps + width_ps);
fd_writel(hw->frr[channel-1], base + FD_REG_FRR1);
fd_writel(start.utc, base + FD_REG_U_START1);
fd_writel(start.coarse, base + FD_REG_C_START1);
......@@ -785,20 +825,60 @@ int fdelay_configure_output(fdelay_device_t *dev, int channel, int enable, int64
return 0;
}
#if 0
int fdelay_get_raw(int *coarse, int *frac)
int fdelay_configure_sync(fdelay_device_t *dev, int mode)
{
if(! (fd_readl(FD_REG_RAWFIFO_CSR) & FD_RAWFIFO_CSR_EMPTY))
fd_decl_private(dev)
if(mode == FDELAY_SYNC_LOCAL)
{
*frac = fd_readl(FD_REG_RAWFIFO_R0) & 0xfffff;
*coarse = fd_readl(FD_REG_RAWFIFO_R1) & 0xfffffff;
return 1;
fd_writel(0, FD_REG_GCR);
fd_writel(FD_GCR_CSYNC_INT, FD_REG_GCR);
hw->wr_enabled = 0;
} else {
fd_writel(0, FD_REG_GCR);
hw->wr_enabled = 1;
hw->wr_state = FDELAY_WR_OFFLINE;
}
return 0;
}
int fdelay_get_sync_status(fdelay_device_t *dev)
{
fd_decl_private(dev)
if(!hw->wr_enabled) return FDELAY_FREE_RUNNING;
switch(hw->wr_state)
{
case FDELAY_WR_OFFLINE:
if(fd_readl(FD_REG_GCR) & FD_GCR_WR_READY)
{
dbg("-> WR Core synced\n");
hw->wr_state = FDELAY_WR_READY;
}
break;
case FDELAY_WR_READY:
fd_writel(FD_GCR_WR_LOCK_EN, FD_REG_GCR);
hw->wr_state = FDELAY_WR_SYNCING;
break;
case FDELAY_WR_SYNCING:
if(fd_readl(FD_REG_GCR) & FD_GCR_WR_LOCKED)
{
fd_writel(FD_GCR_WR_LOCK_EN | FD_GCR_CSYNC_WR, FD_REG_GCR);
fd_writel(FD_GCR_WR_LOCK_EN , FD_REG_GCR);
fd_writel(FD_GCR_WR_LOCK_EN | FD_GCR_INPUT_EN, FD_REG_GCR);
hw->wr_state = FDELAY_WR_SYNCED;
}
break;
case FDELAY_WR_SYNCED:
if((fd_readl(FD_REG_GCR) & FD_GCR_WR_LOCKED) == 0)
hw->wr_state = FDELAY_WR_OFFLINE;
break;
}
return hw->wr_state;
}
#endif
#include <stdio.h>
#include "fdelay_lib.h"
#include "fdelay_private.h"
#include "fdelay_regs.h"
#define M_SDA_OUT(x) { \
if(x) \
fd_writel(fd_readl(FD_REG_I2CR) | FD_I2CR_SDA_OUT, FD_REG_I2CR); \
else \
fd_writel(fd_readl(FD_REG_I2CR) & (~FD_I2CR_SDA_OUT), FD_REG_I2CR); \
udelay(10);\
}
#define M_SCL_OUT(x) { \
if(x) \
fd_writel(fd_readl(FD_REG_I2CR) | FD_I2CR_SCL_OUT, FD_REG_I2CR); \
else \
fd_writel(fd_readl(FD_REG_I2CR) & (~FD_I2CR_SCL_OUT), FD_REG_I2CR); \
udelay(10); \
}
#define M_SDA_IN ((fd_readl(FD_REG_I2CR) & FD_I2CR_SDA_IN) ? 1 : 0)
static void mi2c_start(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SDA_OUT(0);
M_SCL_OUT(0);
}
static void mi2c_repeat_start(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SDA_OUT(1);
M_SCL_OUT(1);
M_SDA_OUT(0);
M_SCL_OUT(0);
}
static void mi2c_stop(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SDA_OUT(0);
M_SCL_OUT(1);
M_SDA_OUT(1);
}
int mi2c_put_byte(fdelay_device_t *dev, unsigned char data)
{
fd_decl_private(dev);
char i;
unsigned char ack;
for (i=0;i<8;i++, data<<=1)
{
M_SDA_OUT(data&0x80);
M_SCL_OUT(1);
M_SCL_OUT(0);
}
M_SDA_OUT(1);
M_SCL_OUT(1);
ack = M_SDA_IN; /* ack: sda is pulled low ->success. */
M_SCL_OUT(0);
M_SDA_OUT(0);
return ack!=0 ? -1 : 0;
}
void mi2c_get_byte(fdelay_device_t *dev, unsigned char *data, int ack)
{
int i;
unsigned char indata = 0;
/* assert: scl is low */
M_SCL_OUT(0);
M_SDA_OUT(1);
for (i=0;i<8;i++)
{
M_SCL_OUT(1);
indata <<= 1;
if ( M_SDA_IN ) indata |= 0x01;
M_SCL_OUT(0);
}
M_SDA_OUT((ack ? 0 : 1));
M_SCL_OUT(1);
M_SCL_OUT(0);
M_SDA_OUT(0);
*data= indata;
}
void mi2c_init(fdelay_device_t *dev)
{
fd_decl_private(dev);
M_SCL_OUT(1);
M_SDA_OUT(1);
}
void mi2c_scan(fdelay_device_t *dev)
{
int i;
for(i=0;i<256;i+=2)
{
mi2c_start(dev);
if(!mi2c_put_byte(dev,i))
printf("Found device at 0x%x\n", i>>1);
mi2c_stop(dev);
}
}
int eeprom_read(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size)
{
int i;
unsigned char c;
for(i=0;i<size;i++)
{
mi2c_start(dev);
if(mi2c_put_byte(dev, i2c_addr << 1) < 0)
{
mi2c_stop(dev);
return -1;
}
mi2c_put_byte(dev, (offset >> 8) & 0xff);
mi2c_put_byte(dev, offset & 0xff);
offset++;
mi2c_stop(dev);
mi2c_start(dev);
mi2c_put_byte(dev, (i2c_addr << 1) | 1);
mi2c_get_byte(dev, &c, 0);
printf("readback: %x\n", c);
*buf++ = c;
mi2c_stop(dev);
}
return size;
}
int eeprom_write(fdelay_device_t *dev, uint8_t i2c_addr, uint32_t offset, uint8_t *buf, size_t size)
{
int i, busy;
for(i=0;i<size;i++)
{
mi2c_start(dev);
if(mi2c_put_byte(dev, i2c_addr << 1) < 0)
{
mi2c_stop(dev);
return -1;
}
mi2c_put_byte(dev, (offset >> 8) & 0xff);
mi2c_put_byte(dev, offset & 0xff);
mi2c_put_byte(dev, *buf++);
offset++;
mi2c_stop(dev);
do /* wait until the chip becomes ready */
{
mi2c_start(dev);
busy = mi2c_put_byte(dev, i2c_addr << 1);
mi2c_stop(dev);
} while(busy);
}
return size;
}
\ No newline at end of file
OBJS = minibone_lib.o ptpd_netif.o
all: $(OBJS)
gcc -o m $(OBJS)
\ No newline at end of file
/* MiniBone library. BUGGY CRAP CODE INTENDED FOR TESTING ONLY! */
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <sys/time.h>
#include "ptpd_netif.h"
#define F_SEL(x) (x & 0xf)
#define F_ERROR (1<<1)
#define F_READBACK (1<<0)
#define F_WRITE (1<<4)
#define RX_TIMEOUT 10
#define MBN_ETHERTYPE 0xa0a0
struct mbn_packet {
uint16_t flags ;
uint32_t a_d;
uint32_t d;
} __attribute__((packed));
struct mb_device {
mac_addr_t dest;
uint16_t ethertype;
wr_socket_t *sock;
int tx_packets, rx_packets, tx_retries, rx_retries;
};
typedef struct
{
uint64_t start_tics;
uint64_t timeout;
} timeout_t ;
static uint64_t get_tics()
{
struct timezone tz = {0, 0};
struct timeval tv;
gettimeofday(&tv, &tz);
return (uint64_t) tv.tv_sec * 1000000ULL + (uint64_t) tv.tv_usec;
}
static inline int tmo_init(timeout_t *tmo, uint32_t milliseconds)
{
tmo->start_tics = get_tics();
tmo->timeout = (uint64_t) milliseconds * 1000ULL;
return 0;
}
static inline int tmo_restart(timeout_t *tmo)
{
tmo->start_tics = get_tics();
return 0;
}
static inline int tmo_expired(timeout_t *tmo)
{
return (get_tics() - tmo->start_tics > tmo->timeout);
}
void *mbn_open(const char *if_name, mac_addr_t target)
{
struct mb_device *dev = malloc(sizeof(struct mb_device));
wr_sockaddr_t saddr;
if(!dev)
return NULL;
memset(dev, 0, sizeof(struct mb_device));
memcpy(dev->dest, target, 6);
strcpy(saddr.if_name, if_name);
memcpy(saddr.mac, target, 6);
saddr.ethertype = htons(MBN_ETHERTYPE);
saddr.family = PTPD_SOCK_RAW_ETHERNET;
dev->sock = ptpd_netif_create_socket(PTPD_SOCK_RAW_ETHERNET, 0, &saddr);
if(!dev->sock)
{
free(dev);
return NULL;
}
return (void *)dev;
}
static int mbn_send(void *priv, uint8_t *data, int size)
{
struct mb_device *dev = (struct mb_device *)priv;
wr_sockaddr_t to;
memcpy(to.mac, dev->dest, 6);
to.ethertype = MBN_ETHERTYPE;
return ptpd_netif_sendto(dev->sock, &to, (void*)data, size, NULL);
}
static int mbn_recv(void *handle, uint8_t *data, int size, int timeout)
{
struct mb_device *dev = (struct mb_device *)handle;
wr_sockaddr_t from;
timeout_t rx_tmo;
tmo_init(&rx_tmo, timeout);
do {
int n = ptpd_netif_recvfrom(dev->sock, &from, (void*)data, size, NULL);
if(n > 0 && from.ethertype == MBN_ETHERTYPE && !memcmp(from.mac, dev->dest, 6))
{
dev->rx_packets++;
return n;
}
// dev->rx_retries++;
} while(!tmo_expired(&rx_tmo));
return 0;
}
void mbn_writel(void *handle, uint32_t d, uint32_t a)
{
struct mb_device *dev = (struct mb_device *)handle;
int n_retries = 3;
struct mbn_packet pkt;
while(n_retries--)
{
pkt.flags = htons(F_SEL(0xf) | F_WRITE);
pkt.a_d= htonl(a);
pkt.d=htonl(d);
mbn_send(handle, (uint8_t *)&pkt, sizeof(pkt));
int n = mbn_recv(handle, (uint8_t *)&pkt, sizeof(pkt), RX_TIMEOUT);
pkt.flags = ntohs(pkt.flags);
if(n == sizeof(pkt) && ! (!(pkt.flags && F_READBACK) && !(pkt.flags & F_ERROR)))
{
int i;
fprintf(stderr,"\nBadPacket: ");
for(i=0;i<n; i++) fprintf(stderr,"%02x ", *(uint8_t*) (&pkt + i));
fprintf(stderr,"\n");
} if(n == sizeof(pkt) && !(pkt.flags && F_READBACK) && !(pkt.flags & F_ERROR))
{
int i;
// fprintf(stderr,"GoodFlags: %x\n", pkt.flags);
/*fprintf(stderr,"\nGoodPacket: ");
for(i=0;i<n; i++) fprintf(stderr,"%02x ", *(uint8_t*) (&pkt + i));
fprintf(stderr,"\n");*/
dev->tx_packets++;
return ;
}
dev->tx_retries++;
}
fprintf(stderr, "No ack.\n");
}
uint32_t mbn_readl(void *handle, uint32_t a)
{
int n_retries = 3;
struct mb_device *dev = (struct mb_device *)handle;
struct mbn_packet pkt;
pkt.flags = htons(F_SEL(0xf));
pkt.a_d= htonl(a);
while(n_retries--)
{
mbn_send(handle, (uint8_t *)&pkt, sizeof(pkt));
int n = mbn_recv(handle, (uint8_t *)&pkt, sizeof(pkt), RX_TIMEOUT);
pkt.flags = ntohs(pkt.flags);
if(n == sizeof(pkt) && (pkt.flags & F_READBACK) && !(pkt.flags & F_ERROR))
{
return ntohl(pkt.a_d);
}
dev->tx_retries++;
}
fprintf(stderr, "No ack.\n");
}
void mbn_stats(void *handle)
{
struct mb_device *dev = (struct mb_device *)handle;
fprintf(stderr,"Sent: %d [retries: %d], rcvd: %d [retries: %d]\n", dev->tx_packets, dev->tx_retries, dev->rx_packets, dev->rx_retries);
}
void mbn_close(void *handle)
{
struct mb_device *dev = (struct mb_device *)handle;
ptpd_netif_close_socket(dev->sock);
}
\ No newline at end of file
/* MiniBone library. BUGGY CRAP CODE INTENDED FOR TESTING ONLY! */
#ifndef __MINIBONE_LIB_H
#define __MINIBONE_LIB_H
#include <stdint.h>
void *mbn_open(const char *if_name, uint8_t target_mac[]);
void mbn_writel(void *handle, uint32_t d, uint32_t a);
uint32_t mbn_readl(void *handle, uint32_t a);
void mbn_close(void *handle);
#endif
// Supports only raw ethernet now.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <linux/if_arp.h>
#include <linux/errqueue.h>
#include <linux/sockios.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <asm/types.h>
#include <fcntl.h>
#include <errno.h>
#include <asm/socket.h>
#include "ptpd_netif.h"
#ifdef NETIF_VERBOSE
#define netif_dbg(...) printf(__VA_ARGS__)
#else
#define netif_dbg(...)
#endif
#define ETHER_MTU 1518
#define DMTD_UPDATE_INTERVAL 100
struct scm_timestamping {
struct timespec systime;
struct timespec hwtimetrans;
struct timespec hwtimeraw;
};
PACKED struct etherpacket {
struct ethhdr ether;
char data[ETHER_MTU];
};
struct tx_timestamp {
int valid;
wr_timestamp_t ts;
uint32_t tag;
uint64_t t_acq;
};
struct my_socket {
int fd;
wr_sockaddr_t bind_addr;
mac_addr_t local_mac;
int if_index;
// parameters for linearization of RX timestamps
uint32_t clock_period;
uint32_t phase_transition;
uint32_t dmtd_phase;
};
struct nasty_hack{
char if_name[20];
int clockedAsPrimary;
};
#ifdef MACIEK_HACKs
struct nasty_hack locking_hack;
#endif
wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags,
wr_sockaddr_t *bind_addr)
{
struct my_socket *s;
struct sockaddr_ll sll;
struct ifreq f;
int fd;
// fprintf(stderr,"CreateSocket!\n");
if(sock_type != PTPD_SOCK_RAW_ETHERNET)
return NULL;
fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
if(fd < 0)
{
perror("socket()");
return NULL;
}
fcntl(fd, F_SETFL, O_NONBLOCK);
// Put the controller in promiscious mode, so it receives everything
strcpy(f.ifr_name, bind_addr->if_name);
if(ioctl(fd, SIOCGIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
f.ifr_flags |= IFF_PROMISC;
if(ioctl(fd, SIOCSIFFLAGS,&f) < 0) { perror("ioctl()"); return NULL; }
// Find the inteface index
strcpy(f.ifr_name, bind_addr->if_name);
ioctl(fd, SIOCGIFINDEX, &f);
sll.sll_ifindex = f.ifr_ifindex;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(bind_addr->ethertype);
sll.sll_halen = 6;
memcpy(sll.sll_addr, bind_addr->mac, 6);
if(bind(fd, (struct sockaddr *)&sll, sizeof(struct sockaddr_ll)) < 0)
{
close(fd);
perror("bind()");
return NULL;
}
s=calloc(sizeof(struct my_socket), 1);
s->if_index = f.ifr_ifindex;
// get interface MAC address
if (ioctl(fd, SIOCGIFHWADDR, &f) < 0) {
perror("ioctl()"); return NULL;
}
memcpy(s->local_mac, f.ifr_hwaddr.sa_data, 6);
memcpy(&s->bind_addr, bind_addr, sizeof(wr_sockaddr_t));
s->fd = fd;
return (wr_socket_t*)s;
}
int ptpd_netif_close_socket(wr_socket_t *sock)
{
struct my_socket *s = (struct my_socket *) sock;
if(!s)
return 0;
close(s->fd);
return 0;
}
int ptpd_netif_sendto(wr_socket_t *sock, wr_sockaddr_t *to, void *data,
size_t data_length, wr_timestamp_t *tx_ts)
{
struct etherpacket pkt;
struct my_socket *s = (struct my_socket *)sock;
struct sockaddr_ll sll;
int rval;
wr_timestamp_t ts;
if(s->bind_addr.family != PTPD_SOCK_RAW_ETHERNET)
return -ENOTSUP;
if(data_length > ETHER_MTU-8) return -EINVAL;
memset(&pkt, 0, sizeof(struct etherpacket));
memcpy(pkt.ether.h_dest, to->mac, 6);
memcpy(pkt.ether.h_source, s->local_mac, 6);
pkt.ether.h_proto =htons(to->ethertype);
memcpy(pkt.data, data, data_length);
size_t len = data_length + sizeof(struct ethhdr);
if(len < 72)
len = 72;
memset(&sll, 0, sizeof(struct sockaddr_ll));
sll.sll_ifindex = s->if_index;
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(to->ethertype);
sll.sll_halen = 6;
// fprintf(stderr,"fd %d ifi %d ethertype %d\n", s->fd,
// s->if_index, to->ethertype);
rval = sendto(s->fd, &pkt, len, 0, (struct sockaddr *)&sll,
sizeof(struct sockaddr_ll));
return rval;
}
int ptpd_netif_recvfrom(wr_socket_t *sock, wr_sockaddr_t *from, void *data,
size_t data_length, wr_timestamp_t *rx_timestamp)
{
struct my_socket *s = (struct my_socket *)sock;
struct etherpacket pkt;
struct msghdr msg;
struct iovec entry;
struct sockaddr_ll from_addr;
struct {
struct cmsghdr cm;
char control[1024];
} control;
struct cmsghdr *cmsg;
struct scm_timestamping *sts = NULL;
size_t len = data_length + sizeof(struct ethhdr);
memset(&msg, 0, sizeof(msg));
msg.msg_iov = &entry;
msg.msg_iovlen = 1;
entry.iov_base = &pkt;
entry.iov_len = len;
msg.msg_name = (caddr_t)&from_addr;
msg.msg_namelen = sizeof(from_addr);
msg.msg_control = &control;
msg.msg_controllen = sizeof(control);
int ret = recvmsg(s->fd, &msg, MSG_DONTWAIT);
if(ret < 0 && errno==EAGAIN) return 0; // would be blocking
if(ret == -EAGAIN) return 0;
if(ret <= 0) return ret;
memcpy(data, pkt.data, ret - sizeof(struct ethhdr));
from->ethertype = ntohs(pkt.ether.h_proto);
memcpy(from->mac, pkt.ether.h_source, 6);
memcpy(from->mac_dest, pkt.ether.h_dest, 6);
return ret - sizeof(struct ethhdr);
}
// Network API for WR-PTPd
#ifndef __PTPD_NETIF_H
#define __PTPD_NETIF_H
#include <stdio.h>
//#include <inttypes.h>
#define PTPD_SOCK_RAW_ETHERNET 1
#define PTPD_SOCK_UDP 2
#define PTPD_FLAGS_MULTICAST 0x1
// error codes (to be extended)
#define PTPD_NETIF_READY 1
#define PTPD_NETIF_OK 0
#define PTPD_NETIF_ERROR -1
#define PTPD_NETIF_NOT_READY -2
#define PTPD_NETIF_NOT_FOUND -3
// GCC-specific
#define PACKED __attribute__((packed))
#define PHYS_PORT_ANY (0xffff)
#define PTPD_NETIF_TX 1
#define PTPD_NETIF_RX 2
#define IFACE_NAME_LEN 16
#define SLAVE_PRIORITY_0 0
#define SLAVE_PRIORITY_1 1
#define SLAVE_PRIORITY_2 2
#define SLAVE_PRIORITY_3 3
#define SLAVE_PRIORITY_4 4
// Some system-independent definitions
typedef uint8_t mac_addr_t[6];
typedef uint32_t ipv4_addr_t;
// WhiteRabbit socket - it's void pointer as the real socket structure is private and probably platform-specific.
typedef void *wr_socket_t;
// Socket address for ptp_netif_ functions
typedef struct {
// Network interface name (eth0, ...)
char if_name[IFACE_NAME_LEN];
// Socket family (RAW ethernet/UDP)
int family;
// MAC address
mac_addr_t mac;
// Destination MASC address, filled by recvfrom() function on interfaces bound to multiple addresses
mac_addr_t mac_dest;
// IP address
ipv4_addr_t ip;
// UDP port
uint16_t port;
// RAW ethertype
uint16_t ethertype;
// physical port to bind socket to
uint16_t physical_port;
} wr_sockaddr_t;
typedef struct {
uint32_t v[4];
} wr_picoseconds_t;
// Precise WhiteRabbit timestamp
// TS[picoseconds] = utc * 1e12 + nsec * 1e3 + phase;
PACKED struct _wr_timestamp {
// UTC time value (seconds)
int64_t utc;
// Nanoseconds
int32_t nsec;
// Phase (in picoseconds), linearized for receive timestamps, zero for send timestamps
int32_t phase; // phase(picoseconds)
int32_t raw_phase;
int32_t raw_nsec;
int32_t raw_ahead;
//int cntr_ahead;
};
typedef struct _wr_timestamp wr_timestamp_t;
/* OK. These functions we'll develop along with network card driver. You can write your own UDP-based stubs for testing purposes. */
// Initialization of network interface:
// - opens devices
// - does necessary ioctls()
// - initializes connection with the mighty HAL daemon
int ptpd_netif_init();
// Creates UDP or Ethernet RAW socket (determined by sock_type) bound to bind_addr. If PTPD_FLAG_MULTICAST is set, the socket is
// automatically added to multicast group. User can specify physical_port field to bind the socket to specific switch port only.
wr_socket_t *ptpd_netif_create_socket(int sock_type, int flags, wr_sockaddr_t *bind_addr);
// Sends a UDP/RAW packet (data, data_length) to address provided in wr_sockaddr_t.
// For raw frames, mac/ethertype needs to be provided, for UDP - ip/port.
// Every transmitted frame has assigned a tag value, stored at tag parameter. This value is later used
// for recovering the precise transmit timestamp. If user doesn't need it, tag parameter can be left NULL.
int ptpd_netif_sendto(wr_socket_t *sock, wr_sockaddr_t *to, void *data, size_t data_length, wr_timestamp_t *tx_ts);
// Receives an UDP/RAW packet. Data is written to (data) and length is returned. Maximum buffer length can be specified
// by data_length parameter. Sender information is stored in structure specified in 'from'. All RXed packets are timestamped and the timestamp
// is stored in rx_timestamp (unless it's NULL).
int ptpd_netif_recvfrom(wr_socket_t *sock, wr_sockaddr_t *from, void *data, size_t data_length, wr_timestamp_t *rx_timestamp);
// Closes the socket.
int ptpd_netif_close_socket(wr_socket_t *sock);
int ptpd_netif_poll(wr_socket_t*);
int ptpd_netif_get_hw_addr(wr_socket_t *sock, mac_addr_t *mac);
/*
* Function start HW locking of freq on WR Slave
* return:
* PTPD_NETIF_ERROR - locking not started
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_locking_enable(int txrx, const char *ifaceName, int priority);
/*
*
* return:
*
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_locking_disable(int txrx, const char *ifaceName, int priority);
int ptpd_netif_locking_poll(int txrx, const char *ifaceName, int priority);
/*
* Function turns on calibration (measurement of delay)
* Tx or Rx depending on the txrx param
* return:
* PTPD_NETIF_NOT_READY - if there is calibratin going on on another port
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibrating_enable(int txrx, const char *ifaceName);
/*
* Function turns off calibration (measurement of delay)
* Tx or Rx depending on the txrx param
* return:
* PTPD_NETIF_ERROR - if there is calibratin going on on another port
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibrating_disable(int txrx, const char *ifaceName);
/*
* Function checks if Rx/Tx (depending on the param) calibration is finished
* if finished, returns measured delay in delta
* return:
*
* PTPD_NETIF_OK - locking started
*/
int ptpd_netif_calibrating_poll(int txrx, const char *ifaceName, uint64_t *delta);
/*
* Function turns on calibration pattern.
* return:
* PTPD_NETIF_NOT_READY - if WRSW is busy with calibration on other switch or error occured
* PTPD_NETIF_OK - calibration started
*/
int ptpd_netif_calibration_pattern_enable(const char *ifaceName, unsigned int calibrationPeriod, unsigned int calibrationPattern, unsigned int calibrationPatternLen);
/*
* Function turns off calibration pattern
* return:
* PTPD_NETIF_ERROR - turning off not successful
* PTPD_NETIF_OK - turning off successful
*/
int ptpd_netif_calibration_pattern_disable(const char *ifaceName);
/*
* Function read calibration data if it's available, used at the beginning of PTPWRd to check if
* HW knows already the interface's deltax, and therefore no need for calibration
* return:
* PTPD_NETIF_NOT_FOUND - if deltas are not known
* PTPD_NETIF_OK - if deltas are known, in such case, deltaTx and deltaRx have valid data
*/
int ptpd_netif_read_calibration_data(const char *ifaceName, uint64_t *deltaTx, uint64_t *deltaRx);
#define MACIEK_TMP
#ifdef MACIEK_TMP
int ptpd_netif_select(wr_socket_t*);
int ptpd_netif_get_hw_addr(wr_socket_t *sock, mac_addr_t *mac);
#endif
/*
* Function reads state of the given port (interface in our case), if the port is up, everything is OK, otherwise ERROR
* return:
* PTPD_NETIF_ERROR - if the port is down
* PTPD_NETIF_OK - if the port is up
*/
int ptpd_netif_get_port_state(const char *ifaceName);
/*
* Function looks for a port (interface) for the port number 'number'
* it will return in the argument ifname the port name
* return:
* PTPD_NETIF_ERROR - port not found
* PTPD_NETIF_OK - if the port found
*/
int ptpd_netif_get_ifName(char *ifname, int number);
/* Returns the millisecond "tics" counter value */
uint64_t ptpd_netif_get_msec_tics();
/*
* Function detects external source lock,
*
* return:
* HEXP_EXTSRC_STATUS_LOCKED 0
* HEXP_LOCK_STATUS_BUSY 1
* HEXP_EXTSRC_STATUS_NOSRC 2
*/
int ptpd_netif_extsrc_detection();
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment