Commit 79e38916 authored by Alessandro Rubini's avatar Alessandro Rubini

wr-nic: move rx management in soft-irq context

parent b79fb98e
......@@ -120,6 +120,7 @@ static int __devinit wrn_probe(struct platform_device *pdev)
wrn->txd = ((void *)wrn->regs) + 0x80; /* was: TX1_D1 */
wrn->rxd = ((void *)wrn->regs) + 0x100; /* was: RX1_D1 */
wrn->databuf = (void *)wrn->regs + offsetof(struct NIC_WB, MEM);
tasklet_init(&wrn->rx_tlet, wrn_rx_interrupt, (unsigned long)wrn);
printk("regs %p, txd %p, rxd %p, buffer %p\n",
wrn->regs, wrn->txd, wrn->rxd, wrn->databuf);
......@@ -188,7 +189,7 @@ static int __devinit wrn_probe(struct platform_device *pdev)
wrn->next_tx_head = wrn->next_tx_tail = wrn->next_rx = 0;
writel(NIC_CR_RX_EN | NIC_CR_TX_EN, &wrn->regs->CR);
writel(~0, (void *)wrn->regs + 0x24 /* EIC_IER */);
writel(WRN_IRQ_ALL, (void *)wrn->regs + 0x24 /* EIC_IER */);
printk("imr: %08x\n", readl((void *)wrn->regs + 0x28 /* EIC_IMR */));
wrn_tstamp_init(wrn);
......
......@@ -379,9 +379,11 @@ static void __wrn_rx_descriptor(struct wrn_dev *wrn, int desc)
netif_receive_skb(skb);
}
static void wrn_rx_interrupt(struct wrn_dev *wrn)
/* This function is called in soft-irq context */
void wrn_rx_interrupt(unsigned long arg)
{
int desc;
struct wrn_dev *wrn = (void *)arg;
struct wrn_rxd __iomem *rx;
u32 reg;
......@@ -390,12 +392,14 @@ static void wrn_rx_interrupt(struct wrn_dev *wrn)
rx = wrn->rxd + desc;
reg = readl(&rx->rx1);
if (reg & NIC_RX1_D1_EMPTY)
return;
break;
__wrn_rx_descriptor(wrn, desc);
wrn->next_rx = __wrn_next_desc(desc);
}
writel(WRN_IRQ_ALL, (void *)wrn->regs + 0x24 /* IER */);
}
/* This, lazily, remains in hard-irq context */
static void wrn_tx_interrupt(struct wrn_dev *wrn)
{
struct wrn_txd *tx;
......@@ -454,8 +458,14 @@ irqreturn_t wrn_interrupt(int irq, void *dev_id)
}
if (irqs & NIC_EIC_ISR_RCOMP) {
pr_debug("%s: RX complete\n", __func__);
wrn_rx_interrupt(wrn);
/*
* This must be processed in soft-irq context, as this is
* what is needed for socket processing. So disable
* the interrupt first, then run the tasklet
*/
writel(WRN_IRQ_ALL_BUT_RX, (void *)wrn->regs + 0x24 /* IER */);
writel(NIC_EIC_ISR_RCOMP, (void *)regs + 0x2c);
tasklet_schedule(&wrn->rx_tlet);
}
return IRQ_HANDLED;
}
......@@ -73,6 +73,7 @@ struct wrn_dev {
struct PPSG_WB __iomem *ppsg_regs; /* ... */
spinlock_t lock;
struct tasklet_struct rx_tlet;
struct wrn_txd __iomem *txd;
struct wrn_rxd __iomem *rxd;
void __iomem *databuf; /* void to ease pointer arith */
......@@ -98,6 +99,11 @@ struct wrn_dev {
int irq_registered;
};
/* We need to disable the rx-complete interrupt, so get the masks */
#define WRN_IRQ_ALL (~0)
#define WRN_IRQ_ALL_BUT_RX (~NIC_EIC_IER_RCOMP)
#define WRN_IRQ_NONE 0
/* Each network device (endpoint) has one such priv structure */
struct wrn_ep {
struct wrn_dev *wrn;
......@@ -201,6 +207,7 @@ struct wrn_phase_req {
/* Following functions are in nic-core.c */
extern irqreturn_t wrn_interrupt(int irq, void *dev_id);
extern int wrn_netops_init(struct net_device *netdev);
extern void wrn_rx_interrupt(unsigned long arg); /* tasklet */
/* Following data in device.c */
struct platform_driver;
......
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