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:
Родитель
5f3a114190
Коммит
805e969f61
|
@ -1199,6 +1199,8 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
|
||||||
iowrite32((int_en & ~PCH_GBE_INT_RX_FIFO_ERR),
|
iowrite32((int_en & ~PCH_GBE_INT_RX_FIFO_ERR),
|
||||||
&hw->reg->INT_EN);
|
&hw->reg->INT_EN);
|
||||||
pch_gbe_stop_receive(adapter);
|
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)
|
if (int_st & PCH_GBE_INT_RX_DMA_ERR)
|
||||||
adapter->stats.intr_rx_dma_err_count++;
|
adapter->stats.intr_rx_dma_err_count++;
|
||||||
|
@ -1218,14 +1220,11 @@ static irqreturn_t pch_gbe_intr(int irq, void *data)
|
||||||
/* Set Pause packet */
|
/* Set Pause packet */
|
||||||
pch_gbe_mac_set_pause_packet(hw);
|
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 */
|
/* 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))) {
|
if (likely(napi_schedule_prep(&adapter->napi))) {
|
||||||
/* Enable only Rx Descriptor empty */
|
/* Enable only Rx Descriptor empty */
|
||||||
atomic_inc(&adapter->irq_sem);
|
atomic_inc(&adapter->irq_sem);
|
||||||
|
@ -1385,7 +1384,7 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
unsigned int cleaned_count = 0;
|
unsigned int cleaned_count = 0;
|
||||||
bool cleaned = false;
|
bool cleaned = true;
|
||||||
|
|
||||||
pr_debug("next_to_clean : %d\n", tx_ring->next_to_clean);
|
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) {
|
while ((tx_desc->gbec_status & DSC_INIT16) == 0x0000) {
|
||||||
pr_debug("gbec_status:0x%04x\n", tx_desc->gbec_status);
|
pr_debug("gbec_status:0x%04x\n", tx_desc->gbec_status);
|
||||||
cleaned = true;
|
|
||||||
buffer_info = &tx_ring->buffer_info[i];
|
buffer_info = &tx_ring->buffer_info[i];
|
||||||
skb = buffer_info->skb;
|
skb = buffer_info->skb;
|
||||||
|
|
||||||
|
@ -1439,9 +1437,11 @@ pch_gbe_clean_tx(struct pch_gbe_adapter *adapter,
|
||||||
tx_desc = PCH_GBE_TX_DESC(*tx_ring, i);
|
tx_desc = PCH_GBE_TX_DESC(*tx_ring, i);
|
||||||
|
|
||||||
/* weight of a sort for tx, to avoid endless transmit cleanup */
|
/* 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;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n",
|
pr_debug("called pch_gbe_unmap_and_free_tx_resource() %d count\n",
|
||||||
cleaned_count);
|
cleaned_count);
|
||||||
/* Recover from running out of Tx resources in xmit_frame */
|
/* Recover from running out of Tx resources in xmit_frame */
|
||||||
|
@ -2168,7 +2168,6 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
|
||||||
{
|
{
|
||||||
struct pch_gbe_adapter *adapter =
|
struct pch_gbe_adapter *adapter =
|
||||||
container_of(napi, struct pch_gbe_adapter, napi);
|
container_of(napi, struct pch_gbe_adapter, napi);
|
||||||
struct net_device *netdev = adapter->netdev;
|
|
||||||
int work_done = 0;
|
int work_done = 0;
|
||||||
bool poll_end_flag = false;
|
bool poll_end_flag = false;
|
||||||
bool cleaned = false;
|
bool cleaned = false;
|
||||||
|
@ -2176,32 +2175,31 @@ static int pch_gbe_napi_poll(struct napi_struct *napi, int budget)
|
||||||
|
|
||||||
pr_debug("budget : %d\n", budget);
|
pr_debug("budget : %d\n", budget);
|
||||||
|
|
||||||
/* Keep link state information with original netdev */
|
|
||||||
if (!netif_carrier_ok(netdev)) {
|
|
||||||
poll_end_flag = true;
|
|
||||||
} else {
|
|
||||||
pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
|
pch_gbe_clean_rx(adapter, adapter->rx_ring, &work_done, budget);
|
||||||
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);
|
|
||||||
}
|
|
||||||
cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
|
cleaned = pch_gbe_clean_tx(adapter, adapter->tx_ring);
|
||||||
|
|
||||||
if (cleaned)
|
if (!cleaned)
|
||||||
work_done = budget;
|
work_done = budget;
|
||||||
/* If no Tx and not enough Rx work done,
|
/* If no Tx and not enough Rx work done,
|
||||||
* exit the polling mode
|
* exit the polling mode
|
||||||
*/
|
*/
|
||||||
if (work_done < budget)
|
if (work_done < budget)
|
||||||
poll_end_flag = true;
|
poll_end_flag = true;
|
||||||
}
|
|
||||||
|
|
||||||
if (poll_end_flag) {
|
if (poll_end_flag) {
|
||||||
napi_complete(napi);
|
napi_complete(napi);
|
||||||
|
if (adapter->rx_stop_flag) {
|
||||||
|
adapter->rx_stop_flag = false;
|
||||||
|
pch_gbe_start_receive(&adapter->hw);
|
||||||
|
}
|
||||||
pch_gbe_irq_enable(adapter);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
pr_debug("poll_end_flag : %d work_done : %d budget : %d\n",
|
pr_debug("poll_end_flag : %d work_done : %d budget : %d\n",
|
||||||
|
|
Загрузка…
Ссылка в новой задаче