|
@@ -1050,6 +1050,66 @@ static void show_rx_chain(struct spider_net_card *card)
|
|
|
}
|
|
|
#endif
|
|
|
|
|
|
+/**
|
|
|
+ * spider_net_resync_head_ptr - Advance head ptr past empty descrs
|
|
|
+ *
|
|
|
+ * If the driver fails to keep up and empty the queue, then the
|
|
|
+ * hardware wil run out of room to put incoming packets. This
|
|
|
+ * will cause the hardware to skip descrs that are full (instead
|
|
|
+ * of halting/retrying). Thus, once the driver runs, it wil need
|
|
|
+ * to "catch up" to where the hardware chain pointer is at.
|
|
|
+ */
|
|
|
+static void spider_net_resync_head_ptr(struct spider_net_card *card)
|
|
|
+{
|
|
|
+ unsigned long flags;
|
|
|
+ struct spider_net_descr_chain *chain = &card->rx_chain;
|
|
|
+ struct spider_net_descr *descr;
|
|
|
+ int i, status;
|
|
|
+
|
|
|
+ /* Advance head pointer past any empty descrs */
|
|
|
+ descr = chain->head;
|
|
|
+ status = spider_net_get_descr_status(descr->hwdescr);
|
|
|
+
|
|
|
+ if (status == SPIDER_NET_DESCR_NOT_IN_USE)
|
|
|
+ return;
|
|
|
+
|
|
|
+ spin_lock_irqsave(&chain->lock, flags);
|
|
|
+
|
|
|
+ descr = chain->head;
|
|
|
+ status = spider_net_get_descr_status(descr->hwdescr);
|
|
|
+ for (i=0; i<chain->num_desc; i++) {
|
|
|
+ if (status != SPIDER_NET_DESCR_CARDOWNED) break;
|
|
|
+ descr = descr->next;
|
|
|
+ status = spider_net_get_descr_status(descr->hwdescr);
|
|
|
+ }
|
|
|
+ chain->head = descr;
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&chain->lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
+static int spider_net_resync_tail_ptr(struct spider_net_card *card)
|
|
|
+{
|
|
|
+ struct spider_net_descr_chain *chain = &card->rx_chain;
|
|
|
+ struct spider_net_descr *descr;
|
|
|
+ int i, status;
|
|
|
+
|
|
|
+ /* Advance tail pointer past any empty and reaped descrs */
|
|
|
+ descr = chain->tail;
|
|
|
+ status = spider_net_get_descr_status(descr->hwdescr);
|
|
|
+
|
|
|
+ for (i=0; i<chain->num_desc; i++) {
|
|
|
+ if ((status != SPIDER_NET_DESCR_CARDOWNED) &&
|
|
|
+ (status != SPIDER_NET_DESCR_NOT_IN_USE)) break;
|
|
|
+ descr = descr->next;
|
|
|
+ status = spider_net_get_descr_status(descr->hwdescr);
|
|
|
+ }
|
|
|
+ chain->tail = descr;
|
|
|
+
|
|
|
+ if ((i == chain->num_desc) || (i == 0))
|
|
|
+ return 1;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* spider_net_decode_one_descr - processes an RX descriptor
|
|
|
* @card: card structure
|
|
@@ -1175,6 +1235,12 @@ spider_net_poll(struct net_device *netdev, int *budget)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if ((packets_done == 0) && (card->num_rx_ints != 0)) {
|
|
|
+ no_more_packets = spider_net_resync_tail_ptr(card);
|
|
|
+ spider_net_resync_head_ptr(card);
|
|
|
+ }
|
|
|
+ card->num_rx_ints = 0;
|
|
|
+
|
|
|
netdev->quota -= packets_done;
|
|
|
*budget -= packets_done;
|
|
|
spider_net_refill_rx_chain(card);
|
|
@@ -1421,7 +1487,11 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
|
|
|
if (netif_msg_intr(card) && net_ratelimit())
|
|
|
pr_err("Spider RX RAM full, incoming packets "
|
|
|
"might be discarded!\n");
|
|
|
- spider_net_rx_irq_off(card);
|
|
|
+ /* Could happen when rx chain is full */
|
|
|
+ spider_net_resync_head_ptr(card);
|
|
|
+ spider_net_refill_rx_chain(card);
|
|
|
+ spider_net_enable_rxdmac(card);
|
|
|
+ card->num_rx_ints ++;
|
|
|
netif_rx_schedule(card->netdev);
|
|
|
show_error = 0;
|
|
|
break;
|
|
@@ -1437,12 +1507,11 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
|
|
|
case SPIDER_NET_GDCDCEINT: /* fallthrough */
|
|
|
case SPIDER_NET_GDBDCEINT: /* fallthrough */
|
|
|
case SPIDER_NET_GDADCEINT:
|
|
|
- if (netif_msg_intr(card) && net_ratelimit())
|
|
|
- pr_err("got descriptor chain end interrupt, "
|
|
|
- "restarting DMAC %c.\n",
|
|
|
- 'D'-(i-SPIDER_NET_GDDDCEINT)/3);
|
|
|
+ spider_net_resync_head_ptr(card);
|
|
|
spider_net_refill_rx_chain(card);
|
|
|
spider_net_enable_rxdmac(card);
|
|
|
+ card->num_rx_ints ++;
|
|
|
+ netif_rx_schedule(card->netdev);
|
|
|
show_error = 0;
|
|
|
break;
|
|
|
|
|
@@ -1451,9 +1520,12 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
|
|
|
case SPIDER_NET_GDCINVDINT: /* fallthrough */
|
|
|
case SPIDER_NET_GDBINVDINT: /* fallthrough */
|
|
|
case SPIDER_NET_GDAINVDINT:
|
|
|
- /* could happen when rx chain is full */
|
|
|
+ /* Could happen when rx chain is full */
|
|
|
+ spider_net_resync_head_ptr(card);
|
|
|
spider_net_refill_rx_chain(card);
|
|
|
spider_net_enable_rxdmac(card);
|
|
|
+ card->num_rx_ints ++;
|
|
|
+ netif_rx_schedule(card->netdev);
|
|
|
show_error = 0;
|
|
|
break;
|
|
|
|
|
@@ -1546,6 +1618,7 @@ spider_net_interrupt(int irq, void *ptr)
|
|
|
if (status_reg & SPIDER_NET_RXINT ) {
|
|
|
spider_net_rx_irq_off(card);
|
|
|
netif_rx_schedule(netdev);
|
|
|
+ card->num_rx_ints ++;
|
|
|
}
|
|
|
if (status_reg & SPIDER_NET_TXINT)
|
|
|
netif_rx_schedule(netdev);
|
|
@@ -2191,6 +2264,7 @@ spider_net_setup_netdev(struct spider_net_card *card)
|
|
|
* NETIF_F_HW_VLAN_FILTER */
|
|
|
|
|
|
netdev->irq = card->pdev->irq;
|
|
|
+ card->num_rx_ints = 0;
|
|
|
|
|
|
dn = pci_device_to_OF_node(card->pdev);
|
|
|
if (!dn)
|