All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.