Commit 31013ca8 authored by Adam Wujek's avatar Adam Wujek 💬 Committed by Alessandro Rubini

wr_nic: apply patch form spec-sw "major cleanup of tx timestamping"

patch taken from spec-sw repo:
kernel/wr_nic: major cleanup of tx timestamping
ab3f2f8d18e4f6ed744438314e5a78b8a509de74
parent d986bbf5
......@@ -198,7 +198,7 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
__func__);
}
wrn->skb_desc[desc].skb = skb; /* Save for tx irq and stamping */
wrn->skb_desc[desc].id = id; /* Save for tx irq and stamping */
wrn->skb_desc[desc].frame_id = id; /* Save for tx irq and stamping */
//netif_stop_queue(dev); /* Queue stopped until tx is over (FIXME?) */
......@@ -512,7 +512,7 @@ static void wrn_tx_interrupt(struct wrn_dev *wrn)
/* hardware timestamping is enabled */
info->tx_flags |= SKBTX_IN_PROGRESS;
pr_debug("%s: %i -- in progress\n", __func__, __LINE__);
wrn_tstamp_find_skb(wrn, i);
wrn_tx_tstamp_skb(wrn, i);
/* It has been freed if found; otherwise keep it */
} else {
dev_kfree_skb_irq(skb);
......
......@@ -15,40 +15,29 @@
#include "wr-nic.h"
/* This looks for an skb in the already-received stamp list */
void wrn_tstamp_find_skb(struct wrn_dev *wrn, int desc)
/* This checks if we already received the timestamp interrupt */
void wrn_tx_tstamp_skb(struct wrn_dev *wrn, int desc)
{
struct skb_shared_hwtstamps *hwts;
struct sk_buff *skb = wrn->skb_desc[desc].skb;
struct wrn_desc_pending *d = wrn->skb_desc + desc;
struct sk_buff *skb = d->skb;
struct timespec ts;
int id = wrn->skb_desc[desc].id;
u32 counter_ppsg; /* PPS generator nanosecond counter */
u32 utc;
int i; /* FIXME: use list for faster access */
for(i = 0; i < WRN_TS_BUF_SIZE; i++)
if(wrn->ts_buf[i].valid && wrn->ts_buf[i].frame_id == id)
break;
if (i == WRN_TS_BUF_SIZE) {
pr_debug("%s: not found\n", __func__);
if (!wrn->skb_desc[desc].valid)
return;
}
pr_debug("%s: found\n", __func__);
/* so we found the skb, do the timestamping magic */
/* already reported by hardware: do the timestamping magic */
wrn_ppsg_read_time(wrn, &counter_ppsg, &utc);
/* The timestamp nanoseconds value is closer to the end of previous second, but the UTC time
read from PPSG is at the beginning of the next second: adjust UTC seconds to avoid 1 sec
"jump" */
if(counter_ppsg < REFCLK_FREQ/4 && wrn->ts_buf[i].ts > 3*REFCLK_FREQ/4)
/* We may be at the beginning og the next second */
if (counter_ppsg < d->cycles)
utc--;
ts.tv_sec = (s32)utc & 0x7fffffff;
ts.tv_nsec = wrn->ts_buf[i].ts * NSEC_PER_TICK;
if (! (wrn->ts_buf[i].valid & TS_INVALID))
{
ts.tv_nsec = d->cycles * NSEC_PER_TICK;
if (!(d->valid & TS_INVALID)) {
hwts = skb_hwtstamps(skb);
hwts->hwtstamp = timespec_to_ktime(ts);
skb_tstamp_tx(skb, hwts);
......@@ -56,68 +45,50 @@ void wrn_tstamp_find_skb(struct wrn_dev *wrn, int desc)
dev_kfree_skb_irq(skb);
/* release both the descriptor and the tstamp entry */
wrn->skb_desc[desc].skb = 0;
wrn->ts_buf[i].valid = 0;
d->skb = 0;
d->valid = 0;
}
/* This function records the timestamp in a list -- called from interrupt */
/* This function, called by txtsu records the timestamp for the descriptor */
static int record_tstamp(struct wrn_dev *wrn, u32 tsval, u32 idreg, u32 r2)
{
int port_id = TXTSU_TSF_R1_PID_R(idreg);
int frame_id = TXTSU_TSF_R1_FID_R(idreg);
int ts_incorrect = r2 & TXTSU_TSF_R2_INCORRECT;
struct skb_shared_hwtstamps *hwts;
struct timespec ts;
struct sk_buff *skb;
u32 utc, counter_ppsg; /* PPS generator nanosecond counter */
int i; /* FIXME: use list for faster access */
/*printk("%s: Got TS: %x pid %d fid %d\n", __func__,
tsval, port_id, frame_id);*/
int i;
/* First of all look if the skb is already pending */
/* Find the skb in the descriptor array */
for (i = 0; i < WRN_NR_DESC; i++)
if (wrn->skb_desc[i].skb && wrn->skb_desc[i].id == frame_id)
if (wrn->skb_desc[i].skb
&& wrn->skb_desc[i].frame_id == frame_id)
break;
if (i < WRN_NR_DESC) {
/*printk("%s: found\n", __func__);*/
skb = wrn->skb_desc[i].skb;
wrn_ppsg_read_time(wrn, &counter_ppsg, &utc);
if(counter_ppsg < (tsval & 0xfffffff))
utc--;
ts.tv_sec = (s32)utc & 0x7fffffff;
ts.tv_nsec = (tsval & 0xfffffff) * NSEC_PER_TICK;
/* Provide the timestamp for the userland only if we're 100% sure about its correctness */
if (!ts_incorrect)
{
hwts = skb_hwtstamps(skb);
hwts->hwtstamp = timespec_to_ktime(ts);
skb_tstamp_tx(skb, hwts);
}
dev_kfree_skb_irq(skb);
wrn->skb_desc[i].skb = 0;
if (i == WRN_NR_DESC) {
/* Not found: Must be a PTP frame sent from the SPEC! */
return 0;
}
/* Otherwise, save it to the list, in an empty slot */
for(i = 0; i < WRN_TS_BUF_SIZE; i++)
if(!wrn->ts_buf[i].valid)
break;
if (i == WRN_TS_BUF_SIZE) {
pr_debug("%s: ENOMEM\n", __func__);
return -ENOMEM;
skb = wrn->skb_desc[i].skb;
wrn_ppsg_read_time(wrn, &counter_ppsg, &utc);
if (counter_ppsg < (tsval & 0xfffffff))
utc--;
ts.tv_sec = (s32)utc & 0x7fffffff;
ts.tv_nsec = (tsval & 0xfffffff) * NSEC_PER_TICK;
/* Provide the timestamp only if 100% sure about its correctness */
if (!ts_incorrect) {
hwts = skb_hwtstamps(skb);
hwts->hwtstamp = timespec_to_ktime(ts);
skb_tstamp_tx(skb, hwts);
}
pr_debug("%s: save to slot %i\n", __func__, i);
wrn->ts_buf[i].ts = tsval;
wrn->ts_buf[i].port_id = port_id;
wrn->ts_buf[i].frame_id = frame_id;
wrn->ts_buf[i].valid = TS_PRESENT;
if (ts_incorrect)
wrn->ts_buf[i].valid |= TS_INVALID;
dev_kfree_skb_irq(skb);
wrn->skb_desc[i].skb = 0;
return 0;
}
......@@ -133,11 +104,7 @@ irqreturn_t wrn_tstamp_interrupt(int irq, void *dev_id)
r1 = readl(&regs->TSF_R1);
r2 = readl(&regs->TSF_R2);
if(record_tstamp(wrn, r0, r1, r2) < 0) {
printk("%s: ENOMEM in the TS buffer. Disabling TX stamping.\n",
__func__);
writel(TXTSU_EIC_IER_NEMPTY, &wrn->txtsu_regs->EIC_IDR);
}
record_tstamp(wrn, r0, r1, r2);
writel(TXTSU_EIC_IER_NEMPTY, &wrn->txtsu_regs->EIC_ISR); /* ack irq */
return IRQ_HANDLED;
}
......@@ -194,7 +161,6 @@ int wrn_tstamp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
void wrn_tstamp_init(struct wrn_dev *wrn)
{
memset(wrn->ts_buf, 0, sizeof(wrn->ts_buf));
/* enable TXTSU irq */
writel(TXTSU_EIC_IER_NEMPTY, &wrn->txtsu_regs->EIC_IER);
}
......
......@@ -65,27 +65,21 @@
#define WRN_IRQ_NAMES {"wr-nic", "wr-tstamp"}
#define WRN_IRQ_HANDLERS {wrn_interrupt, wrn_tstamp_interrupt}
#define WRN_TS_BUF_SIZE 1024 /* array of timestamp structures */
struct wrn_ep; /* Defined later */
/* A timestamping structure to keep information for user-space */
struct wrn_tx_tstamp {
/* We must remember skb, id and tstamp for each pending descriptor, */
struct wrn_desc_pending {
struct sk_buff *skb;
u8 valid;
u8 port_id;
u16 frame_id;
u32 ts;
u32 cycles;
};
/* bits for "valid" field */
#define TS_PRESENT 1
#define TS_INVALID 2 /* as reported by hw: we return 0 as timestamp */
/* We must remember both skb and id for each pending descriptor */
struct wrn_desc_pending {
struct sk_buff *skb;
u32 id; /* only 16 bits, actually */
};
/*
* This is the main data structure for our NIC device. As for locking,
* the rule is that _either_ the wrn _or_ the endpoint is locked. Not both.
......@@ -111,7 +105,6 @@ struct wrn_dev {
int id;
struct net_device *dev[WRN_NR_ENDPOINTS];
struct wrn_tx_tstamp ts_buf[WRN_TS_BUF_SIZE];
/* FIXME: all dev fields must be verified */
......@@ -247,7 +240,7 @@ extern int wrn_endpoint_probe(struct net_device *netdev);
extern void wrn_endpoint_remove(struct net_device *netdev);
/* Following functions from timestamp.c */
extern void wrn_tstamp_find_skb(struct wrn_dev *wrn, int i);
extern void wrn_tx_tstamp_skb(struct wrn_dev *wrn, int desc);
extern int wrn_tstamp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
extern irqreturn_t wrn_tstamp_interrupt(int irq, void *dev_id);
extern void wrn_tstamp_init(struct wrn_dev *wrn);
......
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