netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/7] Skge driver update
@ 2007-03-16 21:01 Stephen Hemminger
  2007-03-16 21:01 ` [PATCH 1/7] skge: deadlock on tx timeout Stephen Hemminger
                   ` (6 more replies)
  0 siblings, 7 replies; 11+ messages in thread
From: Stephen Hemminger @ 2007-03-16 21:01 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

Update to skge driver:
	1-3 bug fixes for upstream-fixes
	4-7 improvements for later releases
	
-- 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/7] skge: deadlock on tx timeout
  2007-03-16 21:01 [PATCH 0/7] Skge driver update Stephen Hemminger
@ 2007-03-16 21:01 ` Stephen Hemminger
  2007-03-23  5:48   ` Jeff Garzik
  2007-03-16 21:01 ` [PATCH 2/7] skge: mask irqs when device down Stephen Hemminger
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Stephen Hemminger @ 2007-03-16 21:01 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

[-- Attachment #1: skge-tx-timeout-deadlock.patch --]
[-- Type: text/plain, Size: 1112 bytes --]

The skge driver will deadlock if gets a transmit timeout
because the netif_tx_lock() is already held.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

---
 drivers/net/skge.c |    6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

--- skge-dev.orig/drivers/net/skge.c
+++ skge-dev/drivers/net/skge.c
@@ -2576,7 +2576,11 @@ static int skge_down(struct net_device *
 	skge_led(skge, LED_MODE_OFF);
 
 	netif_poll_disable(dev);
+
+	netif_tx_lock_bh(dev);
 	skge_tx_clean(dev);
+	netif_tx_unlock_bh(dev);
+
 	skge_rx_clean(skge);
 
 	kfree(skge->rx_ring.start);
@@ -2721,7 +2725,6 @@ static void skge_tx_clean(struct net_dev
 	struct skge_port *skge = netdev_priv(dev);
 	struct skge_element *e;
 
-	netif_tx_lock_bh(dev);
 	for (e = skge->tx_ring.to_clean; e != skge->tx_ring.to_use; e = e->next) {
 		struct skge_tx_desc *td = e->desc;
 		skge_tx_free(skge, e, td->control);
@@ -2730,7 +2733,6 @@ static void skge_tx_clean(struct net_dev
 
 	skge->tx_ring.to_clean = e;
 	netif_wake_queue(dev);
-	netif_tx_unlock_bh(dev);
 }
 
 static void skge_tx_timeout(struct net_device *dev)

-- 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 2/7] skge: mask irqs when device down
  2007-03-16 21:01 [PATCH 0/7] Skge driver update Stephen Hemminger
  2007-03-16 21:01 ` [PATCH 1/7] skge: deadlock on tx timeout Stephen Hemminger
@ 2007-03-16 21:01 ` Stephen Hemminger
  2007-03-16 21:01 ` [PATCH 3/7] skge: use per-port phy locking Stephen Hemminger
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Stephen Hemminger @ 2007-03-16 21:01 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

[-- Attachment #1: skge-noirq-down.patch --]
[-- Type: text/plain, Size: 2585 bytes --]

Wheen a port on the skge driver is not used, it should
mask off interrupts from theat port.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

---
 drivers/net/skge.c |   24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

--- skge-dev.orig/drivers/net/skge.c
+++ skge-dev/drivers/net/skge.c
@@ -105,7 +105,8 @@ static const int txqaddr[] = { Q_XA1, Q_
 static const int rxqaddr[] = { Q_R1, Q_R2 };
 static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F };
 static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F };
-static const u32 irqmask[] = { IS_R1_F|IS_XA1_F, IS_R2_F|IS_XA2_F };
+static const u32 napimask[] = { IS_R1_F|IS_XA1_F, IS_R2_F|IS_XA2_F };
+static const u32 portmask[] = { IS_PORT_1, IS_PORT_2 };
 
 static int skge_get_regs_len(struct net_device *dev)
 {
@@ -2504,6 +2505,11 @@ static int skge_up(struct net_device *de
 	skge_write8(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_START | CSR_IRQ_CL_F);
 	skge_led(skge, LED_MODE_ON);
 
+	spin_lock_irq(&hw->hw_lock);
+	hw->intr_mask |= portmask[port];
+	skge_write32(hw, B0_IMSK, hw->intr_mask);
+	spin_unlock_irq(&hw->hw_lock);
+
 	netif_poll_enable(dev);
 	return 0;
 
@@ -2533,6 +2539,13 @@ static int skge_down(struct net_device *
 	if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
 		cancel_delayed_work(&skge->link_thread);
 
+	netif_poll_disable(dev);
+
+	spin_lock_irq(&hw->hw_lock);
+	hw->intr_mask &= ~portmask[port];
+	skge_write32(hw, B0_IMSK, hw->intr_mask);
+	spin_unlock_irq(&hw->hw_lock);
+
 	skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
 	if (hw->chip_id == CHIP_ID_GENESIS)
 		genesis_stop(skge);
@@ -2575,8 +2588,6 @@ static int skge_down(struct net_device *
 
 	skge_led(skge, LED_MODE_OFF);
 
-	netif_poll_disable(dev);
-
 	netif_tx_lock_bh(dev);
 	skge_tx_clean(dev);
 	netif_tx_unlock_bh(dev);
@@ -3051,7 +3062,7 @@ static int skge_poll(struct net_device *
 
 	spin_lock_irqsave(&hw->hw_lock, flags);
 	__netif_rx_complete(dev);
-	hw->intr_mask |= irqmask[skge->port];
+	hw->intr_mask |= napimask[skge->port];
   	skge_write32(hw, B0_IMSK, hw->intr_mask);
 	skge_read32(hw, B0_IMSK);
 	spin_unlock_irqrestore(&hw->hw_lock, flags);
@@ -3415,10 +3426,9 @@ static int skge_reset(struct skge_hw *hw
 	else
 		hw->ram_size = t8 * 4096;
 
-	hw->intr_mask = IS_HW_ERR | IS_PORT_1;
-	if (hw->ports > 1)
-		hw->intr_mask |= IS_PORT_2;
+	hw->intr_mask = IS_HW_ERR;
 
+	/* Use PHY IRQ for all but fiber based Genesis board */
 	if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC))
 		hw->intr_mask |= IS_EXT_REG;
 

-- 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/7] skge: use per-port phy locking
  2007-03-16 21:01 [PATCH 0/7] Skge driver update Stephen Hemminger
  2007-03-16 21:01 ` [PATCH 1/7] skge: deadlock on tx timeout Stephen Hemminger
  2007-03-16 21:01 ` [PATCH 2/7] skge: mask irqs when device down Stephen Hemminger
@ 2007-03-16 21:01 ` Stephen Hemminger
  2007-03-23  5:49   ` Jeff Garzik
  2007-03-16 21:01 ` [PATCH 4/7] skge: ignore unused error interrupts Stephen Hemminger
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Stephen Hemminger @ 2007-03-16 21:01 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

[-- Attachment #1: skge-phy-port.patch --]
[-- Type: text/plain, Size: 9094 bytes --]

Rather than a workqueue and a per-board mutex to control PHY,
use a tasklet and spinlock. Tasklet is lower overhead and works
just as well for this.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

---
 drivers/net/skge.c |   82 ++++++++++++++++++++++++++++-------------------------
 drivers/net/skge.h |    6 +--
 2 files changed, 47 insertions(+), 41 deletions(-)

--- skge-dev.orig/drivers/net/skge.c
+++ skge-dev/drivers/net/skge.c
@@ -672,7 +672,7 @@ static void skge_led(struct skge_port *s
 	struct skge_hw *hw = skge->hw;
 	int port = skge->port;
 
-	mutex_lock(&hw->phy_mutex);
+	spin_lock_bh(&hw->phy_lock);
 	if (hw->chip_id == CHIP_ID_GENESIS) {
 		switch (mode) {
 		case LED_MODE_OFF:
@@ -743,7 +743,7 @@ static void skge_led(struct skge_port *s
 				     PHY_M_LED_MO_RX(MO_LED_ON));
 		}
 	}
-	mutex_unlock(&hw->phy_mutex);
+	spin_unlock_bh(&hw->phy_lock);
 }
 
 /* blink LED's for finding board */
@@ -1317,7 +1317,7 @@ static void xm_phy_init(struct skge_port
 	xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl);
 
 	/* Poll PHY for status changes */
-	schedule_delayed_work(&skge->link_thread, LINK_HZ);
+	mod_timer(&skge->link_timer, jiffies + LINK_HZ);
 }
 
 static void xm_check_link(struct net_device *dev)
@@ -1392,10 +1392,9 @@ static void xm_check_link(struct net_dev
  * Since internal PHY is wired to a level triggered pin, can't
  * get an interrupt when carrier is detected.
  */
-static void xm_link_timer(struct work_struct *work)
+static void xm_link_timer(unsigned long arg)
 {
-	struct skge_port *skge =
-		container_of(work, struct skge_port, link_thread.work);
+	struct skge_port *skge = (struct skge_port *) arg;
 	struct net_device *dev = skge->netdev;
  	struct skge_hw *hw = skge->hw;
 	int port = skge->port;
@@ -1415,13 +1414,13 @@ static void xm_link_timer(struct work_st
 			goto nochange;
 	}
 
-	mutex_lock(&hw->phy_mutex);
+	spin_lock(&hw->phy_lock);
 	xm_check_link(dev);
-	mutex_unlock(&hw->phy_mutex);
+	spin_unlock(&hw->phy_lock);
 
 nochange:
 	if (netif_running(dev))
-		schedule_delayed_work(&skge->link_thread, LINK_HZ);
+		mod_timer(&skge->link_timer, jiffies + LINK_HZ);
 }
 
 static void genesis_mac_init(struct skge_hw *hw, int port)
@@ -2324,7 +2323,7 @@ static void skge_phy_reset(struct skge_p
 	netif_stop_queue(skge->netdev);
 	netif_carrier_off(skge->netdev);
 
-	mutex_lock(&hw->phy_mutex);
+	spin_lock_bh(&hw->phy_lock);
 	if (hw->chip_id == CHIP_ID_GENESIS) {
 		genesis_reset(hw, port);
 		genesis_mac_init(hw, port);
@@ -2332,7 +2331,7 @@ static void skge_phy_reset(struct skge_p
 		yukon_reset(hw, port);
 		yukon_init(hw, port);
 	}
-	mutex_unlock(&hw->phy_mutex);
+	spin_unlock_bh(&hw->phy_lock);
 
 	dev->set_multicast_list(dev);
 }
@@ -2355,12 +2354,12 @@ static int skge_ioctl(struct net_device 
 		/* fallthru */
 	case SIOCGMIIREG: {
 		u16 val = 0;
-		mutex_lock(&hw->phy_mutex);
+		spin_lock_bh(&hw->phy_lock);
 		if (hw->chip_id == CHIP_ID_GENESIS)
 			err = __xm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val);
 		else
 			err = __gm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val);
-		mutex_unlock(&hw->phy_mutex);
+		spin_unlock_bh(&hw->phy_lock);
 		data->val_out = val;
 		break;
 	}
@@ -2369,14 +2368,14 @@ static int skge_ioctl(struct net_device 
 		if (!capable(CAP_NET_ADMIN))
 			return -EPERM;
 
-		mutex_lock(&hw->phy_mutex);
+		spin_lock_bh(&hw->phy_lock);
 		if (hw->chip_id == CHIP_ID_GENESIS)
 			err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f,
 				   data->val_in);
 		else
 			err = gm_phy_write(hw, skge->port, data->reg_num & 0x1f,
 				   data->val_in);
-		mutex_unlock(&hw->phy_mutex);
+		spin_unlock_bh(&hw->phy_lock);
 		break;
 	}
 	return err;
@@ -2482,12 +2481,12 @@ static int skge_up(struct net_device *de
 		goto free_rx_ring;
 
 	/* Initialize MAC */
-	mutex_lock(&hw->phy_mutex);
+	spin_lock_bh(&hw->phy_lock);
 	if (hw->chip_id == CHIP_ID_GENESIS)
 		genesis_mac_init(hw, port);
 	else
 		yukon_mac_init(hw, port);
-	mutex_unlock(&hw->phy_mutex);
+	spin_unlock_bh(&hw->phy_lock);
 
 	/* Configure RAMbuffers */
 	chunk = hw->ram_size / ((hw->ports + 1)*2);
@@ -2537,7 +2536,7 @@ static int skge_down(struct net_device *
 
 	netif_stop_queue(dev);
 	if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
-		cancel_delayed_work(&skge->link_thread);
+		del_timer_sync(&skge->link_timer);
 
 	netif_poll_disable(dev);
 
@@ -3173,28 +3172,29 @@ static void skge_error_irq(struct skge_h
 }
 
 /*
- * Interrupt from PHY are handled in work queue
+ * Interrupt from PHY are handled in tasklet (softirq)
  * because accessing phy registers requires spin wait which might
  * cause excess interrupt latency.
  */
-static void skge_extirq(struct work_struct *work)
+static void skge_extirq(unsigned long arg)
 {
-	struct skge_hw *hw = container_of(work, struct skge_hw, phy_work);
+	struct skge_hw *hw = (struct skge_hw *) arg;
 	int port;
 
-	mutex_lock(&hw->phy_mutex);
 	for (port = 0; port < hw->ports; port++) {
 		struct net_device *dev = hw->dev[port];
-		struct skge_port *skge = netdev_priv(dev);
 
 		if (netif_running(dev)) {
+			struct skge_port *skge = netdev_priv(dev);
+
+			spin_lock(&hw->phy_lock);
 			if (hw->chip_id != CHIP_ID_GENESIS)
 				yukon_phy_intr(skge);
 			else if (hw->phy_type == SK_PHY_BCOM)
 				bcom_phy_intr(skge);
+			spin_unlock(&hw->phy_lock);
 		}
 	}
-	mutex_unlock(&hw->phy_mutex);
 
 	spin_lock_irq(&hw->hw_lock);
 	hw->intr_mask |= IS_EXT_REG;
@@ -3219,7 +3219,7 @@ static irqreturn_t skge_intr(int irq, vo
 	status &= hw->intr_mask;
 	if (status & IS_EXT_REG) {
 		hw->intr_mask &= ~IS_EXT_REG;
-		schedule_work(&hw->phy_work);
+		tasklet_schedule(&hw->phy_task);
 	}
 
 	if (status & (IS_XA1_F|IS_R1_F)) {
@@ -3295,23 +3295,28 @@ static int skge_set_mac_address(struct n
 
 	memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
 
-	/* disable Rx */
-	ctrl = gma_read16(hw, port, GM_GP_CTRL);
-	gma_write16(hw, port, GM_GP_CTRL, ctrl & ~GM_GPCR_RX_ENA);
+	if (!netif_running(dev)) {
+		memcpy_toio(hw->regs + B2_MAC_1 + port*8, dev->dev_addr, ETH_ALEN);
+		memcpy_toio(hw->regs + B2_MAC_2 + port*8, dev->dev_addr, ETH_ALEN);
+	} else {
+		/* disable Rx */
+		spin_lock_bh(&hw->phy_lock);
+		ctrl = gma_read16(hw, port, GM_GP_CTRL);
+		gma_write16(hw, port, GM_GP_CTRL, ctrl & ~GM_GPCR_RX_ENA);
 
-	memcpy_toio(hw->regs + B2_MAC_1 + port*8, dev->dev_addr, ETH_ALEN);
-	memcpy_toio(hw->regs + B2_MAC_2 + port*8, dev->dev_addr, ETH_ALEN);
+		memcpy_toio(hw->regs + B2_MAC_1 + port*8, dev->dev_addr, ETH_ALEN);
+		memcpy_toio(hw->regs + B2_MAC_2 + port*8, dev->dev_addr, ETH_ALEN);
 
-	if (netif_running(dev)) {
 		if (hw->chip_id == CHIP_ID_GENESIS)
 			xm_outaddr(hw, port, XM_SA, dev->dev_addr);
 		else {
 			gma_set_addr(hw, port, GM_SRC_ADDR_1L, dev->dev_addr);
 			gma_set_addr(hw, port, GM_SRC_ADDR_2L, dev->dev_addr);
 		}
-	}
 
-	gma_write16(hw, port, GM_GP_CTRL, ctrl);
+		gma_write16(hw, port, GM_GP_CTRL, ctrl);
+		spin_unlock_bh(&hw->phy_lock);
+	}
 
 	return 0;
 }
@@ -3496,14 +3501,12 @@ static int skge_reset(struct skge_hw *hw
 
 	skge_write32(hw, B0_IMSK, hw->intr_mask);
 
-	mutex_lock(&hw->phy_mutex);
 	for (i = 0; i < hw->ports; i++) {
 		if (hw->chip_id == CHIP_ID_GENESIS)
 			genesis_reset(hw, i);
 		else
 			yukon_reset(hw, i);
 	}
-	mutex_unlock(&hw->phy_mutex);
 
 	return 0;
 }
@@ -3551,6 +3554,7 @@ static struct net_device *skge_devinit(s
 	skge->netdev = dev;
 	skge->hw = hw;
 	skge->msg_enable = netif_msg_init(debug, default_msg);
+
 	skge->tx_ring.count = DEFAULT_TX_RING_SIZE;
 	skge->rx_ring.count = DEFAULT_RX_RING_SIZE;
 
@@ -3567,7 +3571,7 @@ static struct net_device *skge_devinit(s
 	skge->port = port;
 
 	/* Only used for Genesis XMAC */
-	INIT_DELAYED_WORK(&skge->link_thread, xm_link_timer);
+	setup_timer(&skge->link_timer, xm_link_timer, (unsigned long) skge);
 
 	if (hw->chip_id != CHIP_ID_GENESIS) {
 		dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
@@ -3649,9 +3653,9 @@ static int __devinit skge_probe(struct p
 	}
 
 	hw->pdev = pdev;
-	mutex_init(&hw->phy_mutex);
-	INIT_WORK(&hw->phy_work, skge_extirq);
 	spin_lock_init(&hw->hw_lock);
+	spin_lock_init(&hw->phy_lock);
+	tasklet_init(&hw->phy_task, &skge_extirq, (unsigned long) hw);
 
 	hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
 	if (!hw->regs) {
@@ -3737,6 +3741,8 @@ static void __devexit skge_remove(struct
 	dev0 = hw->dev[0];
 	unregister_netdev(dev0);
 
+	tasklet_disable(&hw->phy_task);
+
 	spin_lock_irq(&hw->hw_lock);
 	hw->intr_mask = 0;
 	skge_write32(hw, B0_IMSK, 0);
--- skge-dev.orig/drivers/net/skge.h
+++ skge-dev/drivers/net/skge.h
@@ -2424,8 +2424,8 @@ struct skge_hw {
 	u32	     	     ram_size;
 	u32	     	     ram_offset;
 	u16		     phy_addr;
-	struct work_struct   phy_work;
-	struct mutex	     phy_mutex;
+	spinlock_t	     phy_lock;
+	struct tasklet_struct phy_task;
 };
 
 enum pause_control {
@@ -2457,7 +2457,7 @@ struct skge_port {
 
 	struct net_device_stats net_stats;
 
-	struct delayed_work  link_thread;
+	struct timer_list    link_timer;
 	enum pause_control   flow_control;
 	enum pause_status    flow_status;
 	u8		     rx_csum;

-- 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 4/7] skge: ignore unused error interrupts
  2007-03-16 21:01 [PATCH 0/7] Skge driver update Stephen Hemminger
                   ` (2 preceding siblings ...)
  2007-03-16 21:01 ` [PATCH 3/7] skge: use per-port phy locking Stephen Hemminger
@ 2007-03-16 21:01 ` Stephen Hemminger
  2007-03-23  5:58   ` Jeff Garzik
  2007-03-16 21:01 ` [PATCH 5/7] skge: transmit locking improvements Stephen Hemminger
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Stephen Hemminger @ 2007-03-16 21:01 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

[-- Attachment #1: skge-ignore-unused-errors.patch --]
[-- Type: text/plain, Size: 599 bytes --]

The following hardware error bits only show up on Genesis chipset
and are handled elsewhere, so they can be masked off.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

---
 drivers/net/skge.h |    1 -
 1 file changed, 1 deletion(-)

--- skge-dev.orig/drivers/net/skge.h
+++ skge-dev/drivers/net/skge.h
@@ -232,7 +232,6 @@ enum {
 	IS_R2_PAR_ERR	= 1<<0,	/* Queue R2 Parity Error */
 
 	IS_ERR_MSK	= IS_IRQ_MST_ERR | IS_IRQ_STAT
-			| IS_NO_STAT_M1 | IS_NO_STAT_M2
 			| IS_RAM_RD_PAR | IS_RAM_WR_PAR
 			| IS_M1_PAR_ERR | IS_M2_PAR_ERR
 			| IS_R1_PAR_ERR | IS_R2_PAR_ERR,

-- 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 5/7] skge: transmit locking improvements
  2007-03-16 21:01 [PATCH 0/7] Skge driver update Stephen Hemminger
                   ` (3 preceding siblings ...)
  2007-03-16 21:01 ` [PATCH 4/7] skge: ignore unused error interrupts Stephen Hemminger
@ 2007-03-16 21:01 ` Stephen Hemminger
  2007-03-16 21:01 ` [PATCH 6/7] skge: rearrange fields Stephen Hemminger
  2007-03-16 21:01 ` [PATCH 7/7] skge: version 1.11 Stephen Hemminger
  6 siblings, 0 replies; 11+ messages in thread
From: Stephen Hemminger @ 2007-03-16 21:01 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

[-- Attachment #1: skge-prefetch.patch --]
[-- Type: text/plain, Size: 2339 bytes --]

Don't need to lock when processing transmit complete unless queue fills.
Modeled after tg3.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

---
 drivers/net/skge.c |   28 ++++++++++++++++++----------
 1 file changed, 18 insertions(+), 10 deletions(-)

--- skge-dev.orig/drivers/net/skge.c
+++ skge-dev/drivers/net/skge.c
@@ -2602,6 +2602,7 @@ static int skge_down(struct net_device *
 
 static inline int skge_avail(const struct skge_ring *ring)
 {
+	smp_mb();
 	return ((ring->to_clean > ring->to_use) ? 0 : ring->count)
 		+ (ring->to_clean - ring->to_use) - 1;
 }
@@ -2690,6 +2691,8 @@ static int skge_xmit_frame(struct sk_buf
 		       dev->name, e - skge->tx_ring.start, skb->len);
 
 	skge->tx_ring.to_use = e->next;
+	smp_wmb();
+
 	if (skge_avail(&skge->tx_ring) <= TX_LOW_WATER) {
 		pr_debug("%s: transmit queue full\n", dev->name);
 		netif_stop_queue(dev);
@@ -2707,8 +2710,6 @@ static void skge_tx_free(struct skge_por
 {
 	struct pci_dev *pdev = skge->hw->pdev;
 
-	BUG_ON(!e->skb);
-
 	/* skb header vs. fragment */
 	if (control & BMU_STF)
 		pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr),
@@ -2726,7 +2727,6 @@ static void skge_tx_free(struct skge_por
 
 		dev_kfree_skb(e->skb);
 	}
-	e->skb = NULL;
 }
 
 /* Free all buffers in transmit ring */
@@ -2998,21 +2998,29 @@ static void skge_tx_done(struct net_devi
 
 	skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F);
 
-	netif_tx_lock(dev);
 	for (e = ring->to_clean; e != ring->to_use; e = e->next) {
-		struct skge_tx_desc *td = e->desc;
+		u32 control = ((const struct skge_tx_desc *) e->desc)->control;
 
-		if (td->control & BMU_OWN)
+		if (control & BMU_OWN)
 			break;
 
-		skge_tx_free(skge, e, td->control);
+		skge_tx_free(skge, e, control);
 	}
 	skge->tx_ring.to_clean = e;
 
-	if (skge_avail(&skge->tx_ring) > TX_LOW_WATER)
-		netif_wake_queue(dev);
+	/* Can run lockless until we need to synchronize to restart queue. */
+	smp_mb();
+
+	if (unlikely(netif_queue_stopped(dev) &&
+		     skge_avail(&skge->tx_ring) > TX_LOW_WATER)) {
+		netif_tx_lock(dev);
+		if (unlikely(netif_queue_stopped(dev) &&
+			     skge_avail(&skge->tx_ring) > TX_LOW_WATER)) {
+			netif_wake_queue(dev);
 
-	netif_tx_unlock(dev);
+		}
+		netif_tx_unlock(dev);
+	}
 }
 
 static int skge_poll(struct net_device *dev, int *budget)

-- 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 6/7] skge: rearrange fields
  2007-03-16 21:01 [PATCH 0/7] Skge driver update Stephen Hemminger
                   ` (4 preceding siblings ...)
  2007-03-16 21:01 ` [PATCH 5/7] skge: transmit locking improvements Stephen Hemminger
@ 2007-03-16 21:01 ` Stephen Hemminger
  2007-03-16 21:01 ` [PATCH 7/7] skge: version 1.11 Stephen Hemminger
  6 siblings, 0 replies; 11+ messages in thread
From: Stephen Hemminger @ 2007-03-16 21:01 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

[-- Attachment #1: skge-mem-opt.patch --]
[-- Type: text/plain, Size: 1002 bytes --]

Do some minor rearrangement of data structures to try and optimize
cache usage.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

---
 drivers/net/skge.h |    9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

--- skge-dev.orig/drivers/net/skge.h
+++ skge-dev/drivers/net/skge.h
@@ -2446,15 +2446,15 @@ enum pause_status {
 
 
 struct skge_port {
-	u32		     msg_enable;
 	struct skge_hw	     *hw;
 	struct net_device    *netdev;
 	int		     port;
+	u32		     msg_enable;
 
 	struct skge_ring     tx_ring;
-	struct skge_ring     rx_ring;
 
-	struct net_device_stats net_stats;
+	struct skge_ring     rx_ring ____cacheline_aligned_in_smp;
+	unsigned int	     rx_buf_size;
 
 	struct timer_list    link_timer;
 	enum pause_control   flow_control;
@@ -2470,7 +2470,8 @@ struct skge_port {
 	void		     *mem;	/* PCI memory for rings */
 	dma_addr_t	     dma;
 	unsigned long	     mem_size;
-	unsigned int	     rx_buf_size;
+
+	struct net_device_stats net_stats;
 };
 
 

-- 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 7/7] skge: version 1.11
  2007-03-16 21:01 [PATCH 0/7] Skge driver update Stephen Hemminger
                   ` (5 preceding siblings ...)
  2007-03-16 21:01 ` [PATCH 6/7] skge: rearrange fields Stephen Hemminger
@ 2007-03-16 21:01 ` Stephen Hemminger
  6 siblings, 0 replies; 11+ messages in thread
From: Stephen Hemminger @ 2007-03-16 21:01 UTC (permalink / raw)
  To: Jeff Garzik; +Cc: netdev

[-- Attachment #1: skge-1.11 --]
[-- Type: text/plain, Size: 443 bytes --]

New version to track changes.

Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

---
 drivers/net/skge.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- skge-dev.orig/drivers/net/skge.c
+++ skge-dev/drivers/net/skge.c
@@ -42,7 +42,7 @@
 #include "skge.h"
 
 #define DRV_NAME		"skge"
-#define DRV_VERSION		"1.10"
+#define DRV_VERSION		"1.11"
 #define PFX			DRV_NAME " "
 
 #define DEFAULT_TX_RING_SIZE	128

-- 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 1/7] skge: deadlock on tx timeout
  2007-03-16 21:01 ` [PATCH 1/7] skge: deadlock on tx timeout Stephen Hemminger
@ 2007-03-23  5:48   ` Jeff Garzik
  0 siblings, 0 replies; 11+ messages in thread
From: Jeff Garzik @ 2007-03-23  5:48 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev

Stephen Hemminger wrote:
> The skge driver will deadlock if gets a transmit timeout
> because the netif_tx_lock() is already held.
> 
> Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

applied 1-3 to #upstream-fixes



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/7] skge: use per-port phy locking
  2007-03-16 21:01 ` [PATCH 3/7] skge: use per-port phy locking Stephen Hemminger
@ 2007-03-23  5:49   ` Jeff Garzik
  0 siblings, 0 replies; 11+ messages in thread
From: Jeff Garzik @ 2007-03-23  5:49 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev

Stephen Hemminger wrote:
> Rather than a workqueue and a per-board mutex to control PHY,
> use a tasklet and spinlock. Tasklet is lower overhead and works
> just as well for this.
> 
> Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>

Like we give a crap about overhead of PHY code.

This seems like the wrong direction to me, but let's see where this leads.

	Jeff




^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/7] skge: ignore unused error interrupts
  2007-03-16 21:01 ` [PATCH 4/7] skge: ignore unused error interrupts Stephen Hemminger
@ 2007-03-23  5:58   ` Jeff Garzik
  0 siblings, 0 replies; 11+ messages in thread
From: Jeff Garzik @ 2007-03-23  5:58 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: netdev

Stephen Hemminger wrote:
> The following hardware error bits only show up on Genesis chipset
> and are handled elsewhere, so they can be masked off.
> 
> Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
> 
> ---
>  drivers/net/skge.h |    1 -
>  1 file changed, 1 deletion(-)

applied 4-7



^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2007-03-23  5:58 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-03-16 21:01 [PATCH 0/7] Skge driver update Stephen Hemminger
2007-03-16 21:01 ` [PATCH 1/7] skge: deadlock on tx timeout Stephen Hemminger
2007-03-23  5:48   ` Jeff Garzik
2007-03-16 21:01 ` [PATCH 2/7] skge: mask irqs when device down Stephen Hemminger
2007-03-16 21:01 ` [PATCH 3/7] skge: use per-port phy locking Stephen Hemminger
2007-03-23  5:49   ` Jeff Garzik
2007-03-16 21:01 ` [PATCH 4/7] skge: ignore unused error interrupts Stephen Hemminger
2007-03-23  5:58   ` Jeff Garzik
2007-03-16 21:01 ` [PATCH 5/7] skge: transmit locking improvements Stephen Hemminger
2007-03-16 21:01 ` [PATCH 6/7] skge: rearrange fields Stephen Hemminger
2007-03-16 21:01 ` [PATCH 7/7] skge: version 1.11 Stephen Hemminger

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).