diff options
-rw-r--r-- | drivers/net/spider_net.c | 86 | ||||
-rw-r--r-- | drivers/net/spider_net.h | 3 |
2 files changed, 82 insertions, 7 deletions
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 69005d113d4d..c99980a14203 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c | |||
@@ -1051,6 +1051,66 @@ static void show_rx_chain(struct spider_net_card *card) | |||
1051 | #endif | 1051 | #endif |
1052 | 1052 | ||
1053 | /** | 1053 | /** |
1054 | * spider_net_resync_head_ptr - Advance head ptr past empty descrs | ||
1055 | * | ||
1056 | * If the driver fails to keep up and empty the queue, then the | ||
1057 | * hardware wil run out of room to put incoming packets. This | ||
1058 | * will cause the hardware to skip descrs that are full (instead | ||
1059 | * of halting/retrying). Thus, once the driver runs, it wil need | ||
1060 | * to "catch up" to where the hardware chain pointer is at. | ||
1061 | */ | ||
1062 | static void spider_net_resync_head_ptr(struct spider_net_card *card) | ||
1063 | { | ||
1064 | unsigned long flags; | ||
1065 | struct spider_net_descr_chain *chain = &card->rx_chain; | ||
1066 | struct spider_net_descr *descr; | ||
1067 | int i, status; | ||
1068 | |||
1069 | /* Advance head pointer past any empty descrs */ | ||
1070 | descr = chain->head; | ||
1071 | status = spider_net_get_descr_status(descr->hwdescr); | ||
1072 | |||
1073 | if (status == SPIDER_NET_DESCR_NOT_IN_USE) | ||
1074 | return; | ||
1075 | |||
1076 | spin_lock_irqsave(&chain->lock, flags); | ||
1077 | |||
1078 | descr = chain->head; | ||
1079 | status = spider_net_get_descr_status(descr->hwdescr); | ||
1080 | for (i=0; i<chain->num_desc; i++) { | ||
1081 | if (status != SPIDER_NET_DESCR_CARDOWNED) break; | ||
1082 | descr = descr->next; | ||
1083 | status = spider_net_get_descr_status(descr->hwdescr); | ||
1084 | } | ||
1085 | chain->head = descr; | ||
1086 | |||
1087 | spin_unlock_irqrestore(&chain->lock, flags); | ||
1088 | } | ||
1089 | |||
1090 | static int spider_net_resync_tail_ptr(struct spider_net_card *card) | ||
1091 | { | ||
1092 | struct spider_net_descr_chain *chain = &card->rx_chain; | ||
1093 | struct spider_net_descr *descr; | ||
1094 | int i, status; | ||
1095 | |||
1096 | /* Advance tail pointer past any empty and reaped descrs */ | ||
1097 | descr = chain->tail; | ||
1098 | status = spider_net_get_descr_status(descr->hwdescr); | ||
1099 | |||
1100 | for (i=0; i<chain->num_desc; i++) { | ||
1101 | if ((status != SPIDER_NET_DESCR_CARDOWNED) && | ||
1102 | (status != SPIDER_NET_DESCR_NOT_IN_USE)) break; | ||
1103 | descr = descr->next; | ||
1104 | status = spider_net_get_descr_status(descr->hwdescr); | ||
1105 | } | ||
1106 | chain->tail = descr; | ||
1107 | |||
1108 | if ((i == chain->num_desc) || (i == 0)) | ||
1109 | return 1; | ||
1110 | return 0; | ||
1111 | } | ||
1112 | |||
1113 | /** | ||
1054 | * spider_net_decode_one_descr - processes an RX descriptor | 1114 | * spider_net_decode_one_descr - processes an RX descriptor |
1055 | * @card: card structure | 1115 | * @card: card structure |
1056 | * | 1116 | * |
@@ -1175,6 +1235,12 @@ spider_net_poll(struct net_device *netdev, int *budget) | |||
1175 | } | 1235 | } |
1176 | } | 1236 | } |
1177 | 1237 | ||
1238 | if ((packets_done == 0) && (card->num_rx_ints != 0)) { | ||
1239 | no_more_packets = spider_net_resync_tail_ptr(card); | ||
1240 | spider_net_resync_head_ptr(card); | ||
1241 | } | ||
1242 | card->num_rx_ints = 0; | ||
1243 | |||
1178 | netdev->quota -= packets_done; | 1244 | netdev->quota -= packets_done; |
1179 | *budget -= packets_done; | 1245 | *budget -= packets_done; |
1180 | spider_net_refill_rx_chain(card); | 1246 | spider_net_refill_rx_chain(card); |
@@ -1421,7 +1487,11 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) | |||
1421 | if (netif_msg_intr(card) && net_ratelimit()) | 1487 | if (netif_msg_intr(card) && net_ratelimit()) |
1422 | pr_err("Spider RX RAM full, incoming packets " | 1488 | pr_err("Spider RX RAM full, incoming packets " |
1423 | "might be discarded!\n"); | 1489 | "might be discarded!\n"); |
1424 | spider_net_rx_irq_off(card); | 1490 | /* Could happen when rx chain is full */ |
1491 | spider_net_resync_head_ptr(card); | ||
1492 | spider_net_refill_rx_chain(card); | ||
1493 | spider_net_enable_rxdmac(card); | ||
1494 | card->num_rx_ints ++; | ||
1425 | netif_rx_schedule(card->netdev); | 1495 | netif_rx_schedule(card->netdev); |
1426 | show_error = 0; | 1496 | show_error = 0; |
1427 | break; | 1497 | break; |
@@ -1437,12 +1507,11 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) | |||
1437 | case SPIDER_NET_GDCDCEINT: /* fallthrough */ | 1507 | case SPIDER_NET_GDCDCEINT: /* fallthrough */ |
1438 | case SPIDER_NET_GDBDCEINT: /* fallthrough */ | 1508 | case SPIDER_NET_GDBDCEINT: /* fallthrough */ |
1439 | case SPIDER_NET_GDADCEINT: | 1509 | case SPIDER_NET_GDADCEINT: |
1440 | if (netif_msg_intr(card) && net_ratelimit()) | 1510 | spider_net_resync_head_ptr(card); |
1441 | pr_err("got descriptor chain end interrupt, " | ||
1442 | "restarting DMAC %c.\n", | ||
1443 | 'D'-(i-SPIDER_NET_GDDDCEINT)/3); | ||
1444 | spider_net_refill_rx_chain(card); | 1511 | spider_net_refill_rx_chain(card); |
1445 | spider_net_enable_rxdmac(card); | 1512 | spider_net_enable_rxdmac(card); |
1513 | card->num_rx_ints ++; | ||
1514 | netif_rx_schedule(card->netdev); | ||
1446 | show_error = 0; | 1515 | show_error = 0; |
1447 | break; | 1516 | break; |
1448 | 1517 | ||
@@ -1451,9 +1520,12 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg) | |||
1451 | case SPIDER_NET_GDCINVDINT: /* fallthrough */ | 1520 | case SPIDER_NET_GDCINVDINT: /* fallthrough */ |
1452 | case SPIDER_NET_GDBINVDINT: /* fallthrough */ | 1521 | case SPIDER_NET_GDBINVDINT: /* fallthrough */ |
1453 | case SPIDER_NET_GDAINVDINT: | 1522 | case SPIDER_NET_GDAINVDINT: |
1454 | /* could happen when rx chain is full */ | 1523 | /* Could happen when rx chain is full */ |
1524 | spider_net_resync_head_ptr(card); | ||
1455 | spider_net_refill_rx_chain(card); | 1525 | spider_net_refill_rx_chain(card); |
1456 | spider_net_enable_rxdmac(card); | 1526 | spider_net_enable_rxdmac(card); |
1527 | card->num_rx_ints ++; | ||
1528 | netif_rx_schedule(card->netdev); | ||
1457 | show_error = 0; | 1529 | show_error = 0; |
1458 | break; | 1530 | break; |
1459 | 1531 | ||
@@ -1546,6 +1618,7 @@ spider_net_interrupt(int irq, void *ptr) | |||
1546 | if (status_reg & SPIDER_NET_RXINT ) { | 1618 | if (status_reg & SPIDER_NET_RXINT ) { |
1547 | spider_net_rx_irq_off(card); | 1619 | spider_net_rx_irq_off(card); |
1548 | netif_rx_schedule(netdev); | 1620 | netif_rx_schedule(netdev); |
1621 | card->num_rx_ints ++; | ||
1549 | } | 1622 | } |
1550 | if (status_reg & SPIDER_NET_TXINT) | 1623 | if (status_reg & SPIDER_NET_TXINT) |
1551 | netif_rx_schedule(netdev); | 1624 | netif_rx_schedule(netdev); |
@@ -2191,6 +2264,7 @@ spider_net_setup_netdev(struct spider_net_card *card) | |||
2191 | * NETIF_F_HW_VLAN_FILTER */ | 2264 | * NETIF_F_HW_VLAN_FILTER */ |
2192 | 2265 | ||
2193 | netdev->irq = card->pdev->irq; | 2266 | netdev->irq = card->pdev->irq; |
2267 | card->num_rx_ints = 0; | ||
2194 | 2268 | ||
2195 | dn = pci_device_to_OF_node(card->pdev); | 2269 | dn = pci_device_to_OF_node(card->pdev); |
2196 | if (!dn) | 2270 | if (!dn) |
diff --git a/drivers/net/spider_net.h b/drivers/net/spider_net.h index 4a1e0d28a502..b620f181227c 100644 --- a/drivers/net/spider_net.h +++ b/drivers/net/spider_net.h | |||
@@ -25,7 +25,7 @@ | |||
25 | #ifndef _SPIDER_NET_H | 25 | #ifndef _SPIDER_NET_H |
26 | #define _SPIDER_NET_H | 26 | #define _SPIDER_NET_H |
27 | 27 | ||
28 | #define VERSION "2.0 A" | 28 | #define VERSION "2.0 B" |
29 | 29 | ||
30 | #include "sungem_phy.h" | 30 | #include "sungem_phy.h" |
31 | 31 | ||
@@ -461,6 +461,7 @@ struct spider_net_card { | |||
461 | struct work_struct tx_timeout_task; | 461 | struct work_struct tx_timeout_task; |
462 | atomic_t tx_timeout_task_counter; | 462 | atomic_t tx_timeout_task_counter; |
463 | wait_queue_head_t waitq; | 463 | wait_queue_head_t waitq; |
464 | int num_rx_ints; | ||
464 | 465 | ||
465 | /* for ethtool */ | 466 | /* for ethtool */ |
466 | int msg_enable; | 467 | int msg_enable; |