Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 805e969f authored by Toshiharu Okada's avatar Toshiharu Okada Committed by David S. Miller
Browse files

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: default avatarToshiharu Okada <toshiharu-linux@dsn.okisemi.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 5f3a1141
Loading
Loading
Loading
Loading
+27 −29
Original line number Original line Diff line number Diff line
@@ -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",