Commit accbd802 authored by Alessandro Rubini's avatar Alessandro Rubini

misc code wrote on Dec 9th with Tom

parent 901772d6
......@@ -190,6 +190,8 @@ static int __devinit wrn_probe(struct platform_device *pdev)
writel(NIC_CR_RX_EN | NIC_CR_TX_EN, &wrn->regs->CR);
writel(~0, (void *)wrn->regs + 0x24 /* EIC_IER */);
printk("imr: %08x\n", readl((void *)wrn->regs + 0x28 /* EIC_IMR */));
wrn_tstamp_init(wrn);
err = 0;
out:
if (err) {
......
......@@ -114,7 +114,7 @@ static int __wrn_alloc_tx_desc(struct wrn_dev *wrn)
/* Actual transmission over a single endpoint */
static void __wrn_tx_desc(struct wrn_ep *ep, int desc,
void *data, int len, int id)
void *data, int len, int id, int do_stamp)
{
struct wrn_dev *wrn = ep->wrn;
int offset = __wrn_desc_offset(wrn, WRN_DDIR_TX, desc);
......@@ -133,11 +133,12 @@ static void __wrn_tx_desc(struct wrn_ep *ep, int desc,
writel(1<<ep->ep_number, &tx->tx3);
/* TX register 2: ofset and length */
/* TX register 2: offset and length */
writel(offset | (len << 16), &tx->tx2);
/* TX register 1: id and masks */
writel((len < 46 ? NIC_TX1_D1_PAD_E : 0) | NIC_TX1_D1_READY | (id << 16),
/* TX register 1: id and masks -- and tx_enable if needed */
writel((len < 60 ? NIC_TX1_D1_PAD_E : 0) | NIC_TX1_D1_READY
| (do_stamp ? NIC_TX1_D1_TS_E : 0) | (id << 16),
&tx->tx1);
}
......@@ -146,11 +147,12 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct wrn_ep *ep = netdev_priv(dev);
struct wrn_dev *wrn = ep->wrn;
//union skb_shared_tx *shtx = skb_tx(skb);
union skb_shared_tx *shtx = skb_tx(skb);
unsigned long flags;
int desc;
int id;
void *data;
int do_stamp = 0;
void *data; /* FIXME: move data and len to __wrn_tx_desc */
unsigned len;
if (unlikely(skb->len > WRN_MTU)) {
......@@ -162,7 +164,7 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Allocate a descriptor and id (start from last allocated) */
spin_lock_irqsave(&wrn->lock, flags);
desc = __wrn_alloc_tx_desc(wrn);
id = wrn->id++;
id = (wrn->id++) & 0xffff;
spin_unlock_irqrestore(&wrn->lock, flags);
if (desc < 0) /* error */
......@@ -173,27 +175,24 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
//spin_lock_irqsave(&ep->lock, flags);
wrn->skb_desc[desc] = skb; /* Save for tx irq and stamping */
//netif_stop_queue(dev); /* Queue stopped until tx is over (FIXME?) */
if (wrn->skb_desc[desc].skb) {
pr_err("%s: descriptor overflow: tx timestamp pending\n",
__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 */
if(test_bit(WRN_EP_STAMPING_TX, &ep->ep_flags)) {
#if 0 /* FIXME: the hw tx stamping */
struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
shtx->in_progress = 1;
*(u16 *) hwts = tx_oob = nic->tx_hwtstamp_oob;
//netif_stop_queue(dev); /* Queue stopped until tx is over (FIXME?) */
nic->tx_hwtstamp_oob ++;
if(nic->tx_hwtstamp_oob == 60000)
nic->tx_hwtstamp_oob = 1;
#endif
/* FIXME: check the WRN_EP_STAMPING_TX flag and its meaning */
if (shtx->hardware) {
/* hardware timestamping is enabled */
do_stamp = 1;
}
/* Mark the owner of this descriptor */
wrn->skb_desc[desc] = skb;
/* This both copies the data to the descriptr and fires tx */
printk("%s: %i\n", __func__, __LINE__);
__wrn_tx_desc(ep, desc, data, len, id);
__wrn_tx_desc(ep, desc, data, len, id, do_stamp);
printk("%s: %i\n", __func__, __LINE__);
/* We are done, this is trivial maiintainance*/
......@@ -306,8 +305,6 @@ static void __wrn_rx_descriptor(struct wrn_dev *wrn, int desc)
dev = wrn->dev[epnum];
ep = netdev_priv(dev);
/* FIXME: rx timestamp */
/* Data and length */
off = NIC_RX1_D3_OFFSET_R(r3);
len = NIC_RX1_D3_LEN_R(r3);
......@@ -375,6 +372,7 @@ static void wrn_tx_interrupt(struct wrn_dev *wrn)
{
struct wrn_txd *tx;
struct sk_buff *skb;
union skb_shared_tx *shtx;
u32 reg;
int i;
......@@ -386,12 +384,19 @@ static void wrn_tx_interrupt(struct wrn_dev *wrn)
if (reg & NIC_TX1_D1_READY)
return; /* no more */
skb = wrn->skb_desc[i];
/* FIXME: get the stamp from the fifo */
dev_kfree_skb_irq(skb);
wrn->skb_desc[i] = 0;
skb = wrn->skb_desc[i].skb;
shtx = skb_tx(skb);
if (shtx->hardware) {
/* hardware timestamping is enabled */
shtx->in_progress = 1;
printk("%s: %i -- in progress\n", __func__, __LINE__);
wrn_tstamp_find_skb(wrn, i);
/* It has been freed if found; otherwise keep it */
} else {
dev_kfree_skb_irq(skb);
wrn->skb_desc[i].skb = 0;
}
wrn->next_tx_tail = __wrn_next_desc(i);
}
}
......
......@@ -15,46 +15,101 @@
#include "wr-nic.h"
static int record_tstamp(struct wrn_dev *wrn, u32 ts, u8 port_id, u16 frame_id)
/* This looks for an skb in the already-received stamp list */
void wrn_tstamp_find_skb(struct wrn_dev *wrn, int desc)
{
struct skb_shared_hwtstamps *hwts;
struct sk_buff *skb = wrn->skb_desc[desc].skb;
int id = wrn->skb_desc[desc].id;
u32 counter_ppsg; /* PPS generator nanosecond counter */
u32 utc;
int i; /* FIXME: use list for faster access */
pr_debug("%s: Got TS: %x pid %d fid %d\n", __func__,
ts, port_id, frame_id);
for(i=0;i<WRN_TS_BUF_SIZE;i++)
if(!wrn->ts_buf[i].valid) {
wrn->ts_buf[i].ts = ts;
wrn->ts_buf[i].port_id = port_id;
wrn->ts_buf[i].frame_id = frame_id;
wrn->ts_buf[i].valid = 1;
return 0;
}
/* no space in TS buffer? */
return -ENOMEM;
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__);
return;
}
pr_debug("%s: found\n", __func__);
/* so we found the skb, do the timestamping magic */
hwts = skb_hwtstamps(skb);
wrn_ppsg_read_time(wrn, &counter_ppsg, &utc);
if(counter_ppsg < wrn->ts_buf[i].ts)
utc--;
hwts->hwtstamp.tv.sec = (s32)utc & 0x7fffffff;
hwts->hwtstamp.tv.nsec = wrn->ts_buf[i].ts * 8; /* scale to nsecs */
skb_tstamp_tx(skb, hwts);
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;
}
void wrn_tstamp_init(struct wrn_dev *wrn)
/* This function records the timestamp in a list -- called from interrupt */
static int record_tstamp(struct wrn_dev *wrn, u32 ts, u32 idreg)
{
memset(wrn->ts_buf, 0, sizeof(wrn->ts_buf));
/* enable TXTSU irq */
writel(TXTSU_EIC_IER_NEMPTY, &wrn->txtsu_regs->EIC_IER);
int port_id = TXTSU_TSF_R1_PID_R(idreg);
int frame_id = TXTSU_TSF_R1_FID_R(idreg);
struct skb_shared_hwtstamps *hwts;
struct sk_buff *skb;
u32 utc, counter_ppsg; /* PPS generator nanosecond counter */
int i; /* FIXME: use list for faster access */
pr_debug("%s: Got TS: %x pid %d fid %d\n", __func__,
ts, port_id, frame_id);
/* First of all look if the skb is already pending */
for (i = 0; i < WRN_NR_DESC; i++)
if (wrn->skb_desc[i].skb && wrn->skb_desc[i].id == frame_id)
break;
if (i < WRN_NR_DESC) {
pr_debug("%s: found\n", __func__);
skb = wrn->skb_desc[i].skb;
hwts = skb_hwtstamps(skb);
wrn_ppsg_read_time(wrn, &counter_ppsg, &utc);
if(counter_ppsg < wrn->ts_buf[i].ts)
utc--;
hwts->hwtstamp.tv.sec = (s32)utc & 0x7fffffff;
hwts->hwtstamp.tv.nsec = ts * 8; /* scale to nanoseconds */
skb_tstamp_tx(skb, hwts);
dev_kfree_skb_irq(skb);
wrn->skb_desc[i].skb = 0;
}
/* Otherwise, save it to the list */
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;
}
pr_debug("%s: save to slot %i\n", __func__, i);
wrn->ts_buf[i].ts = ts;
wrn->ts_buf[i].port_id = port_id;
wrn->ts_buf[i].frame_id = frame_id;
wrn->ts_buf[i].valid = 1;
return 0;
}
irqreturn_t wrn_tstamp_interrupt(int irq, void *dev_id)
{
struct wrn_dev *wrn = dev_id;
struct TXTSU_WB *regs = wrn->txtsu_regs;
/* FIXME: locking */
u32 r0, r1;
printk("%s: %i\n", __func__, __LINE__);
/* FIXME: locking */
r0 = readl(&regs->TSF_R0);
r1 = readl(&regs->TSF_R1);
if(record_tstamp(wrn, r0,
TXTSU_TSF_R1_PID_R(r1),
TXTSU_TSF_R1_FID_R(r1)) < 0) {
if(record_tstamp(wrn, r0, r1) < 0) {
printk("%s: ENOMEM in the TS buffer. Disabling TX stamping.\n",
__func__);
writel(TXTSU_EIC_IER_NEMPTY, &wrn->txtsu_regs->EIC_IDR);
......@@ -112,3 +167,11 @@ int wrn_tstamp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EFAULT;
return 0;
}
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);
}
......@@ -46,10 +46,10 @@
{NULL, wrn_interrupt, NULL, NULL, wrn_tstamp_interrupt}
#endif
/* Temporarily, one handler only */
#define WRN_IRQ_NUMBERS {WRN_IRQ_NIC}
#define WRN_IRQ_NAMES {"wr-nic"}
#define WRN_IRQ_HANDLERS {wrn_interrupt}
/* Temporarily, two handlers only */
#define WRN_IRQ_NUMBERS {WRN_IRQ_NIC, WRN_IRQ_TSTAMP}
#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 */
......@@ -63,6 +63,12 @@ struct wrn_tx_tstamp {
u32 ts;
};
/* 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.
......@@ -83,7 +89,7 @@ struct wrn_dev {
int next_rx;
/* For TX descriptors, we must keep track of the ownwer */
struct sk_buff *skb_desc[WRN_NR_TXDESC];
struct wrn_desc_pending skb_desc[WRN_NR_TXDESC];
int id;
struct net_device *dev[WRN_NR_ENDPOINTS];
......@@ -213,8 +219,10 @@ 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 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);
/* Following functions from dmtd.c */
extern int wrn_phase_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
......
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