From: linas@austin.ibm.com (Linas Vepstas)
To: akpm@osdl.org
Cc: jeff@garzik.org, Arnd Bergmann <arnd@arndb.de>,
netdev@vger.kernel.org, James K Lewis <jklewis@us.ibm.com>,
linux-kernel@vger.kernel.org, linuxppc-dev@ozlabs.org
Subject: [PATCH 15/21]: powerpc/cell spidernet refine locking
Date: Tue, 10 Oct 2006 16:14:29 -0500 [thread overview]
Message-ID: <20061010211429.GL4381@austin.ibm.com> (raw)
In-Reply-To: <20061010204946.GW4381@austin.ibm.com>
The transmit side of the spider ethernet driver currently
places locks around some very large chunks of code. This
results in a fair amount of lock contention is some cases.
This patch makes the locks much more fine-grained, protecting
only the cirtical sections. One lock is used to protect
three locations: the queue head and tail pointers, and the
queue low-watermark location.
Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: James K Lewis <jklewis@us.ibm.com>
----
drivers/net/spider_net.c | 95 +++++++++++++++++++++--------------------------
1 file changed, 43 insertions(+), 52 deletions(-)
Index: linux-2.6.18-mm2/drivers/net/spider_net.c
===================================================================
--- linux-2.6.18-mm2.orig/drivers/net/spider_net.c 2006-10-10 13:10:37.000000000 -0500
+++ linux-2.6.18-mm2/drivers/net/spider_net.c 2006-10-10 13:20:08.000000000 -0500
@@ -646,8 +646,9 @@ static int
spider_net_prepare_tx_descr(struct spider_net_card *card,
struct sk_buff *skb)
{
- struct spider_net_descr *descr = card->tx_chain.head;
+ struct spider_net_descr *descr;
dma_addr_t buf;
+ unsigned long flags;
int length;
length = skb->len;
@@ -666,6 +667,10 @@ spider_net_prepare_tx_descr(struct spide
return -ENOMEM;
}
+ spin_lock_irqsave(&card->tx_chain.lock, flags);
+ descr = card->tx_chain.head;
+ card->tx_chain.head = descr->next;
+
descr->buf_addr = buf;
descr->buf_size = length;
descr->next_descr_addr = 0;
@@ -674,6 +679,8 @@ spider_net_prepare_tx_descr(struct spide
descr->dmac_cmd_status =
SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS;
+ spin_unlock_irqrestore(&card->tx_chain.lock, flags);
+
if (skb->protocol == htons(ETH_P_IP))
switch (skb->nh.iph->protocol) {
case IPPROTO_TCP:
@@ -691,42 +698,17 @@ spider_net_prepare_tx_descr(struct spide
return 0;
}
-/**
- * spider_net_release_tx_descr - processes a used tx descriptor
- * @card: card structure
- * @descr: descriptor to release
- *
- * releases a used tx descriptor (unmapping, freeing of skb)
- */
-static inline void
-spider_net_release_tx_descr(struct spider_net_card *card)
-{
- struct spider_net_descr *descr = card->tx_chain.tail;
- struct sk_buff *skb;
- unsigned int len;
-
- card->tx_chain.tail = card->tx_chain.tail->next;
- descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
-
- /* unmap the skb */
- skb = descr->skb;
- if (!skb)
- return;
- len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
- pci_unmap_single(card->pdev, descr->buf_addr, len,
- PCI_DMA_TODEVICE);
- dev_kfree_skb(skb);
-}
-
static void
spider_net_set_low_watermark(struct spider_net_card *card)
{
+ unsigned long flags;
int status;
int cnt=0;
int i;
struct spider_net_descr *descr = card->tx_chain.tail;
- /* Measure the length of the queue. */
+ /* Measure the length of the queue. Measurement does not
+ * need to be precise -- does not need a lock. */
while (descr != card->tx_chain.head) {
status = descr->dmac_cmd_status & SPIDER_NET_DESCR_NOT_IN_USE;
if (status == SPIDER_NET_DESCR_NOT_IN_USE)
@@ -746,11 +728,13 @@ spider_net_set_low_watermark(struct spid
descr = descr->next;
/* Set the new watermark, clear the old watermark */
+ spin_lock_irqsave(&card->tx_chain.lock, flags);
descr->dmac_cmd_status |= SPIDER_NET_DESCR_TXDESFLG;
if (card->low_watermark && card->low_watermark != descr)
card->low_watermark->dmac_cmd_status =
card->low_watermark->dmac_cmd_status & ~SPIDER_NET_DESCR_TXDESFLG;
card->low_watermark = descr;
+ spin_unlock_irqrestore(&card->tx_chain.lock, flags);
}
/**
@@ -769,21 +753,31 @@ static int
spider_net_release_tx_chain(struct spider_net_card *card, int brutal)
{
struct spider_net_descr_chain *chain = &card->tx_chain;
+ struct spider_net_descr *descr;
+ struct sk_buff *skb;
+ u32 buf_addr;
+ unsigned long flags;
int status;
spider_net_read_reg(card, SPIDER_NET_GDTDMACCNTR);
while (chain->tail != chain->head) {
- status = spider_net_get_descr_status(chain->tail);
+ spin_lock_irqsave(&chain->lock, flags);
+ descr = chain->tail;
+
+ status = spider_net_get_descr_status(descr);
switch (status) {
case SPIDER_NET_DESCR_COMPLETE:
card->netdev_stats.tx_packets++;
- card->netdev_stats.tx_bytes += chain->tail->skb->len;
+ card->netdev_stats.tx_bytes += descr->skb->len;
break;
case SPIDER_NET_DESCR_CARDOWNED:
- if (!brutal)
+ if (!brutal) {
+ spin_unlock_irqrestore(&chain->lock, flags);
return 1;
+ }
+
/* fallthrough, if we release the descriptors
* brutally (then we don't care about
* SPIDER_NET_DESCR_CARDOWNED) */
@@ -800,12 +794,25 @@ spider_net_release_tx_chain(struct spide
default:
card->netdev_stats.tx_dropped++;
- if (!brutal)
+ if (!brutal) {
+ spin_unlock_irqrestore(&chain->lock, flags);
return 1;
+ }
}
- spider_net_release_tx_descr(card);
- }
+ chain->tail = descr->next;
+ descr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE;
+ skb = descr->skb;
+ buf_addr = descr->buf_addr;
+ spin_unlock_irqrestore(&chain->lock, flags);
+
+ /* unmap the skb */
+ if (skb) {
+ int len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
+ pci_unmap_single(card->pdev, buf_addr, len, PCI_DMA_TODEVICE);
+ dev_kfree_skb(skb);
+ }
+ }
return 0;
}
@@ -857,27 +864,19 @@ spider_net_xmit(struct sk_buff *skb, str
{
struct spider_net_card *card = netdev_priv(netdev);
struct spider_net_descr_chain *chain = &card->tx_chain;
- struct spider_net_descr *descr = chain->head;
- unsigned long flags;
-
- spin_lock_irqsave(&chain->lock, flags);
spider_net_release_tx_chain(card, 0);
if ((chain->head->next == chain->tail->prev) ||
- (spider_net_get_descr_status(descr) != SPIDER_NET_DESCR_NOT_IN_USE) ||
(spider_net_prepare_tx_descr(card, skb) != 0)) {
card->netdev_stats.tx_dropped++;
- spin_unlock_irqrestore(&chain->lock, flags);
netif_stop_queue(netdev);
return NETDEV_TX_BUSY;
}
spider_net_set_low_watermark(card);
spider_net_kick_tx_dma(card);
- card->tx_chain.head = card->tx_chain.head->next;
- spin_unlock_irqrestore(&chain->lock, flags);
return NETDEV_TX_OK;
}
@@ -893,16 +892,11 @@ spider_net_xmit(struct sk_buff *skb, str
static void
spider_net_cleanup_tx_ring(struct spider_net_card *card)
{
- unsigned long flags;
-
- spin_lock_irqsave(&card->tx_chain.lock, flags);
-
if ((spider_net_release_tx_chain(card, 0) != 0) &&
(card->netdev->flags & IFF_UP)) {
spider_net_kick_tx_dma(card);
netif_wake_queue(card->netdev);
}
- spin_unlock_irqrestore(&card->tx_chain.lock, flags);
}
/**
@@ -1930,10 +1924,7 @@ spider_net_stop(struct net_device *netde
spider_net_disable_rxdmac(card);
/* release chains */
- if (spin_trylock(&card->tx_chain.lock)) {
- spider_net_release_tx_chain(card, 1);
- spin_unlock(&card->tx_chain.lock);
- }
+ spider_net_release_tx_chain(card, 1);
spider_net_free_chain(card, &card->tx_chain);
spider_net_free_chain(card, &card->rx_chain);
next prev parent reply other threads:[~2006-10-10 21:14 UTC|newest]
Thread overview: 46+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-10-10 20:49 [PATCH 0/21]: powerpc/cell spidernet bugfixes, etc Linas Vepstas
2006-10-10 20:49 ` Linas Vepstas
2006-10-10 20:56 ` [PATCH 1/21]: powerpc/cell spidernet ethtool -i version number info Linas Vepstas
2006-10-10 20:57 ` [PATCH 2/21]: powerpc/cell spidernet burst alignment patch Linas Vepstas
2006-10-10 20:59 ` [PATCH 3/21]: Spidernet module parm permissions Linas Vepstas
2006-10-10 21:00 ` [PATCH 4/21]: powerpc/cell spidernet force-end fix Linas Vepstas
2006-10-10 21:00 ` [PATCH 0/21]: powerpc/cell spidernet bugfixes, etc Andrew Morton
2006-10-10 21:00 ` Andrew Morton
2006-10-10 21:01 ` [PATCH 5/21]: powerpc/cell spidernet zlen min packet length Linas Vepstas
2006-10-10 21:01 ` [PATCH 6/21]: powerpc/cell spidernet add missing netdev watchdog Linas Vepstas
2006-10-10 21:02 ` [PATCH 7/21]: Spidernet fix register field definitions Linas Vepstas
2006-10-10 21:04 ` [PATCH 8/21]: Spidernet stop queue when queue is full Linas Vepstas
2006-10-10 21:05 ` [PATCH 9/21]: powerpc/cell spidernet bogus rx interrupt bit Linas Vepstas
2006-10-10 21:06 ` [PATCH 10/21]: powerpc/cell spidernet fix error interrupt print Linas Vepstas
2006-10-10 21:08 ` [PATCH 11/21]: powerpc/cell spidernet stop error printing patch Linas Vepstas
2006-10-10 21:09 ` [PATCH 12/21]: powerpc/cell spidernet incorrect offset Linas Vepstas
2006-10-10 21:11 ` [PATCH 13/21]: powerpc/cell spidernet low watermark patch Linas Vepstas
2006-10-10 21:13 ` [PATCH 14/21]: powerpc/cell spidernet NAPI polling info Linas Vepstas
2006-10-10 21:14 ` Linas Vepstas [this message]
2006-10-10 21:15 ` [PATCH 16/21]: powerpc/cell spidernet Linas Vepstas
2006-10-10 21:18 ` [PATCH 17/21]: powerpc/cell spidernet reduce DMA kicking Linas Vepstas
2006-10-10 21:19 ` [PATCH 18/21]: powerpc/cell spidernet variable name change Linas Vepstas
2006-10-10 21:21 ` [PATCH 19/21]: powerpc/cell spidernet DMA direction fix Linas Vepstas
2006-10-10 21:22 ` [PATCH 20/21]: powerpc/cell spidernet release all descrs Linas Vepstas
2006-10-10 21:23 ` [PATCH 21/21]: powerpc/cell spidernet DMA coalescing Linas Vepstas
2006-10-10 23:20 ` jschopp
2006-10-11 1:46 ` Geoff Levand
2006-10-11 1:46 ` Geoff Levand
2006-10-11 9:25 ` Arnd Bergmann
2006-10-11 9:25 ` Arnd Bergmann
2006-10-11 9:25 ` Arnd Bergmann
2006-10-11 15:20 ` Linas Vepstas
2006-10-11 15:20 ` Linas Vepstas
2006-10-11 15:47 ` Geoff Levand
2006-10-11 15:47 ` Geoff Levand
2006-10-11 22:13 ` Benjamin Herrenschmidt
2006-10-11 22:13 ` Benjamin Herrenschmidt
2006-10-11 7:15 ` Benjamin Herrenschmidt
2006-10-11 7:15 ` Benjamin Herrenschmidt
2006-10-14 2:12 ` Joel Schopp
2006-10-11 16:02 ` [PATCH 0/21]: powerpc/cell spidernet bugfixes, etc Arnd Bergmann
2006-10-11 16:02 ` Arnd Bergmann
2006-10-11 16:42 ` James K Lewis
2006-10-11 16:42 ` James K Lewis
2006-10-11 21:06 ` James K Lewis
2006-10-11 21:06 ` James K Lewis
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20061010211429.GL4381@austin.ibm.com \
--to=linas@austin.ibm.com \
--cc=akpm@osdl.org \
--cc=arnd@arndb.de \
--cc=jeff@garzik.org \
--cc=jklewis@us.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linuxppc-dev@ozlabs.org \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.