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) ...@@ -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(NIC_CR_RX_EN | NIC_CR_TX_EN, &wrn->regs->CR);
writel(~0, (void *)wrn->regs + 0x24 /* EIC_IER */); writel(~0, (void *)wrn->regs + 0x24 /* EIC_IER */);
printk("imr: %08x\n", readl((void *)wrn->regs + 0x28 /* EIC_IMR */)); printk("imr: %08x\n", readl((void *)wrn->regs + 0x28 /* EIC_IMR */));
wrn_tstamp_init(wrn);
err = 0; err = 0;
out: out:
if (err) { if (err) {
......
...@@ -114,7 +114,7 @@ static int __wrn_alloc_tx_desc(struct wrn_dev *wrn) ...@@ -114,7 +114,7 @@ static int __wrn_alloc_tx_desc(struct wrn_dev *wrn)
/* Actual transmission over a single endpoint */ /* Actual transmission over a single endpoint */
static void __wrn_tx_desc(struct wrn_ep *ep, int desc, 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; struct wrn_dev *wrn = ep->wrn;
int offset = __wrn_desc_offset(wrn, WRN_DDIR_TX, desc); 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, ...@@ -133,11 +133,12 @@ static void __wrn_tx_desc(struct wrn_ep *ep, int desc,
writel(1<<ep->ep_number, &tx->tx3); 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); writel(offset | (len << 16), &tx->tx2);
/* TX register 1: id and masks */ /* TX register 1: id and masks -- and tx_enable if needed */
writel((len < 46 ? NIC_TX1_D1_PAD_E : 0) | NIC_TX1_D1_READY | (id << 16), 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); &tx->tx1);
} }
...@@ -146,11 +147,12 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -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_ep *ep = netdev_priv(dev);
struct wrn_dev *wrn = ep->wrn; 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; unsigned long flags;
int desc; int desc;
int id; int id;
void *data; int do_stamp = 0;
void *data; /* FIXME: move data and len to __wrn_tx_desc */
unsigned len; unsigned len;
if (unlikely(skb->len > WRN_MTU)) { if (unlikely(skb->len > WRN_MTU)) {
...@@ -162,7 +164,7 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -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) */ /* Allocate a descriptor and id (start from last allocated) */
spin_lock_irqsave(&wrn->lock, flags); spin_lock_irqsave(&wrn->lock, flags);
desc = __wrn_alloc_tx_desc(wrn); desc = __wrn_alloc_tx_desc(wrn);
id = wrn->id++; id = (wrn->id++) & 0xffff;
spin_unlock_irqrestore(&wrn->lock, flags); spin_unlock_irqrestore(&wrn->lock, flags);
if (desc < 0) /* error */ if (desc < 0) /* error */
...@@ -173,27 +175,24 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -173,27 +175,24 @@ static int wrn_start_xmit(struct sk_buff *skb, struct net_device *dev)
//spin_lock_irqsave(&ep->lock, flags); //spin_lock_irqsave(&ep->lock, flags);
wrn->skb_desc[desc] = skb; /* Save for tx irq and stamping */ if (wrn->skb_desc[desc].skb) {
//netif_stop_queue(dev); /* Queue stopped until tx is over (FIXME?) */ 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)) { //netif_stop_queue(dev); /* Queue stopped until tx is over (FIXME?) */
#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;
nic->tx_hwtstamp_oob ++; /* FIXME: check the WRN_EP_STAMPING_TX flag and its meaning */
if(nic->tx_hwtstamp_oob == 60000) if (shtx->hardware) {
nic->tx_hwtstamp_oob = 1; /* hardware timestamping is enabled */
#endif 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 */ /* This both copies the data to the descriptr and fires tx */
printk("%s: %i\n", __func__, __LINE__); 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__); printk("%s: %i\n", __func__, __LINE__);
/* We are done, this is trivial maiintainance*/ /* We are done, this is trivial maiintainance*/
...@@ -306,8 +305,6 @@ static void __wrn_rx_descriptor(struct wrn_dev *wrn, int desc) ...@@ -306,8 +305,6 @@ static void __wrn_rx_descriptor(struct wrn_dev *wrn, int desc)
dev = wrn->dev[epnum]; dev = wrn->dev[epnum];
ep = netdev_priv(dev); ep = netdev_priv(dev);
/* FIXME: rx timestamp */
/* Data and length */ /* Data and length */
off = NIC_RX1_D3_OFFSET_R(r3); off = NIC_RX1_D3_OFFSET_R(r3);
len = NIC_RX1_D3_LEN_R(r3); len = NIC_RX1_D3_LEN_R(r3);
...@@ -375,6 +372,7 @@ static void wrn_tx_interrupt(struct wrn_dev *wrn) ...@@ -375,6 +372,7 @@ static void wrn_tx_interrupt(struct wrn_dev *wrn)
{ {
struct wrn_txd *tx; struct wrn_txd *tx;
struct sk_buff *skb; struct sk_buff *skb;
union skb_shared_tx *shtx;
u32 reg; u32 reg;
int i; int i;
...@@ -386,12 +384,19 @@ static void wrn_tx_interrupt(struct wrn_dev *wrn) ...@@ -386,12 +384,19 @@ static void wrn_tx_interrupt(struct wrn_dev *wrn)
if (reg & NIC_TX1_D1_READY) if (reg & NIC_TX1_D1_READY)
return; /* no more */ return; /* no more */
skb = wrn->skb_desc[i]; skb = wrn->skb_desc[i].skb;
shtx = skb_tx(skb);
/* FIXME: get the stamp from the fifo */
if (shtx->hardware) {
dev_kfree_skb_irq(skb); /* hardware timestamping is enabled */
wrn->skb_desc[i] = 0; 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); wrn->next_tx_tail = __wrn_next_desc(i);
} }
} }
......
...@@ -15,46 +15,101 @@ ...@@ -15,46 +15,101 @@
#include "wr-nic.h" #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 */ 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++) for(i = 0; i < WRN_TS_BUF_SIZE; i++)
if(!wrn->ts_buf[i].valid) { if(wrn->ts_buf[i].valid && wrn->ts_buf[i].frame_id == id)
wrn->ts_buf[i].ts = ts; break;
wrn->ts_buf[i].port_id = port_id;
wrn->ts_buf[i].frame_id = frame_id; if (i == WRN_TS_BUF_SIZE) {
wrn->ts_buf[i].valid = 1; pr_debug("%s: not found\n", __func__);
return 0; return;
} }
pr_debug("%s: found\n", __func__);
/* no space in TS buffer? */
return -ENOMEM; /* 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)); int port_id = TXTSU_TSF_R1_PID_R(idreg);
/* enable TXTSU irq */ int frame_id = TXTSU_TSF_R1_FID_R(idreg);
writel(TXTSU_EIC_IER_NEMPTY, &wrn->txtsu_regs->EIC_IER); 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) irqreturn_t wrn_tstamp_interrupt(int irq, void *dev_id)
{ {
struct wrn_dev *wrn = dev_id; struct wrn_dev *wrn = dev_id;
struct TXTSU_WB *regs = wrn->txtsu_regs; struct TXTSU_WB *regs = wrn->txtsu_regs;
/* FIXME: locking */
u32 r0, r1; u32 r0, r1;
printk("%s: %i\n", __func__, __LINE__);
/* FIXME: locking */
r0 = readl(&regs->TSF_R0); r0 = readl(&regs->TSF_R0);
r1 = readl(&regs->TSF_R1); r1 = readl(&regs->TSF_R1);
if(record_tstamp(wrn, r0, if(record_tstamp(wrn, r0, r1) < 0) {
TXTSU_TSF_R1_PID_R(r1),
TXTSU_TSF_R1_FID_R(r1)) < 0) {
printk("%s: ENOMEM in the TS buffer. Disabling TX stamping.\n", printk("%s: ENOMEM in the TS buffer. Disabling TX stamping.\n",
__func__); __func__);
writel(TXTSU_EIC_IER_NEMPTY, &wrn->txtsu_regs->EIC_IDR); 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) ...@@ -112,3 +167,11 @@ int wrn_tstamp_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
return -EFAULT; return -EFAULT;
return 0; 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 @@ ...@@ -46,10 +46,10 @@
{NULL, wrn_interrupt, NULL, NULL, wrn_tstamp_interrupt} {NULL, wrn_interrupt, NULL, NULL, wrn_tstamp_interrupt}
#endif #endif
/* Temporarily, one handler only */ /* Temporarily, two handlers only */
#define WRN_IRQ_NUMBERS {WRN_IRQ_NIC} #define WRN_IRQ_NUMBERS {WRN_IRQ_NIC, WRN_IRQ_TSTAMP}
#define WRN_IRQ_NAMES {"wr-nic"} #define WRN_IRQ_NAMES {"wr-nic", "wr-tstamp"}
#define WRN_IRQ_HANDLERS {wrn_interrupt} #define WRN_IRQ_HANDLERS {wrn_interrupt, wrn_tstamp_interrupt}
#define WRN_TS_BUF_SIZE 1024 /* array of timestamp structures */ #define WRN_TS_BUF_SIZE 1024 /* array of timestamp structures */
...@@ -63,6 +63,12 @@ struct wrn_tx_tstamp { ...@@ -63,6 +63,12 @@ struct wrn_tx_tstamp {
u32 ts; 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, * 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. * the rule is that _either_ the wrn _or_ the endpoint is locked. Not both.
...@@ -83,7 +89,7 @@ struct wrn_dev { ...@@ -83,7 +89,7 @@ struct wrn_dev {
int next_rx; int next_rx;
/* For TX descriptors, we must keep track of the ownwer */ /* 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; int id;
struct net_device *dev[WRN_NR_ENDPOINTS]; struct net_device *dev[WRN_NR_ENDPOINTS];
...@@ -213,8 +219,10 @@ extern int wrn_endpoint_probe(struct net_device *netdev); ...@@ -213,8 +219,10 @@ extern int wrn_endpoint_probe(struct net_device *netdev);
extern void wrn_endpoint_remove(struct net_device *netdev); extern void wrn_endpoint_remove(struct net_device *netdev);
/* Following functions from timestamp.c */ /* 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 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 irqreturn_t wrn_tstamp_interrupt(int irq, void *dev_id);
extern void wrn_tstamp_init(struct wrn_dev *wrn);
/* Following functions from dmtd.c */ /* Following functions from dmtd.c */
extern int wrn_phase_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); 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