|
@@ -329,8 +329,6 @@ struct rx_queue {
|
|
|
dma_addr_t rx_desc_dma;
|
|
|
int rx_desc_area_size;
|
|
|
struct sk_buff **rx_skb;
|
|
|
-
|
|
|
- struct timer_list rx_oom;
|
|
|
};
|
|
|
|
|
|
struct tx_queue {
|
|
@@ -372,6 +370,7 @@ struct mv643xx_eth_private {
|
|
|
u8 rxq_mask;
|
|
|
int rxq_primary;
|
|
|
struct napi_struct napi;
|
|
|
+ struct timer_list rx_oom;
|
|
|
struct rx_queue rxq[8];
|
|
|
|
|
|
/*
|
|
@@ -473,44 +472,43 @@ static void __txq_maybe_wake(struct tx_queue *txq)
|
|
|
/* rx ***********************************************************************/
|
|
|
static void txq_reclaim(struct tx_queue *txq, int force);
|
|
|
|
|
|
-static void rxq_refill(struct rx_queue *rxq)
|
|
|
+static int rxq_refill(struct rx_queue *rxq, int budget, int *oom)
|
|
|
{
|
|
|
- struct mv643xx_eth_private *mp = rxq_to_mp(rxq);
|
|
|
- unsigned long flags;
|
|
|
+ int skb_size;
|
|
|
+ int refilled;
|
|
|
|
|
|
- spin_lock_irqsave(&mp->lock, flags);
|
|
|
+ /*
|
|
|
+ * Reserve 2+14 bytes for an ethernet header (the hardware
|
|
|
+ * automatically prepends 2 bytes of dummy data to each
|
|
|
+ * received packet), 16 bytes for up to four VLAN tags, and
|
|
|
+ * 4 bytes for the trailing FCS -- 36 bytes total.
|
|
|
+ */
|
|
|
+ skb_size = rxq_to_mp(rxq)->dev->mtu + 36;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Make sure that the skb size is a multiple of 8 bytes, as
|
|
|
+ * the lower three bits of the receive descriptor's buffer
|
|
|
+ * size field are ignored by the hardware.
|
|
|
+ */
|
|
|
+ skb_size = (skb_size + 7) & ~7;
|
|
|
|
|
|
- while (rxq->rx_desc_count < rxq->rx_ring_size) {
|
|
|
- int skb_size;
|
|
|
+ refilled = 0;
|
|
|
+ while (refilled < budget && rxq->rx_desc_count < rxq->rx_ring_size) {
|
|
|
struct sk_buff *skb;
|
|
|
int unaligned;
|
|
|
int rx;
|
|
|
|
|
|
- /*
|
|
|
- * Reserve 2+14 bytes for an ethernet header (the
|
|
|
- * hardware automatically prepends 2 bytes of dummy
|
|
|
- * data to each received packet), 16 bytes for up to
|
|
|
- * four VLAN tags, and 4 bytes for the trailing FCS
|
|
|
- * -- 36 bytes total.
|
|
|
- */
|
|
|
- skb_size = mp->dev->mtu + 36;
|
|
|
-
|
|
|
- /*
|
|
|
- * Make sure that the skb size is a multiple of 8
|
|
|
- * bytes, as the lower three bits of the receive
|
|
|
- * descriptor's buffer size field are ignored by
|
|
|
- * the hardware.
|
|
|
- */
|
|
|
- skb_size = (skb_size + 7) & ~7;
|
|
|
-
|
|
|
skb = dev_alloc_skb(skb_size + dma_get_cache_alignment() - 1);
|
|
|
- if (skb == NULL)
|
|
|
+ if (skb == NULL) {
|
|
|
+ *oom = 1;
|
|
|
break;
|
|
|
+ }
|
|
|
|
|
|
unaligned = (u32)skb->data & (dma_get_cache_alignment() - 1);
|
|
|
if (unaligned)
|
|
|
skb_reserve(skb, dma_get_cache_alignment() - unaligned);
|
|
|
|
|
|
+ refilled++;
|
|
|
rxq->rx_desc_count++;
|
|
|
|
|
|
rx = rxq->rx_used_desc++;
|
|
@@ -534,15 +532,7 @@ static void rxq_refill(struct rx_queue *rxq)
|
|
|
skb_reserve(skb, 2);
|
|
|
}
|
|
|
|
|
|
- if (rxq->rx_desc_count != rxq->rx_ring_size)
|
|
|
- mod_timer(&rxq->rx_oom, jiffies + (HZ / 10));
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&mp->lock, flags);
|
|
|
-}
|
|
|
-
|
|
|
-static inline void rxq_refill_timer_wrapper(unsigned long data)
|
|
|
-{
|
|
|
- rxq_refill((struct rx_queue *)data);
|
|
|
+ return refilled;
|
|
|
}
|
|
|
|
|
|
static int rxq_process(struct rx_queue *rxq, int budget)
|
|
@@ -556,17 +546,12 @@ static int rxq_process(struct rx_queue *rxq, int budget)
|
|
|
struct rx_desc *rx_desc;
|
|
|
unsigned int cmd_sts;
|
|
|
struct sk_buff *skb;
|
|
|
- unsigned long flags;
|
|
|
-
|
|
|
- spin_lock_irqsave(&mp->lock, flags);
|
|
|
|
|
|
rx_desc = &rxq->rx_desc_area[rxq->rx_curr_desc];
|
|
|
|
|
|
cmd_sts = rx_desc->cmd_sts;
|
|
|
- if (cmd_sts & BUFFER_OWNED_BY_DMA) {
|
|
|
- spin_unlock_irqrestore(&mp->lock, flags);
|
|
|
+ if (cmd_sts & BUFFER_OWNED_BY_DMA)
|
|
|
break;
|
|
|
- }
|
|
|
rmb();
|
|
|
|
|
|
skb = rxq->rx_skb[rxq->rx_curr_desc];
|
|
@@ -576,8 +561,6 @@ static int rxq_process(struct rx_queue *rxq, int budget)
|
|
|
if (rxq->rx_curr_desc == rxq->rx_ring_size)
|
|
|
rxq->rx_curr_desc = 0;
|
|
|
|
|
|
- spin_unlock_irqrestore(&mp->lock, flags);
|
|
|
-
|
|
|
dma_unmap_single(NULL, rx_desc->buf_ptr,
|
|
|
rx_desc->buf_size, DMA_FROM_DEVICE);
|
|
|
rxq->rx_desc_count--;
|
|
@@ -635,15 +618,14 @@ static int rxq_process(struct rx_queue *rxq, int budget)
|
|
|
mp->dev->last_rx = jiffies;
|
|
|
}
|
|
|
|
|
|
- rxq_refill(rxq);
|
|
|
-
|
|
|
return rx;
|
|
|
}
|
|
|
|
|
|
static int mv643xx_eth_poll(struct napi_struct *napi, int budget)
|
|
|
{
|
|
|
struct mv643xx_eth_private *mp;
|
|
|
- int rx;
|
|
|
+ int work_done;
|
|
|
+ int oom;
|
|
|
int i;
|
|
|
|
|
|
mp = container_of(napi, struct mv643xx_eth_private, napi);
|
|
@@ -663,17 +645,32 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
- rx = 0;
|
|
|
- for (i = 7; rx < budget && i >= 0; i--)
|
|
|
- if (mp->rxq_mask & (1 << i))
|
|
|
- rx += rxq_process(mp->rxq + i, budget - rx);
|
|
|
+ work_done = 0;
|
|
|
+ oom = 0;
|
|
|
+ for (i = 7; work_done < budget && i >= 0; i--) {
|
|
|
+ if (mp->rxq_mask & (1 << i)) {
|
|
|
+ struct rx_queue *rxq = mp->rxq + i;
|
|
|
|
|
|
- if (rx < budget) {
|
|
|
+ work_done += rxq_process(rxq, budget - work_done);
|
|
|
+ work_done += rxq_refill(rxq, budget - work_done, &oom);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (work_done < budget) {
|
|
|
+ if (oom)
|
|
|
+ mod_timer(&mp->rx_oom, jiffies + (HZ / 10));
|
|
|
netif_rx_complete(mp->dev, napi);
|
|
|
wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT);
|
|
|
}
|
|
|
|
|
|
- return rx;
|
|
|
+ return work_done;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void oom_timer_wrapper(unsigned long data)
|
|
|
+{
|
|
|
+ struct mv643xx_eth_private *mp = (void *)data;
|
|
|
+
|
|
|
+ napi_schedule(&mp->napi);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -1565,10 +1562,6 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index)
|
|
|
nexti * sizeof(struct rx_desc);
|
|
|
}
|
|
|
|
|
|
- init_timer(&rxq->rx_oom);
|
|
|
- rxq->rx_oom.data = (unsigned long)rxq;
|
|
|
- rxq->rx_oom.function = rxq_refill_timer_wrapper;
|
|
|
-
|
|
|
return 0;
|
|
|
|
|
|
|
|
@@ -1591,8 +1584,6 @@ static void rxq_deinit(struct rx_queue *rxq)
|
|
|
|
|
|
rxq_disable(rxq);
|
|
|
|
|
|
- del_timer_sync(&rxq->rx_oom);
|
|
|
-
|
|
|
for (i = 0; i < rxq->rx_ring_size; i++) {
|
|
|
if (rxq->rx_skb[i]) {
|
|
|
dev_kfree_skb(rxq->rx_skb[i]);
|
|
@@ -1854,7 +1845,7 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id)
|
|
|
wrl(mp, INT_MASK(mp->port_num), 0x00000000);
|
|
|
rdl(mp, INT_MASK(mp->port_num));
|
|
|
|
|
|
- netif_rx_schedule(dev, &mp->napi);
|
|
|
+ napi_schedule(&mp->napi);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -2041,6 +2032,7 @@ static int mv643xx_eth_open(struct net_device *dev)
|
|
|
{
|
|
|
struct mv643xx_eth_private *mp = netdev_priv(dev);
|
|
|
int err;
|
|
|
+ int oom;
|
|
|
int i;
|
|
|
|
|
|
wrl(mp, INT_CAUSE(mp->port_num), 0);
|
|
@@ -2056,6 +2048,9 @@ static int mv643xx_eth_open(struct net_device *dev)
|
|
|
|
|
|
init_mac_tables(mp);
|
|
|
|
|
|
+ napi_enable(&mp->napi);
|
|
|
+
|
|
|
+ oom = 0;
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
if ((mp->rxq_mask & (1 << i)) == 0)
|
|
|
continue;
|
|
@@ -2068,7 +2063,12 @@ static int mv643xx_eth_open(struct net_device *dev)
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- rxq_refill(mp->rxq + i);
|
|
|
+ rxq_refill(mp->rxq + i, INT_MAX, &oom);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (oom) {
|
|
|
+ mp->rx_oom.expires = jiffies + (HZ / 10);
|
|
|
+ add_timer(&mp->rx_oom);
|
|
|
}
|
|
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
@@ -2084,8 +2084,6 @@ static int mv643xx_eth_open(struct net_device *dev)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- napi_enable(&mp->napi);
|
|
|
-
|
|
|
netif_carrier_off(dev);
|
|
|
netif_stop_queue(dev);
|
|
|
|
|
@@ -2150,6 +2148,8 @@ static int mv643xx_eth_stop(struct net_device *dev)
|
|
|
|
|
|
napi_disable(&mp->napi);
|
|
|
|
|
|
+ del_timer_sync(&mp->rx_oom);
|
|
|
+
|
|
|
netif_carrier_off(dev);
|
|
|
netif_stop_queue(dev);
|
|
|
|
|
@@ -2613,8 +2613,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
|
|
|
|
|
|
mp->dev = dev;
|
|
|
|
|
|
- netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 64);
|
|
|
-
|
|
|
set_params(mp, pd);
|
|
|
|
|
|
spin_lock_init(&mp->lock);
|
|
@@ -2633,6 +2631,12 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
|
|
|
}
|
|
|
init_pscr(mp, pd->speed, pd->duplex);
|
|
|
|
|
|
+ netif_napi_add(dev, &mp->napi, mv643xx_eth_poll, 128);
|
|
|
+
|
|
|
+ init_timer(&mp->rx_oom);
|
|
|
+ mp->rx_oom.data = (unsigned long)mp;
|
|
|
+ mp->rx_oom.function = oom_timer_wrapper;
|
|
|
+
|
|
|
|
|
|
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
|
|
|
BUG_ON(!res);
|