pch_gbe: Fixed the issue on which a network freezes
The pch_gbe driver has an issue which a network stops, when receiving traffic is high. In the case, The link down and up are necessary to return a network. This patch fixed this issue. Signed-off-by: Toshiharu Okada <toshiharu-linux@dsn.okisemi.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
5f3a114190
commit
805e969f61
|
@ -1199,6 +1199,8 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
|
|||
iowrite32((int_en & ~PCH_GBE_INT_RX_FIFO_ERR),
|
||||
&hw->reg->INT_EN);
|
||||
pch_gbe_stop_receive(adapter);
|
||||
int_st |= ioread32(&hw->reg->INT_ST);
|
||||
int_st = int_st & ioread32(&hw->reg->INT_EN);
|
||||
}
|
||||
if (int_st & PCH_GBE_INT_RX_DMA_ERR)
|
||||
adapter->stats.intr_rx_dma_err_count++;
|
||||
|
@ -1218,14 +1220,11 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
|
|||
/* Set Pause packet */
|
||||
pch_gbe_mac_set_pause_packet(hw);
|
||||
}
|
||||
if ((int_en & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT))
|
||||
== 0) {
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
|
||||
/* When request status is Receive interruption */
|
||||
if ((int_st & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT))) {
|
||||
if ((int_st & (PCH_GBE_INT_RX_DMA_CMPLT | PCH_GBE_INT_TX_CMPLT)) ||
|
||||
(adapter->rx_stop_flag == true)) {
|
||||
if (likely(napi_schedule_prep(&adapter->napi))) {
|
||||
/* Enable only Rx Descriptor empty */
|
||||
atomic_inc(&adapter->irq_sem);
|
||||
|
@ -1385,7 +1384,7 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
|
|||
struct sk_buff *skb;
|
||||
unsigned int i;
|
||||
unsigned int cleaned_count = 0;
|
||||
bool cleaned = false;
|
||||
bool cleaned = true;
|
||||
|
||||
pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean);
|
||||
|
||||
|
@ -1396,7 +1395,6 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
|
|||
|
||||
while ((tx_desc->gbec_status & DSC_INIT16) == 0x0000) {
|
||||
pr_debug("gbec_status:0x%04x\n", tx_desc->gbec_status);
|
||||
cleaned = true;
|
||||
buffer_info = &tx_ring->buffer_info[i];
|
||||
skb = buffer_info->skb;
|
||||
|
||||
|
@ -1439,8 +1437,10 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
|
|||
tx_desc = PCH_GBE_TX_DESC(*tx_ring, i);
|
||||
|
||||
/* weight of a sort for tx, to avoid endless transmit cleanup */
|
||||
if (cleaned_count++ == PCH_GBE_TX_WEIGHT)
|
||||
if (cleaned_count++ == PCH_GBE_TX_WEIGHT) {
|
||||
cleaned = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n",
|
||||
cleaned_count);
|
||||
|
@ -2168,7 +2168,6 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
|
|||
{
|
||||
struct pch_gbe_adapter *adapter =
|
||||
container_of(napi, struct pch_gbe_adapter, napi);
|
||||
struct net_device *netdev = adapter->netdev;
|
||||
int work_done = 0;
|
||||
bool poll_end_flag = false;
|
||||
bool cleaned = false;
|
||||
|
@ -2176,33 +2175,32 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
|
|||
|
||||
pr_debug("budget : %d\n", budget);
|
||||
|
||||
/* Keep link state information with original netdev */
|
||||
if (!netif_carrier_ok(netdev)) {
|
||||
pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
|
||||
cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
|
||||
|
||||
if (!cleaned)
|
||||
work_done = budget;
|
||||
/* If no Tx and not enough Rx work done,
|
||||
* exit the polling mode
|
||||
*/
|
||||
if (work_done < budget)
|
||||
poll_end_flag = true;
|
||||
} else {
|
||||
pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
|
||||
|
||||
if (poll_end_flag) {
|
||||
napi_complete(napi);
|
||||
if (adapter->rx_stop_flag) {
|
||||
adapter->rx_stop_flag = false;
|
||||
pch_gbe_start_receive(&adapter->hw);
|
||||
}
|
||||
pch_gbe_irq_enable(adapter);
|
||||
} else
|
||||
if (adapter->rx_stop_flag) {
|
||||
adapter->rx_stop_flag = false;
|
||||
pch_gbe_start_receive(&adapter->hw);
|
||||
int_en = ioread32(&adapter->hw.reg->INT_EN);
|
||||
iowrite32((int_en | PCH_GBE_INT_RX_FIFO_ERR),
|
||||
&adapter->hw.reg->INT_EN);
|
||||
&adapter->hw.reg->INT_EN);
|
||||
}
|
||||
cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
|
||||
|
||||
if (cleaned)
|
||||
work_done = budget;
|
||||
/* If no Tx and not enough Rx work done,
|
||||
* exit the polling mode
|
||||
*/
|
||||
if (work_done < budget)
|
||||
poll_end_flag = true;
|
||||
}
|
||||
|
||||
if (poll_end_flag) {
|
||||
napi_complete(napi);
|
||||
pch_gbe_irq_enable(adapter);
|
||||
}
|
||||
|
||||
pr_debug("poll_end_flag : %d work_done : %d budget : %d\n",
|
||||
poll_end_flag, work_done, budget);
|
||||
|
|
Loading…
Reference in a new issue