Commit ab7106d2 authored by Adam Wujek's avatar Adam Wujek

arch-wrs: uplift parts of libwr for WRS

add util.c for functions get_monotonic_*
Signed-off-by: Adam Wujek's avatarAdam Wujek <adam.wujek@cern.ch>
parent d040a207
......@@ -11,6 +11,7 @@ OBJ-y += $A/wrs-startup.o \
$A/wrs-calibration.o \
$A/wrs-ipcserver.o \
$A/shmem.o \
$A/util.o \
arch-unix/unix-conf.o \
lib/cmdline.o \
lib/conf.o \
......
......@@ -45,7 +45,7 @@ typedef struct hal_port_calibration {
int tx_calibrated;
struct shw_sfp_caldata sfp;
struct shw_sfp_header sfp_header_raw;
} hal_port_calibration_t;
/* Internal port state structure */
......@@ -110,7 +110,7 @@ struct hal_temp_sensors {
};
/* This is the overall structure stored in shared memory */
#define HAL_SHMEM_VERSION 8 /* Version 8 because of adding HAL mode */
#define HAL_SHMEM_VERSION 9 /* Version 9 because of adding sfp_header_raw */
struct hal_shmem_header {
int nports;
......
#ifndef __LIBWR_SHW_SFPLIB_H
#define __LIBWR_SHW_SFPLIB_H
#define SFP_LED_LINK (1 << 0)
#define SFP_LED_WRMODE (1 << 1)
/* note each led contains green and orange part */
#define SFP_LED_WRMODE_SLAVE (1) /* green */
#define SFP_LED_WRMODE_NON_WR (2) /* orange */
#define SFP_LED_WRMODE_MASTER (3) /* yellow */
#define SFP_LED_WRMODE_OFF (3) /* to off entire WRMODE LED */
#define SFP_LED_WRMODE1 (1 << 0)
#define SFP_LED_WRMODE2 (1 << 1)
#define SFP_LED_SYNCED (1 << 2)
#define SFP_TX_DISABLE (1 << 3)
#define shw_sfp_set_led_link(num, status) \
shw_sfp_set_generic(num, status, SFP_LED_LINK)
#define shw_sfp_set_led_wrmode(num, status) \
shw_sfp_set_generic(num, status, SFP_LED_WRMODE)
#define shw_sfp_set_led_synced(num, status) \
shw_sfp_set_generic(num, status, SFP_LED_SYNCED)
......@@ -20,6 +19,16 @@
#define SFP_FLAG_CLASS_DATA (1 << 0)
#define SFP_FLAG_DEVICE_DATA (1 << 1)
#define SFP_FLAG_1GbE (1 << 2) /* SFP is 1GbE */
#define SFP_FLAG_IN_DB (1 << 3) /* SFP is present in data base */
#define SFP_SPEED_1Gb 0x0D /* Speed of SFP in 100MB/s. According to
* SFF-8472.PDF: By convention 1.25 Gb/s
* should be rounded up to 0Dh (13 in
* units of 100 MBd) for Ethernet
* 1000BASE-X. */
#define SFP_SPEED_1Gb_10 0x0A /* Unfortunatelly the above is not always true,
* e.g. Cisco copper SFP (MGBT1) says simply 10 and not 13.*/
struct shw_sfp_caldata {
uint32_t flags;
......@@ -61,7 +70,8 @@ struct shw_sfp_header {
uint8_t vendor_oui[3];
uint8_t vendor_pn[16];
uint8_t vendor_rev[4];
uint8_t reserved4[3];
uint8_t tx_wavelength[2];
uint8_t reserved4;
uint8_t cc_base;
/* extended ID fields start here */
......@@ -107,7 +117,4 @@ int shw_sfp_read_verify_header(int num, struct shw_sfp_header *head);
struct shw_sfp_caldata *shw_sfp_get_cal_data(int num,
struct shw_sfp_header *head);
/* Read and verify the header all at once. returns -1 on failure */
int shw_sfp_read_verify_header(int num, struct shw_sfp_header *head);
#endif /* __LIBWR_SHW_SFPLIB_H */
......@@ -5,10 +5,12 @@
#ifndef __WRS_SHM_H__
#define __WRS_SHM_H__
#include <stdint.h>
#include <stdio.h>
#define WRS_SHM_FILE "/dev/shm/wrs-shmem-%i"
#define WRS_SHM_DEFAULT_PATH "/dev/shm"
#define WRS_SHM_FILE "wrs-shmem-%i"
#define WRS_SHM_MIN_SIZE (4*1024)
#define WRS_SHM_MAX_SIZE (256*1024)
#define WRS_SHM_MAX_SIZE (512*1024)
/* Each process "name" (i.e. id) is added to the filename above */
enum wrs_shm_name {
......@@ -40,10 +42,24 @@ struct wrs_shm_head {
#define WRS_SHM_WRITE 0x0001
#define WRS_SHM_LOCKED 0x0002 /* at init time: writers locks, readers wait */
/* Set custom path for shmem */
void wrs_shm_set_path(char *new_path);
/* Allow to ignore the flag WRS_SHM_LOCKED
* If this flag is not ignored then function wrs_shm_get_and_check is not able
* to open shmem successfully due to lack of process running with the given pid
*/
void wrs_shm_ignore_flag_locked(int ignore_flag);
/* get vs. put, like in the kernel. Errors are in errno (see source) */
void *wrs_shm_get(enum wrs_shm_name name_id, char *name, unsigned long flags);
int wrs_shm_put(void *headptr);
/* A reader may wait for the writer (polling on version field) */
void wrs_shm_wait(void *headptr, int msec_step, int retries, FILE *msg);
int wrs_shm_get_and_check(enum wrs_shm_name shm_name,
struct wrs_shm_head **head);
/* The writer can allocate structures that live in the area itself */
void *wrs_shm_alloc(void *headptr, size_t size);
......
#ifndef __LIBWR_HW_UTIL_H
#define __LIBWR_HW_UTIL_H
#include <stdio.h>
#include <inttypes.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define atoidef(argc, argv, param_i, def) (argc > (param_i) ? \
atoi(argv[(param_i)]) : (def))
#define strtoldef(argc, argv, param_i, def) (argc > (param_i) ? \
strtol(argv[(param_i)], NULL, 0) : (def))
void shw_udelay_init(void);
void shw_udelay(uint32_t microseconds);
/* get monotonic number of useconds */
uint64_t get_monotonic_tics(void);
/* get monotonic number of seconds */
time_t get_monotonic_sec(void);
/* Change endianess of the string, for example when accessing strings in
* the SoftPLL */
void strncpy_e(char *d, char *s, int len);
/* Create map */
void *create_map(unsigned long address, unsigned long size);
#endif /* __LIBWR_HW_UTIL_H */
......@@ -11,14 +11,38 @@
#include <sys/mman.h>
#include <libwr/shmem.h>
#define SHM_LOCK_TIMEOUT 2
#include <libwr/util.h>
#define SHM_LOCK_TIMEOUT_MS 50 /* in ms */
static char wrs_shm_path[50] = WRS_SHM_DEFAULT_PATH;
static int wrs_shm_locked = WRS_SHM_LOCKED;
/* Set custom path for shmem */
void wrs_shm_set_path(char *new_path)
{
strncpy(wrs_shm_path, new_path, 50);
}
/* Allow to ignore the flag WRS_SHM_LOCKED
* If this flag is not ignored then function wrs_shm_get_and_check is not able
* to open shmem successfully due to lack of process running with the given pid
*/
void wrs_shm_ignore_flag_locked(int ignore_flag)
{
if (ignore_flag)
wrs_shm_locked = 0;
else
wrs_shm_locked = WRS_SHM_LOCKED;
}
/* Get wrs shared memory */
/* return NULL and set errno on error */
void *wrs_shm_get(enum wrs_shm_name name_id, char *name, unsigned long flags)
{
struct wrs_shm_head *head;
struct stat stbuf;
struct timespec tv1, tv2;
uint64_t tv1, tv2;
void *map;
char fname[64];
int write_access = flags & WRS_SHM_WRITE;
......@@ -29,7 +53,7 @@ void *wrs_shm_get(enum wrs_shm_name name_id, char *name, unsigned long flags)
return NULL;
}
sprintf(fname, WRS_SHM_FILE, name_id);
sprintf(fname, "%.50s/"WRS_SHM_FILE, wrs_shm_path, name_id);
fd = open(fname, O_RDWR | O_CREAT | O_SYNC, 0644);
if (fd < 0)
return NULL; /* keep errno */
......@@ -51,10 +75,10 @@ void *wrs_shm_get(enum wrs_shm_name name_id, char *name, unsigned long flags)
if (!write_access) {
/* This is a reader: if locked, wait for a writer */
if (!(flags & WRS_SHM_LOCKED))
if (!(flags & wrs_shm_locked))
return map;
clock_gettime(CLOCK_MONOTONIC, &tv1);
tv1 = get_monotonic_tics();
while (1) {
/* Releasing does not mean initial data is in place! */
/* Read data with wrs_shm_seqbegin and
......@@ -63,8 +87,8 @@ void *wrs_shm_get(enum wrs_shm_name name_id, char *name, unsigned long flags)
return map;
usleep(10 * 1000);
clock_gettime(CLOCK_MONOTONIC, &tv2);
if (tv2.tv_sec - tv1.tv_sec < SHM_LOCK_TIMEOUT)
tv2 = get_monotonic_tics();
if (((tv2 - tv1) / 1000) < SHM_LOCK_TIMEOUT_MS)
continue;
errno = ETIMEDOUT;
......@@ -86,7 +110,7 @@ void *wrs_shm_get(enum wrs_shm_name name_id, char *name, unsigned long flags)
head->stamp = 0;
head->data_off = sizeof(*head);
head->data_size = 0;
if (flags & WRS_SHM_LOCKED)
if (flags & wrs_shm_locked)
head->sequence = 1; /* a sort of lock */
else
head->sequence = 0;
......@@ -113,6 +137,34 @@ int wrs_shm_put(void *headptr)
return 0;
}
/* Open shmem and check if data is available
* return 0 when ok, otherwise error
* 1 when openning shmem failed
* 2 when version is 0 */
int wrs_shm_get_and_check(enum wrs_shm_name shm_name,
struct wrs_shm_head **head)
{
int ii;
int version;
/* try to open shmem */
if (!(*head) && !(*head = wrs_shm_get(shm_name, "",
WRS_SHM_READ | WRS_SHM_LOCKED))) {
return 1;
}
ii = wrs_shm_seqbegin(*head);
/* read head version */
version = (*head)->version;
if (wrs_shm_seqretry(*head, ii) || !version) {
/* data in shmem available and version not zero */
return 2;
}
/* all ok */
return 0;
}
/* The writer can allocate structures that live in the area itself */
void *wrs_shm_alloc(void *headptr, size_t size)
{
......@@ -148,12 +200,10 @@ void *wrs_shm_follow(void *headptr, void *ptr)
void wrs_shm_write(void *headptr, int flags)
{
struct wrs_shm_head *head = headptr;
struct timespec tv;
if (flags == WRS_SHM_WRITE_END) {
/* At end-of-writing update the timestamp too */
clock_gettime(CLOCK_MONOTONIC, &tv);
head->stamp = tv.tv_sec;
head->stamp = get_monotonic_sec();
}
head->sequence++;
return;
......@@ -181,10 +231,8 @@ int wrs_shm_seqretry(void *headptr, unsigned start)
int wrs_shm_age(void *headptr)
{
struct wrs_shm_head *head = headptr;
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
return tv.tv_sec - head->stamp;
return get_monotonic_sec() - head->stamp;
}
/* A reader can get the information pointer, for a specific version, or NULL */
......
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <libwr/util.h>
#include <arpa/inet.h> /* for ntohl */
static int loops_per_msec = -1;
/* Calculate how many loops per millisecond we make in this CPU */
void shw_udelay_init(void)
{
volatile int i;
int j, cur, min = 0;
uint64_t tv1, tv2;
for (j = 0; j < 10; j++) {
tv1 = get_monotonic_tics();
for (i = 0; i < 100*1000; i++)
;
tv2 = get_monotonic_tics();
cur = tv2 - tv1;
/* keep minimum time, assuming we were scheduled-off less */
if (!min || cur < min)
min = cur;
}
loops_per_msec = i * 1000 / min;
if (0)
printf("loops per msec %i\n", loops_per_msec);
/*
* I get 39400 more or less; it makes sense at 197 bogomips.
* The loop is 6 instructions with 3 (cached) memory accesses
* and 1 jump. 197/39.4 = 5.0 .
*/
}
/*
* This function is needed to for slow delays to overcome the jiffy-grained
* delays that the kernel offers. We can't wait for 1ms when needing 4us.
*/
void shw_udelay(uint32_t microseconds)
{
volatile int i;
if (loops_per_msec < 0)
shw_udelay_init();
if (microseconds > 1000) {
usleep(microseconds);
return;
}
for (i = 0; i < loops_per_msec * microseconds / 1000; i++)
;
}
/* get monotonic number of useconds */
uint64_t get_monotonic_tics(void)
{
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
return (uint64_t) tv.tv_sec * 1000000ULL +
(uint64_t) (tv.tv_nsec / 1000);
}
/* get monotonic number of seconds */
time_t get_monotonic_sec(void)
{
struct timespec tv;
clock_gettime(CLOCK_MONOTONIC, &tv);
return tv.tv_sec;
}
/* change endianess of the string, for example when accessing strings in
* the SoftPLL */
void strncpy_e(char *d, char *s, int len)
{
int i;
int len_4;
uint32_t *s_i, *d_i;
s_i = (uint32_t *)s;
d_i = (uint32_t *)d;
len_4 = (len+3)/4; /* ceil len to word lenth (4) */
for (i = 0; i < len_4; i++)
d_i[i] = ntohl(s_i[i]);
}
void *create_map(unsigned long address, unsigned long size)
{
unsigned long ps = getpagesize();
unsigned long offset, fragment, len;
void *mapaddr;
int fd;
fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd < 0)
return NULL;
offset = address & ~(ps - 1);
fragment = address & (ps - 1);
len = address + size - offset;
mapaddr = mmap(0, len, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, offset);
close(fd);
if (mapaddr == MAP_FAILED)
return NULL;
return mapaddr + fragment;
}
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