[PATCH 13/26] atl1: refactor interrupt handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Jay Cliburn <[email protected]>

Refactor interrupt handling to conform with the current vendor driver
version 1.2.40.2.

Signed-off-by: Jay Cliburn <[email protected]>
---
 drivers/net/atlx/atl1.c |  196 ++++++++++++++++++++++-------------------------
 drivers/net/atlx/atl1.h |   25 +++++-
 drivers/net/atlx/atlx.c |    2 +-
 3 files changed, 114 insertions(+), 109 deletions(-)

diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c
index d38f26f..9c86ef4 100644
--- a/drivers/net/atlx/atl1.c
+++ b/drivers/net/atlx/atl1.c
@@ -1740,12 +1740,11 @@ next:
 	return num_alloc;
 }
 
-static void atl1_intr_rx(struct atl1_adapter *adapter)
+static void atl1_clean_rx_irq(struct atl1_adapter *adapter)
 {
+	struct net_device *netdev = adapter->netdev;
 	int i, count;
-	u16 length;
-	u16 rrd_next_to_clean;
-	u32 value;
+	u16 length, rrd_next_to_clean;
 	struct atl1_rfd_ring *rfd_ring = &adapter->rfd_ring;
 	struct atl1_rrd_ring *rrd_ring = &adapter->rrd_ring;
 	struct atl1_buffer *buffer_info;
@@ -1754,7 +1753,7 @@ static void atl1_intr_rx(struct atl1_adapter *adapter)
 
 	count = 0;
 
-	rrd_next_to_clean = atomic_read(&rrd_ring->next_to_clean);
+	rrd_next_to_clean = (u16) atomic_read(&rrd_ring->next_to_clean);
 
 	while (1) {
 		rrd = ATL1_RRD_DESC(rrd_ring, rrd_next_to_clean);
@@ -1795,6 +1794,7 @@ chk_rrd:
 			/* bad rrd */
 			dev_printk(KERN_DEBUG, &adapter->pdev->dev,
 				"bad RRD\n");
+
 			/* see if update RFD index */
 			if (rrd->num_buf > 1)
 				atl1_update_rfd_index(adapter, rrd);
@@ -1823,13 +1823,18 @@ rrd_ok:
 		count++;
 
 		if (unlikely(rrd->pkt_flg & PACKET_FLAG_ERR)) {
-			if (!(rrd->err_flg &
-				(ERR_FLAG_IP_CHKSUM | ERR_FLAG_L4_CHKSUM
-				| ERR_FLAG_LEN))) {
-				/* packet error, don't need upstream */
-				buffer_info->alloced = 0;
-				rrd->xsz.valid = 0;
-				continue;
+			if (rrd->err_flg & (ERR_FLAG_CRC | ERR_FLAG_TRUNC |
+				ERR_FLAG_CODE | ERR_FLAG_OV)) {
+				if (!(netdev->flags & IFF_PROMISC)) {
+					/* packet error, don't need upstream */
+					buffer_info->alloced = 0;
+					rrd->xsz.valid = 0;
+					dev_printk(KERN_DEBUG,
+						&adapter->pdev->dev,
+						"rrd error flag 0x%08X\n",
+						rrd->err_flg);
+					continue;
+				}
 			}
 		}
 
@@ -1862,33 +1867,13 @@ rrd_ok:
 	}
 
 	atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean);
-
 	atl1_alloc_rx_buffers(adapter);
 
-	/* update mailbox ? */
-	if (count) {
-		u32 tpd_next_to_use;
-		u32 rfd_next_to_use;
-
-		spin_lock(&adapter->mb_lock);
-
-		tpd_next_to_use = atomic_read(&adapter->tpd_ring.next_to_use);
-		rfd_next_to_use =
-		    atomic_read(&adapter->rfd_ring.next_to_use);
-		rrd_next_to_clean =
-		    atomic_read(&adapter->rrd_ring.next_to_clean);
-		value = ((rfd_next_to_use & MB_RFD_PROD_INDX_MASK) <<
-			MB_RFD_PROD_INDX_SHIFT) |
-                        ((rrd_next_to_clean & MB_RRD_CONS_INDX_MASK) <<
-			MB_RRD_CONS_INDX_SHIFT) |
-                        ((tpd_next_to_use & MB_TPD_PROD_INDX_MASK) <<
-			MB_TPD_PROD_INDX_SHIFT);
-		iowrite32(value, adapter->hw.hw_addr + REG_MAILBOX);
-		spin_unlock(&adapter->mb_lock);
-	}
+	if (count)
+		atl1_update_mailbox(adapter);
 }
 
-static void atl1_intr_tx(struct atl1_adapter *adapter)
+static bool atl1_clean_tx_irq(struct atl1_adapter *adapter)
 {
 	struct atl1_tpd_ring *tpd_ring = &adapter->tpd_ring;
 	struct atl1_buffer *buffer_info;
@@ -1905,7 +1890,7 @@ static void atl1_intr_tx(struct atl1_adapter *adapter)
 		buffer_info = &tpd_ring->buffer_info[sw_tpd_next_to_clean];
 		if (buffer_info->dma) {
 			pci_unmap_page(adapter->pdev, buffer_info->dma,
-				       buffer_info->length, PCI_DMA_TODEVICE);
+				buffer_info->length, PCI_DMA_TODEVICE);
 			buffer_info->dma = 0;
 		}
 
@@ -1922,6 +1907,11 @@ static void atl1_intr_tx(struct atl1_adapter *adapter)
 	if (netif_queue_stopped(adapter->netdev)
 	    && netif_carrier_ok(adapter->netdev))
 		netif_wake_queue(adapter->netdev);
+
+	if (sw_tpd_next_to_clean == (u16) atomic_read(&tpd_ring->next_to_use))
+		return true;
+	else
+		return false;
 }
 
 static u16 atl1_tpd_avail(struct atl1_tpd_ring *tpd_ring)
@@ -2285,80 +2275,75 @@ static int atl1_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 static irqreturn_t atl1_intr(int irq, void *data)
 {
 	struct atl1_adapter *adapter = netdev_priv(data);
+	struct atl1_hw *hw = &adapter->hw;
 	u32 status;
-	u8 update_rx;
 	int max_ints = 10;
 
 	status = adapter->cmb.cmb->int_stats;
 	if (!status)
 		return IRQ_NONE;
 
-	update_rx = 0;
-
-	do {
-		/* clear CMB interrupt status at once */
-		adapter->cmb.cmb->int_stats = 0;
-
-		if (status & ISR_GPHY)	/* clear phy status */
-			atlx_clear_phy_int(adapter);
+loopint:
+	/* clear CMB interrupt status at once */
+	adapter->cmb.cmb->int_stats = 0;
 
-		/* clear ISR status, and Enable CMB DMA/Disable Interrupt */
-		iowrite32(status | ISR_DIS_INT, adapter->hw.hw_addr + REG_ISR);
+	if (status & ISR_GPHY)	/* clear phy status */
+		atlx_clear_phy_int(adapter);
 
-		/* check if SMB intr */
-		if (status & ISR_SMB)
-			atl1_inc_smb(adapter);
+	/* clear ISR status, and Enable CMB DMA/Disable Interrupt */
+	status |= (ISR_DIS_INT | ISR_DIS_DMA);
+	iowrite32(status, adapter->hw.hw_addr + REG_ISR);
 
-		/* check if PCIE PHY Link down */
-		if (status & ISR_PHY_LINKDOWN) {
-			dev_printk(KERN_DEBUG, &adapter->pdev->dev,
-				"pcie phy link down %x\n", status);
-			if (netif_running(adapter->netdev)) {	/* reset MAC */
-				iowrite32(0, adapter->hw.hw_addr + REG_IMR);
-				schedule_work(&adapter->pcie_dma_to_rst_task);
-				return IRQ_HANDLED;
-			}
-		}
-
-		/* check if DMA read/write error ? */
-		if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
-			dev_printk(KERN_DEBUG, &adapter->pdev->dev,
-				"pcie DMA r/w error (status = 0x%x)\n",
-				status);
-			iowrite32(0, adapter->hw.hw_addr + REG_IMR);
-			schedule_work(&adapter->pcie_dma_to_rst_task);
+	/* check if PCIE PHY Link down */
+	if (status & ISR_PHY_LINKDOWN) {
+		dev_printk(KERN_DEBUG, &adapter->pdev->dev,
+			"pcie phy link down %x\n", status);
+		if (netif_running(adapter->netdev)) {
+			/* reset MAC */
+			iowrite32(0, hw->hw_addr + REG_ISR);
+			iowrite32(0, hw->hw_addr + REG_IMR);
+			ioread32(hw->hw_addr + REG_IMR);
+			schedule_work(&adapter->reset_task);
 			return IRQ_HANDLED;
 		}
+	}
 
-		/* link event */
-		if (status & ISR_GPHY) {
-			adapter->soft_stats.tx_carrier_errors++;
-			atl1_check_for_link(adapter);
-		}
+	/* check if DMA read/write error ? */
+	if (status & (ISR_DMAR_TO_RST | ISR_DMAW_TO_RST)) {
+		dev_printk(KERN_DEBUG, &adapter->pdev->dev,
+			"pcie DMA r/w error (status = 0x%x)\n",
+			status);
+		iowrite32(0, hw->hw_addr + REG_ISR);
+		iowrite32(0, hw->hw_addr + REG_IMR);
+		ioread32(hw->hw_addr + REG_IMR);
+		schedule_work(&adapter->reset_task);
+		return IRQ_HANDLED;
+	}
 
-		/* transmit event */
-		if (status & ISR_CMB_TX)
-			atl1_intr_tx(adapter);
-
-		/* rx exception */
-		if (unlikely(status & (ISR_RXF_OV | ISR_RFD_UNRUN |
-			ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
-			ISR_HOST_RRD_OV | ISR_CMB_RX))) {
-			if (status & (ISR_RXF_OV | ISR_RFD_UNRUN |
-				ISR_RRD_OV | ISR_HOST_RFD_UNRUN |
-				ISR_HOST_RRD_OV))
-				dev_printk(KERN_DEBUG, &adapter->pdev->dev,
-					"rx exception, ISR = 0x%x\n", status);
-			atl1_intr_rx(adapter);
-		}
+	/* check if SMB intr */
+	if (status & ISR_SMB)
+		atl1_inc_smb(adapter);
 
-		if (--max_ints < 0)
-			break;
+	/* link event */
+	if (status & (ISR_GPHY | ISR_MANUAL)) {
+		adapter->soft_stats.tx_carrier_errors++;
+		atl1_check_for_link(adapter);
+	}
+
+	/* transmit event */
+	if (status & ISR_TX_EVENT)
+		atl1_clean_tx_irq(adapter);
 
-	} while ((status = adapter->cmb.cmb->int_stats));
+	/* rx event */
+	if (status & ISR_RX_EVENT)
+		atl1_clean_rx_irq(adapter);
 
-	/* re-enable Interrupt */
-	iowrite32(ISR_DIS_SMB | ISR_DIS_DMA, adapter->hw.hw_addr + REG_ISR);
+	status = adapter->cmb.cmb->int_stats;
+	if ((--max_ints > 0) && status)
+		goto loopint;
+
+	/* re-enable interrupts */
+	iowrite32((ISR_DIS_SMB | ISR_DIS_DMA), adapter->hw.hw_addr + REG_ISR);
 	return IRQ_HANDLED;
 }
 
@@ -2460,16 +2445,22 @@ void atl1_down(struct atl1_adapter *adapter)
 	atl1_clean_rx_ring(adapter);
 }
 
-static void atl1_tx_timeout_task(struct work_struct *work)
+static void atl1_reinit_locked(struct atl1_adapter *adapter)
 {
-	struct atl1_adapter *adapter =
-		container_of(work, struct atl1_adapter, tx_timeout_task);
-	struct net_device *netdev = adapter->netdev;
-
-	netif_device_detach(netdev);
+	WARN_ON(in_interrupt());
+	while (test_and_set_bit(__ATL1_RESETTING, &adapter->flags))
+		msleep(1);
 	atl1_down(adapter);
 	atl1_up(adapter);
-	netif_device_attach(netdev);
+	clear_bit(__ATL1_RESETTING, &adapter->flags);
+}
+
+static void atl1_reset_task(struct work_struct *work)
+{
+	struct atl1_adapter *adapter;
+
+	adapter = container_of(work, struct atl1_adapter, reset_task);
+	atl1_reinit_locked(adapter);
 }
 
 /*
@@ -2857,12 +2848,9 @@ static int __devinit atl1_probe(struct pci_dev *pdev,
 	adapter->phy_config_timer.data = (unsigned long)adapter;
 	adapter->phy_timer_pending = false;
 
-	INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task);
-
+	INIT_WORK(&adapter->reset_task, atl1_reset_task);
 	INIT_WORK(&adapter->link_chg_task, atlx_link_chg_task);
 
-	INIT_WORK(&adapter->pcie_dma_to_rst_task, atl1_tx_timeout_task);
-
 	err = register_netdev(netdev);
 	if (err)
 		goto err_common;
diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h
index 2c2570e..8198f82 100644
--- a/drivers/net/atlx/atl1.h
+++ b/drivers/net/atlx/atl1.h
@@ -262,7 +262,7 @@ extern const struct ethtool_ops atl1_ethtool_ops;
 #define ISR_RRD_OV				0x20
 #define ISR_TXF_UNRUN				0x40
 #define ISR_LINK				0x80
-#define ISR_HOST_RFD_UNRUN			0x100
+#define ISR_HOST_RFD_UR				0x100
 #define ISR_HOST_RRD_OV				0x200
 #define ISR_DMAR_TO_RST				0x400
 #define ISR_DMAW_TO_RST				0x800
@@ -288,6 +288,24 @@ extern const struct ethtool_ops atl1_ethtool_ops;
 	ISR_CMB_TX	|\
 	ISR_CMB_RX)
 
+#define ISR_TX_EVENT	(\
+	ISR_TXF_UNRUN	|\
+	ISR_TX_PKT	|\
+	ISR_TX_DMA	|\
+	ISR_CMB_TX	|\
+	ISR_MAC_TX)
+
+#define ISR_RX_EVENT	(\
+	ISR_RXF_OV	|\
+	ISR_RFD_UNRUN	|\
+	ISR_RRD_OV	|\
+	ISR_HOST_RFD_UR	|\
+	ISR_HOST_RRD_OV	|\
+	ISR_RX_PKT	|\
+	ISR_RX_DMA	|\
+	ISR_CMB_RX	|\
+	ISR_MAC_RX)
+
 /* Debug Interrupt Mask  (enable all interrupt) */
 #define IMR_DEBUG_MASK	(\
 	ISR_SMB		|\
@@ -762,10 +780,8 @@ struct atl1_adapter {
 	u32 wol;
 	u16 link_speed;
 	u16 link_duplex;
-	spinlock_t lock;
-	struct work_struct tx_timeout_task;
+	struct work_struct reset_task;
 	struct work_struct link_chg_task;
-	struct work_struct pcie_dma_to_rst_task;
 	struct timer_list watchdog_timer;
 	struct timer_list phy_config_timer;
 	bool phy_timer_pending;
@@ -776,6 +792,7 @@ struct atl1_adapter {
 	/* TX */
 	struct atl1_tpd_ring tpd_ring;
 	spinlock_t mb_lock;
+	spinlock_t lock;
 
 	/* RX */
 	struct atl1_rfd_ring rfd_ring;
diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c
index 354050f..18c2d7e 100644
--- a/drivers/net/atlx/atlx.c
+++ b/drivers/net/atlx/atlx.c
@@ -204,7 +204,7 @@ static void atlx_tx_timeout(struct net_device *netdev)
 {
 	struct atlx_adapter *adapter = netdev_priv(netdev);
 	/* Do the reset outside of interrupt context */
-	schedule_work(&adapter->tx_timeout_task);
+	schedule_work(&adapter->reset_task);
 }
 
 /*
-- 
1.5.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux