LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2]:  powerpc/cell spidernet bottom half
From: Linas Vepstas @ 2006-08-16 16:18 UTC (permalink / raw)
  To: netdev, linux-kernel, linuxppc-dev
  Cc: akpm, Jens Osterkamp, James K Lewis, jeff, Arnd Bergmann
In-Reply-To: <20060811170337.GH10638@austin.ibm.com>


Please apply and forward upstream. This patch requires the previous
sequence of 4 spidernet patches to be applied.

--linas


The recent set of low-waterark patches for the spider result in a
significant amount of computing being done in an interrupt context.
This patch moves this to a "bottom half" aka work queue, so that
the code runs in a normal kernel context. Curiously, this seems to 
result in a performance boost of about 5% for large packets.

Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
Cc: Utz Bacher <utz.bacher@de.ibm.com>
Cc: Jens Osterkamp <Jens.Osterkamp@de.ibm.com>

----
 drivers/net/spider_net.c |   21 +++++++++++++++------
 drivers/net/spider_net.h |    4 +++-
 2 files changed, 18 insertions(+), 7 deletions(-)

Index: linux-2.6.18-rc3-mm2/drivers/net/spider_net.c
===================================================================
--- linux-2.6.18-rc3-mm2.orig/drivers/net/spider_net.c	2006-08-15 14:25:50.000000000 -0500
+++ linux-2.6.18-rc3-mm2/drivers/net/spider_net.c	2006-08-15 14:28:56.000000000 -0500
@@ -883,9 +883,10 @@ out:
  * spider_net_cleanup_tx_ring - cleans up the TX ring
  * @card: card structure
  *
- * spider_net_cleanup_tx_ring is called by the tx_timer (as we don't use
- * interrupts to cleanup our TX ring) and returns sent packets to the stack
- * by freeing them
+ * spider_net_cleanup_tx_ring is called by either the tx_timer
+ * or from a work-queue scheduled by the tx-empty interrupt.
+ * This routine releases resources associted with transmitted
+ * packets, including updating the queue tail pointer.
  */
 static void
 spider_net_cleanup_tx_ring(struct spider_net_card *card)
@@ -895,12 +896,20 @@ spider_net_cleanup_tx_ring(struct spider
 	spin_lock_irqsave(&card->tx_chain.lock, flags);
 
 	if ((spider_net_release_tx_chain(card, 0) != 0) &&
-	    (card->netdev->flags & IFF_UP))
+	    (card->netdev->flags & IFF_UP)) {
 		spider_net_kick_tx_dma(card);
+		netif_wake_queue(card->netdev);
+	}
 
 	spin_unlock_irqrestore(&card->tx_chain.lock, flags);
 }
 
+static void
+spider_net_tx_cleanup_task(void * data)
+{
+	spider_net_cleanup_tx_ring((struct spider_net_card *) data);
+}
+
 /**
  * spider_net_do_ioctl - called for device ioctls
  * @netdev: interface device structure
@@ -1499,8 +1508,7 @@ spider_net_interrupt(int irq, void *ptr,
 		netif_rx_schedule(netdev);
 	}
 	if (status_reg & SPIDER_NET_TXINT ) {
-		spider_net_cleanup_tx_ring(card);
-		netif_wake_queue(netdev);
+		schedule_work(&card->tx_cleanup_task);
 	}
 
 	if (status_reg & SPIDER_NET_ERRINT )
@@ -2117,6 +2125,7 @@ spider_net_alloc_card(void)
 	card->netdev = netdev;
 	card->msg_enable = SPIDER_NET_DEFAULT_MSG;
 	INIT_WORK(&card->tx_timeout_task, spider_net_tx_timeout_task, netdev);
+	INIT_WORK(&card->tx_cleanup_task, spider_net_tx_cleanup_task, card);
 	init_waitqueue_head(&card->waitq);
 	atomic_set(&card->tx_timeout_task_counter, 0);
 
Index: linux-2.6.18-rc3-mm2/drivers/net/spider_net.h
===================================================================
--- linux-2.6.18-rc3-mm2.orig/drivers/net/spider_net.h	2006-08-15 14:25:50.000000000 -0500
+++ linux-2.6.18-rc3-mm2/drivers/net/spider_net.h	2006-08-15 14:28:56.000000000 -0500
@@ -24,7 +24,7 @@
 #ifndef _SPIDER_NET_H
 #define _SPIDER_NET_H
 
-#define VERSION "1.1 A"
+#define VERSION "1.1 B"
 
 #include "sungem_phy.h"
 
@@ -441,6 +441,8 @@ struct spider_net_card {
 	atomic_t tx_timeout_task_counter;
 	wait_queue_head_t waitq;
 
+	struct work_struct tx_cleanup_task;
+
 	/* for ethtool */
 	int msg_enable;
 

^ permalink raw reply

* [PATCH 2/2]:  powerpc/cell spidernet refine locking
From: Linas Vepstas @ 2006-08-16 16:23 UTC (permalink / raw)
  To: netdev, linux-kernel, linuxppc-dev
  Cc: akpm, , Arnd Bergmann, jeff, Jens Osterkamp, James K Lewis, wq
In-Reply-To: <20060811170337.GH10638@austin.ibm.com>


Please apply and forward upstream. This patch requires the 
pervious set of four spidernet patches to be applied.

--linas

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 (the queue head and tail pointers,
and the queue low-watermark location).

This, with the previous patches, result in the following 
performance, using netperf, averaged over 5 minute runs:

pkt size    rate
========    ====
1500        804 Mbits/sec
 800        701 Mbits/sec
 600        600 Mbits/sec
 300        280 Mbits/sec
  60         60 Mbits/sec


Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
Cc: Utz Bacher <utz.bacher@de.ibm.com>
Cc: Jens Osterkamp <Jens.Osterkamp@de.ibm.com>

----
 drivers/net/spider_net.c |   77 ++++++++++++++++++++---------------------------
 drivers/net/spider_net.h |    2 -
 2 files changed, 35 insertions(+), 44 deletions(-)

Index: linux-2.6.18-rc3-mm2/drivers/net/spider_net.c
===================================================================
--- linux-2.6.18-rc3-mm2.orig/drivers/net/spider_net.c	2006-08-15 14:28:56.000000000 -0500
+++ linux-2.6.18-rc3-mm2/drivers/net/spider_net.c	2006-08-15 14:29:36.000000000 -0500
@@ -644,8 +644,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;
 
 	buf = pci_map_single(card->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
 	if (buf == DMA_ERROR_CODE) {
@@ -655,6 +656,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 = card->tx_chain.head->next;
+
 	descr->buf_addr = buf;
 	descr->buf_size = skb->len;
 	descr->next_descr_addr = 0;
@@ -663,6 +668,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:
@@ -673,37 +680,16 @@ spider_net_prepare_tx_descr(struct spide
 			break;
 		}
 
+	/* Chain the bus address, so that the DMA engine finds this descr. */
 	descr->prev->next_descr_addr = descr->bus_addr;
 
 	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;
-
-	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;
-	pci_unmap_single(card->pdev, descr->buf_addr, skb->len,
-			PCI_DMA_TODEVICE);
-	dev_kfree_skb_any(skb);
-}
-
 static void
 spider_net_set_low_watermark(struct spider_net_card *card)
 {
+	unsigned long flags;
 	int status;
 	int cnt=0;
 	int i;
@@ -727,11 +713,13 @@ spider_net_set_low_watermark(struct spid
 		descr = descr->next;
 
 	/* Set the new watermark, clear the old wtermark */
+	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);
 }
 
 /**
@@ -750,22 +738,30 @@ 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;
 	int rc=0;
 
 	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) {
 				rc = 1;
+				spin_unlock_irqrestore(&chain->lock, flags);
 				goto done;
 			}
 			/* fallthrough, if we release the descriptors
@@ -785,9 +781,19 @@ spider_net_release_tx_chain(struct spide
 		default:
 			card->netdev_stats.tx_dropped++;
 			rc = 1;
+			spin_unlock_irqrestore(&chain->lock, flags);
 			goto done;
 		}
-		spider_net_release_tx_descr(card);
+
+		chain->tail = chain->tail->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 */
+		pci_unmap_single(card->pdev, buf_addr, skb->len, PCI_DMA_TODEVICE);
+		dev_kfree_skb_any(skb);
 	}
 done:
 	if (rc == 1)
@@ -844,11 +850,8 @@ 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;
 	int result;
: 
-	spin_lock_irqsave(&chain->lock, flags);
-
 	spider_net_release_tx_chain(card, 0);
 
 	if (chain->head->next == chain->tail->prev) {
@@ -869,12 +872,9 @@ spider_net_xmit(struct sk_buff *skb, str
 	}
 
 	result = NETDEV_TX_OK;
-
 	spider_net_kick_tx_dma(card);
-	card->tx_chain.head = card->tx_chain.head->next;
 
 out:
-	spin_unlock_irqrestore(&chain->lock, flags);
 	netif_wake_queue(netdev);
 	return result;
 }
@@ -891,17 +891,11 @@ out:
 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);
 }
 
 static void
@@ -1932,10 +1926,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);
Index: linux-2.6.18-rc3-mm2/drivers/net/spider_net.h
===================================================================
--- linux-2.6.18-rc3-mm2.orig/drivers/net/spider_net.h	2006-08-15 14:28:56.000000000 -0500
+++ linux-2.6.18-rc3-mm2/drivers/net/spider_net.h	2006-08-15 14:29:36.000000000 -0500
@@ -24,7 +24,7 @@
 #ifndef _SPIDER_NET_H
 #define _SPIDER_NET_H
 
-#define VERSION "1.1 B"
+#define VERSION "1.1 C"
 
 #include "sungem_phy.h"
 

^ permalink raw reply

* Re: [PATCH 1/2]:  powerpc/cell spidernet bottom half
From: Jeff Garzik @ 2006-08-16 16:30 UTC (permalink / raw)
  To: Linas Vepstas
  Cc: akpm, Arnd Bergmann, netdev, James K Lewis, linux-kernel,
	linuxppc-dev, Jens Osterkamp
In-Reply-To: <20060816161856.GD20551@austin.ibm.com>

Linas Vepstas wrote:
> Please apply and forward upstream. This patch requires the previous
> sequence of 4 spidernet patches to be applied.
> 
> --linas
> 
> 
> The recent set of low-waterark patches for the spider result in a
> significant amount of computing being done in an interrupt context.
> This patch moves this to a "bottom half" aka work queue, so that
> the code runs in a normal kernel context. Curiously, this seems to 
> result in a performance boost of about 5% for large packets.
> 
> Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
> Cc: Utz Bacher <utz.bacher@de.ibm.com>
> Cc: Jens Osterkamp <Jens.Osterkamp@de.ibm.com>

Let's not reinvented NAPI, shall we...

	Jeff

^ permalink raw reply

* Re: PowerPC paxtest results w/ gcc-4.1
From: Segher Boessenkool @ 2006-08-16 17:49 UTC (permalink / raw)
  To: Gabriel Paubert
  Cc: 'Albert Cahalan', linuxppc-dev, debian-powerpc,
	Paul Mackerras
In-Reply-To: <20060816105925.GB21865@iram.es>

> I never understood why PTE entries waste 4 bits (WIMG)
> for effectively very few valid combinations.

The only invalid combinations are WI=11 -- if you know of
a way to fit 12 combinations in fewer than 4 bits, let us
know :-)

Not all of those 12 are very useful, of course.


Segher

^ permalink raw reply

* Re: [PATCH 7/7] ehea: Makefile & Kconfig
From: Michael Neuling @ 2006-08-16 19:27 UTC (permalink / raw)
  To: Jan-Bernd Themann
  Cc: Thomas Klein, Jan-Bernd Themann, netdev, linux-kernel,
	Thomas Klein, linux-ppc, Christoph Raisch, Marcus Eder
In-Reply-To: <44E0A580.9020507@de.ibm.com>

This patch is still being white space munged so it doesn't apply.  

The context is being shifted over 1 column.  All your other patches add
new files so there is no context and hence they apply.

Mikey

In message <44E0A580.9020507@de.ibm.com> you wrote:
> Signed-off-by: Jan-Bernd Themann <themann@de.ibm.com>
> 
> 
>   drivers/net/Kconfig  |    6 ++++++
>   drivers/net/Makefile |    1 +
>   2 files changed, 7 insertions(+)
> 
> 
> 
> diff -Nurp -X dontdiff linux-2.6.18-rc4/drivers/net/Kconfig patched_kernel/dr
ivers/net/Kconfig
> --- linux-2.6.18-rc4/drivers/net/Kconfig	2006-08-06 11:20:11.000000000 -
0700
> +++ patched_kernel/drivers/net/Kconfig	2006-08-08 03:00:49.526421944 -
0700
> @@ -2277,6 +2277,12 @@ config CHELSIO_T1
>             To compile this driver as a module, choose M here: the module
>             will be called cxgb.
> 
> +config EHEA
> +        tristate "eHEA Ethernet support"
> +        depends on IBMEBUS
> +        ---help---
> +          This driver supports the IBM pSeries ethernet adapter
> +
>   config IXGB
>   	tristate "Intel(R) PRO/10GbE support"
>   	depends on PCI
> diff -Nurp -X dontdiff linux-2.6.18-rc4/drivers/net/Makefile patched_kernel/d
rivers/net/Makefile
> --- linux-2.6.18-rc4/drivers/net/Makefile	2006-08-06 11:20:11.000000000 -
0700
> +++ patched_kernel/drivers/net/Makefile	2006-08-08 03:00:30.061451584 -
0700
> @@ -10,6 +10,7 @@ obj-$(CONFIG_E1000) += e1000/
>   obj-$(CONFIG_IBM_EMAC) += ibm_emac/
>   obj-$(CONFIG_IXGB) += ixgb/
>   obj-$(CONFIG_CHELSIO_T1) += chelsio/
> +obj-$(CONFIG_EHEA) += ehea/
>   obj-$(CONFIG_BONDING) += bonding/
>   obj-$(CONFIG_GIANFAR) += gianfar_driver.o
> 
> 
> 
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
> 

^ permalink raw reply

* [PATCH] powerpc: Make RTAS console init generic
From: Michael Neuling @ 2006-08-16 19:42 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev, anton

The rtas console doesn't have to be Cell specific.  If we get both
rtas tokens, we should just enabled the console then and there.

Signed-off-by: Michael Neuling <mikey@neuling.org>
---
Updated Kconfig so we can enable it.  

 arch/powerpc/Kconfig                |    2 +-
 arch/powerpc/kernel/rtas.c          |    5 +++++
 arch/powerpc/platforms/cell/setup.c |    4 ----
 3 files changed, 6 insertions(+), 5 deletions(-)

Index: linux-2.6-ozlabs/arch/powerpc/Kconfig
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/Kconfig
+++ linux-2.6-ozlabs/arch/powerpc/Kconfig
@@ -426,7 +426,7 @@ config PPC_IBM_CELL_BLADE
 	select UDBG_RTAS_CONSOLE
 
 config UDBG_RTAS_CONSOLE
-	bool
+	bool "RTAS based debug console"
 	default n
 
 config XICS
Index: linux-2.6-ozlabs/arch/powerpc/kernel/rtas.c
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/kernel/rtas.c
+++ linux-2.6-ozlabs/arch/powerpc/kernel/rtas.c
@@ -910,6 +910,11 @@ int __init early_init_dt_scan_rtas(unsig
 	basep = of_get_flat_dt_prop(node, "get-term-char", NULL);
 	if (basep)
 		rtas_getchar_token = *basep;
+
+	if (rtas_putchar_token != RTAS_UNKNOWN_SERVICE &&
+	    rtas_getchar_token != RTAS_UNKNOWN_SERVICE)
+		udbg_init_rtas_console();
+
 #endif
 
 	/* break now */
Index: linux-2.6-ozlabs/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-2.6-ozlabs.orig/arch/powerpc/platforms/cell/setup.c
+++ linux-2.6-ozlabs/arch/powerpc/platforms/cell/setup.c
@@ -150,10 +150,6 @@ static int __init cell_probe(void)
 	    !of_flat_dt_is_compatible(root, "IBM,CPBW-1.0"))
 		return 0;
 
-#ifdef CONFIG_UDBG_RTAS_CONSOLE
-	udbg_init_rtas_console();
-#endif
-
 	hpte_init_native();
 
 	return 1;

^ permalink raw reply

* Re: [PATCH 1/2]:  powerpc/cell spidernet bottom half
From: Linas Vepstas @ 2006-08-16 20:30 UTC (permalink / raw)
  To: Jeff Garzik
  Cc: akpm, Arnd Bergmann, netdev, James K Lewis, linux-kernel,
	linuxppc-dev, Jens Osterkamp
In-Reply-To: <44E34825.2020105@garzik.org>

On Wed, Aug 16, 2006 at 12:30:29PM -0400, Jeff Garzik wrote:
> Linas Vepstas wrote:
> >
> >The recent set of low-waterark patches for the spider result in a
> 
> Let's not reinvented NAPI, shall we...

?? 

I was under the impression that NAPI was for the receive side only.
This round of patches were for the transmit queue.

Let me describe the technical problem; perhaps there's some other
solution for it?  

The default socket size seems to be 128KB; (cat
/proc/sys/net/core/wmem_default) if a user application
writes more than 128 KB to a socket, the app is blocked by the 
kernel till there's room in the socket for more.  At gigabit speeds,
a network card can drain 128KB in about a millisecond, or about
four times a jiffy (assuming  HZ=250).  If the network card isn't
generaing interrupts, (and there are no other interrupts flying 
around) then the tcp stack only wakes up once a jiffy, and so 
the user app is scheduled only once a jiffy.  Thus, the max
bandwidth that the app can see is (HZ * wmem_default) bytes per 
second, or about 250 Mbits/sec for my system.  Disappointing 
for a gigabit adapter.

There's three ways out of this: 

(1) tell the sysadmin to 
    "echo 1234567 > /proc/sys/net/core/wmem_default" which 
    violates all the rules.

(2) Poll more frequently than once-a-jiffy. Arnd Bergmann and I 
    got this working, using hrtimers. It worked pretty well,
    but seemed like a hack to me.

(3) Generate transmit queue low-watermark interrupts, 
    which is an admitedly olde-fashioned but common
    engineering practice.  This round of patches implement 
    this.


--linas

^ permalink raw reply

* Re: [PATCH 1/2]:  powerpc/cell spidernet bottom half
From: Jeff Garzik @ 2006-08-16 20:34 UTC (permalink / raw)
  To: Linas Vepstas
  Cc: akpm, Arnd Bergmann, netdev, James K Lewis, linux-kernel,
	linuxppc-dev, Jens Osterkamp
In-Reply-To: <20060816203043.GJ20551@austin.ibm.com>

Linas Vepstas wrote:
> I was under the impression that NAPI was for the receive side only.

That depends on the driver implementation.

	Jeff

^ permalink raw reply

* RE: 8260  SMC1 and SMC2 serial port problems
From: Pelton, Dave @ 2006-08-16 20:46 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: Boris Shteinbock

[-- Attachment #1: Type: text/plain, Size: 3486 bytes --]

Hi Boris,

I recently upgraded my kernel from 2.6.15 to 2.6.17 on a 8247 based
custom board (8247 has a CPM2 and is similar to the 8260).  I use SMC2
as a serial port, and I had a couple of problems when I started using
2.6.17.  I think initially I was seeing the same behaviour as you
(serial port only worked when it was defined as the console).

The "compat mode" message you are seeing is part of the new CPM UART
0.02 driver (refer to http://patchwork.ozlabs.org/linuxppc/patch?id=5149
and related patches).  If there are no UART platform devices added in
your board specific code, then you will see this message.  To make the
compat mode work properly with the new driver I made a couple of changes
(see attached cpm2_uart_noplatform.diff).  The changes are to
drivers/serial/cpm_uart/cpm_uart_core.c:

1) Added a call to pinfo->set_lineif in cpm_uart_request_port
This code is required to set up the port pins and BRG for the UART.
This was in the old version of the driver and I added it back.  As far
as I can tell, this chunk of code is what makes the serial port work
properly when it is not the console (in compat mode).  To make this
properly compatible with the platform stuff, this call should not be
made if the device has platform data, but I'm not exactly sure how to
add that check in a clean way.

2) Added a call to cpm_uart_init_portdesc in cpm_uart_console_init
This was another snippet that was in the previous version of the driver.
I don't recall exactly what behaviour this fixed, but I think it made
things better.  Again this may not work properly if the device has
platform data.


I did try defining a platform device for the UART in my board specific
file (similar to what is done in arch/ppc/platforms/mpc8272ads_setup.c),
but I ran into a couple of problems here too.  The main problem is that
arch/ppc/syslib/pq2_devices.c needs a small change to the naming of
things for the SMCs (see attached cpm2_smc_resource_rename.diff).  That
made things work better, but not 100%.  I decided to go back to compat
mode, because with the fixes outlined above it was working fine for me.


- Hope this helps,
  David Pelton


-----Original Message-----
Sent: Monday, August 14, 2006 6:26 PM
To: linuxppc-embedded@ozlabs.org
Subject: 8260 SMC1 and SMC2 serial port problems

Hi guys.

I am working on the Linux port on a custom 8260-based board.
During the port I've encountered a few problems with serial ports.

1. On the latest kernel 2.6.17 the cpm2 serial driver fails during the
bus scan and fails back to so called compat mode.
2. For whatever strange reason, the driver is unable to initialize
serial port, if the console on SMC is not selected.
3. I am unable to work with both SMC1 and SMC2 together. During driver
init, only one port actually gets an IRQ.
In another words, if I enable both SMC1 and SMC2 in the  kernel config. 
and put console on ttyCPM0, then SMC1 gets IRQ, but SMC2 doesn't. dmesg
actually prints IRQs for both ports, but looking into /proc/irq reveals,
that only one interrupt is assigned only for port that is used as a
console.

2) and 3) relate for both 2.6.17 and 2.6.16 kernel trees

Could someone, please, advise me, on possible solutions for those
problems ?

Thanks in advance,
Boris
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded

[-- Attachment #2: cpm2_smc_resource_rename.diff --]
[-- Type: application/octet-stream, Size: 901 bytes --]

Index: linux/arch/ppc/syslib/pq2_devices.c
===================================================================
--- linux/arch/ppc/syslib/pq2_devices.c	(revision 33743)
+++ linux/arch/ppc/syslib/pq2_devices.c	(working copy)
@@ -297,13 +297,13 @@
 		.num_resources	 = 3,
 		.resource = (struct resource[]) {
 			{
-				.name	= "smc_mem",
+				.name	= "regs",
 				.start	= 0x11A80,
 				.end	= 0x11A8F,
 				.flags	= IORESOURCE_MEM,
 			},
 			{
-				.name	= "smc_pram",
+				.name	= "pram",
 				.start	= 0x87fc,
 				.end	= 0x87fd,
 				.flags	= IORESOURCE_MEM,
@@ -321,13 +321,13 @@
 		.num_resources	 = 3,
 		.resource = (struct resource[]) {
 			{
-				.name	= "smc_mem",
+				.name	= "regs",
 				.start	= 0x11A90,
 				.end	= 0x11A9F,
 				.flags	= IORESOURCE_MEM,
 			},
 			{
-				.name	= "smc_pram",
+				.name	= "pram",
 				.start	= 0x88fc,
 				.end	= 0x88fd,
 				.flags	= IORESOURCE_MEM,

[-- Attachment #3: cpm2_uart_noplatform.diff --]
[-- Type: application/octet-stream, Size: 881 bytes --]

Index: linux/drivers/serial/cpm_uart/cpm_uart_core.c
===================================================================
--- linux/drivers/serial/cpm_uart/cpm_uart_core.c	(revision 33559)
+++ linux/drivers/serial/cpm_uart/cpm_uart_core.c	(working copy)
@@ -868,6 +869,14 @@
 	if (pinfo->flags & FLAG_CONSOLE)
 		return 0;
 
+	/*
+	 * Setup any port IO, connect any baud rate generators,
+	 * etc.	 This is expected to be handled by board
+	 * dependant code
+	 */
+	if (pinfo->set_lineif)		 
+		pinfo->set_lineif(pinfo);	 
+ 
 	if (IS_SMC(pinfo)) {
 		pinfo->smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
 		pinfo->smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
@@ -1238,7 +1243,10 @@
 
 int __init cpm_uart_console_init(void)
 {
-	register_console(&cpm_scc_uart_console);
+	int ret = cpm_uart_init_portdesc(); 	 
+
+	if (!ret)
+		register_console(&cpm_scc_uart_console);
 	return 0;
 }
 

^ permalink raw reply

* Linux hanging on Xilinx SystemACE
From: Clint Thomas @ 2006-08-16 21:06 UTC (permalink / raw)
  To: linuxppc-embedded

[-- Attachment #1: Type: text/plain, Size: 836 bytes --]

Hey,

Using the powerpc development tree of Linux 2.4, I am trying to boot my
system from CompactFlash using Xilinx SystemACE. My compact flash card
has two partitions, a 16MB FAT16 that holds the combination FPGA image /
Linux Kernel ELF file, and an Ext2 partition that holds the root file
system. The system starts the boot process, uncompresses the Linux
kernel and begins loading drivers. Part way into this process, it
conducts a partition check of the drive being reported to it by
SystemACE, however, it hangs at that point. No kernel panic, no error
message, it simply hangs. Here is the output at that point...

Partition check:
 xsysacea:
 
what I am trying to find out is if this problem has been seen/fixed in
the past? or did I format the CF card incorrectly?
 
Clinton Thomas
cthomas@soneticom.com
 

[-- Attachment #2: Type: text/html, Size: 1432 bytes --]

^ permalink raw reply

* Re: [PATCH 1/2]: powerpc/cell spidernet bottom half
From: David Miller @ 2006-08-16 20:46 UTC (permalink / raw)
  To: jeff
  Cc: akpm, arnd, netdev, jklewis, linux-kernel, linuxppc-dev,
	Jens.Osterkamp
In-Reply-To: <44E38157.4070805@garzik.org>

From: Jeff Garzik <jeff@garzik.org>
Date: Wed, 16 Aug 2006 16:34:31 -0400

> Linas Vepstas wrote:
> > I was under the impression that NAPI was for the receive side only.
> 
> That depends on the driver implementation.

What Jeff is trying to say is that TX reclaim can occur in
the NAPI poll routine, and in fact this is what the vast
majority of NAPI drivers do.

It also makes the locking simpler.

In practice, the best thing seems to be to put both RX and TX
work into ->poll() and have a very mild hw interrupt mitigation
setting programmed into the chip.

I'm not familiar with the spidernet TX side interrupt capabilities
so I can't say whether that is something that can be directly
implied.  In fact, I get the impression that spidernet is limited
in some way and that's where all the strange approaches are coming
from :)

^ permalink raw reply

* Re: [PATCH 1/2]: powerpc/cell spidernet bottom half
From: Arnd Bergmann @ 2006-08-16 21:24 UTC (permalink / raw)
  To: David Miller
  Cc: akpm, jeff, netdev, jklewis, linux-kernel, linuxppc-dev,
	Jens.Osterkamp
In-Reply-To: <20060816.134640.115912460.davem@davemloft.net>

Am Wednesday 16 August 2006 22:46 schrieb David Miller:
> I'm not familiar with the spidernet TX side interrupt capabilities
> so I can't say whether that is something that can be directly
> implied. =A0In fact, I get the impression that spidernet is limited
> in some way and that's where all the strange approaches are coming
> from :)

Actually, the capabilities of the chip are quite powerful, it only
seems to be hard to make it go fast using any of them. That may
be the fault of strange locking rules and other bugs we had in
the driver before, so maybe you can recommend which one to use.

Cleaning up the TX queue only from ->poll() like all the others
sounds like the right approach to simplify the code.

The spider hardware offers at least these options:

=2D end of TX queue interrupt
=2D set a per-descriptor bit to fire an interrupt at a specific frame
=2D an interrupt for each frame (may be multiple descriptors)
=2D an interrupt for each descriptor
=2D timers implemented in the spidernet hardware

We first had an interrupt per descriptor, then got rid of all TX
interrupts and replaced them by timers to reduce the interrupt load,
but reducing throughput in the case where user space sleeps on a full
socket buffer.

The last patches that were suggested introduce marking a single descriptor
(not the last one, but somewhere near the end of the queue) so we fire
an interrupt just before the TX queue gets empty.

	Arnd <><

^ permalink raw reply

* Re: [PATCH 1/2]: powerpc/cell spidernet bottom half
From: David Miller @ 2006-08-16 21:32 UTC (permalink / raw)
  To: arnd
  Cc: akpm, jeff, netdev, jklewis, linux-kernel, linuxppc-dev,
	Jens.Osterkamp
In-Reply-To: <200608162324.47235.arnd@arndb.de>

From: Arnd Bergmann <arnd@arndb.de>
Date: Wed, 16 Aug 2006 23:24:46 +0200

> We first had an interrupt per descriptor, then got rid of all TX
> interrupts and replaced them by timers to reduce the interrupt load,
> but reducing throughput in the case where user space sleeps on a full
> socket buffer.

The best schemes seem to be to interrupt mitigate using a combination
of time and number of TX entries pending to be purged.  This is what
most gigabit chips seem to offer.

On Tigon3, for example, we tell the chip to interrupt if either 53
frames or 150usecs have passed since the first TX packet has become
available for reclaim.

That bounds the latency as well as force the interrupt if a lot of TX
work becomes available.

Can spidernet be told these kinds of parameters?  "N packets or
X usecs"?

This is all controllable via ethtool btw (via ETHTOOL_{S,G}COALESCE),
so you can experiment if you want.

^ permalink raw reply

* Re: Linux hanging on Xilinx SystemACE
From: Grant Likely @ 2006-08-16 21:48 UTC (permalink / raw)
  To: Clint Thomas; +Cc: linuxppc-embedded
In-Reply-To: <3C02138692C13C4BB675FE7EA240952918DBED@bluefin.Soneticom.local>

On 8/16/06, Clint Thomas <cthomas@soneticom.com> wrote:
>
>
> Hey,
>
> Using the powerpc development tree of Linux 2.4, I am trying to boot my
> system from CompactFlash using Xilinx SystemACE. My compact flash card has
> two partitions, a 16MB FAT16 that holds the combination FPGA image / Linux
> Kernel ELF file, and an Ext2 partition that holds the root file system. The
> system starts the boot process, uncompresses the Linux kernel and begins
> loading drivers. Part way into this process, it conducts a partition check
> of the drive being reported to it by SystemACE, however, it hangs at that
> point. No kernel panic, no error message, it simply hangs. Here is the
> output at that point...
>
> Partition check:
>  xsysacea:
>
> what I am trying to find out is if this problem has been seen/fixed in the
> past? or did I format the CF card incorrectly?

Checking partitions is a user-space activity (fsck).  Remove it from
your init scripts.  Besides, unless your using a microdrive, your ext2
rootfs should be mounted read-only which greatly reduces the need for
fsck.  (because FLASH will wear out after too many writes)

Cheers,
g.
-- 
Grant Likely, B.Sc. P.Eng.
Secret Lab Technologies Ltd.
grant.likely@secretlab.ca
(403) 399-0195

^ permalink raw reply

* Re: [PATCH 1/2]: powerpc/cell spidernet bottom half
From: Linas Vepstas @ 2006-08-16 21:58 UTC (permalink / raw)
  To: David Miller
  Cc: akpm, jeff, arnd, netdev, jklewis, linux-kernel, linuxppc-dev,
	Jens.Osterkamp
In-Reply-To: <20060816.134640.115912460.davem@davemloft.net>

On Wed, Aug 16, 2006 at 01:46:40PM -0700, David Miller wrote:
> From: Jeff Garzik <jeff@garzik.org>
> Date: Wed, 16 Aug 2006 16:34:31 -0400
> 
> > Linas Vepstas wrote:
> > > I was under the impression that NAPI was for the receive side only.
> > 
> > That depends on the driver implementation.
> 
> What Jeff is trying to say is that TX reclaim can occur in
> the NAPI poll routine, and in fact this is what the vast
> majority of NAPI drivers do.

I'll experiment with this.  When doing, say, an ftp, there are 
enough TCP ack packets coming back to have NAPI netdev->poll 
be called frequently enough? 

> implied.  In fact, I get the impression that spidernet is limited
> in some way and that's where all the strange approaches are coming
> from :)

Hmm. Or maybe I'm just getting old. Once upon a time, low watermarks
were considered the "best" way of doing anything; never occurred to me
it would be considered "strange".  Based on my probably obsolete idea
of what constitutes "slick hardware", I was actually impressed by what
the spidernet could do.

Aside from cleaning up the transmit ring in the receive poll loop,
what would be the not-so-strange way of doing things?

--linas

^ permalink raw reply

* Re: Linux hanging on Xilinx SystemACE
From: Keith J Outwater @ 2006-08-16 22:01 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <3C02138692C13C4BB675FE7EA240952918DBED@bluefin.Soneticom.local>

[-- Attachment #1: Type: text/plain, Size: 1677 bytes --]

Clint,

> Using the powerpc development tree of Linux 2.4, I am trying to boot my 
system from CompactFlash using Xilinx SystemACE. My compact flash card has 
two partitions, a 16MB FAT16 that holds the combination FPGA image / Linux 
Kernel ELF file, and an Ext2 partition that holds the root file system. 
The system starts the boot process, uncompresses the Linux kernel and 
begins loading drivers. Part way into this process, it conducts a 
partition check of the drive being reported to it by SystemACE, however, 
it hangs at that point. No kernel panic, no error message, it simply 
hangs. Here is the output at that point...
> 
> Partition check:
>  xsysacea:
> 
> what I am trying to find out is if this problem has been seen/fixed in 
the past? or did I format the CF card incorrectly?
> 

I have a system that uses the SystemAce in a similar way.  I was also 
having lockups.  After a lot of digging, I found a patch by John Masters 
(e-mail unknown) to the MontaVista SystemAce driver in the 2.4 kernel that 
disables the use of interrupts and runs the SystemAce in a polled mode. 
Performance is not that great, but at least it does not crash with the 
patch.  As I recall, the reason that the unpatched driver crashed is that 
the SystemAce is issuing more than one interrupt upon completion of a 
sector read or write.  Apparently, the Xilinx ML300 board works fine 
without this patch while other eval boards like the Memec DS-BD-2VPxx 
crash without the patch.

This still may not be your problem, but the patch may help later on.

I've attached the patched file.  The file is from 
./drivers/block/xilinx_sysace/adapter.c in the 2.4.30 from MontaVista.

Keith

[-- Attachment #2: adapter.c --]
[-- Type: application/octet-stream, Size: 25817 bytes --]

/*
 * adapter.c
 *
 * Xilinx System ACE Adapter component to interface System ACE to Linux
 *
 * Author: MontaVista Software, Inc.
 *         source@mvista.com
 *
 * History:
 * 22/09/2004 - Added xsa_use_interrupts.
 * Jon Masters <jcm@xxxxxxxxxxxxxx>.
 *
 * 2002 (c) MontaVista, Software, Inc.  This file is licensed under the terms
 * of the GNU General Public License version 2.  This program is licensed
 * "as is" without any warranty of any kind, whether express or implied.
 */

/*
 * Through System ACE, the processor can access the CompactFlash and the
 * JTAG chain.  In addition, the System ACE controls system reset and
 * which configuration will be loaded into the JTAG chain at that time.
 * This driver provides two different interfaces.  The first is handling
 * reset by tying into the system's reset code as well as providing a
 * /proc interface to read and write which configuration should be used
 * when the system is reset.  The second is to expose a block interface
 * to the CompactFlash.
 * 
 * This driver is a bit unusual in that it is composed of two logical
 * parts where one part is the OS independent code and the other part is
 * the OS dependent code.  Xilinx provides their drivers split in this
 * fashion.  This file represents the Linux OS dependent part known as
 * the Linux adapter.  The other files in this directory are the OS
 * independent files as provided by Xilinx with no changes made to them.
 * The names exported by those files begin with XSysAce_.  All functions
 * in this file that are called by Linux have names that begin with
 * xsysace_.  Any other functions are static helper functions.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/hdreg.h>
#include <linux/slab.h>
#include <linux/blkpg.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>

#define NR_HD		1	/* System ACE only handles one CompactFlash */
#define PARTN_BITS	4	/* Only allow 15 partitions. */

/* Dynamically allocate a major number. */
static int xsa_major = 0;

#define MAJOR_NR	(xsa_major)
#define MAJOR_NAME	"xsysace"

#define DEVICE_NAME	"System ACE"
#define DEVICE_REQUEST	xsysace_do_request
#define DEVICE_NR(device) (MINOR(device) >> PARTN_BITS)

#include <linux/blk.h>
#include <linux/blkdev.h>
#include <xbasic_types.h>
#include "xsysace.h"

#undef  DEBUG
#ifdef  DEBUG
# define debugk(fmt,args...)    printk(fmt ,##args)
# define DEBUG_OPTARG(arg)  arg,
#else
# define debugk(fmt,args...)
# define DEBUG_OPTARG(arg)
#endif

/*
 * We have to disable interrupts on certain boards where writing causes an
 * additional unexpected hardware interrupt on sector write completion.
 */
static int xsa_use_interrupts = 0;

MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
MODULE_DESCRIPTION("Xilinx System ACE block driver");
MODULE_LICENSE("GPL");
MODULE_PARM(xsa_enable_interrupts, "i");

/*
 * We have to wait for a lock and for the CompactFlash to not be busy
 * via polling.  If dont_spin is non-zero, we will use schedule_timeout
 * in a loop to check for these conditions.  If dont_spin is zero, we
 * will tight loop without a schedule_timeout as long as need_resched is
 * false.  If need_resched is true, we'll fall back to using
 * schedule_timeout.  This could obviously be made run-time settable.
 */
static const int dont_spin = 0;

static u32 save_BaseAddress;	/* Saved physical base address */
#ifdef CONFIG_VIRTEX_II_PRO
static void (*old_restart)(char *cmd);	/* old ppc_md.restart */
#endif

static unsigned char heads;
static unsigned char sectors;
static unsigned short cylinders;

static int access_count = 0;
static char revalidating = 0;
static DECLARE_WAIT_QUEUE_HEAD(revalidate_wait);

/*
 * The following variables are used to keep track of what all has been
 * done to make error handling easier.
 */
static char reqirq = 0;		/* Has request_irq() been called? */
static char registered = 0;	/* Has devfs_register_blkdev() been called? */

/*
 * The underlying OS independent code needs space as well.  A pointer to
 * the following XSysAce structure will be passed to any XSysAce_
 * function that requires it.  However, we treat the data as an opaque
 * object in this file (meaning that we never reference any of the
 * fields inside of the structure).
 */
static XSysAce SysAce;

/* These tables are indexed by major and minor numbers. */
static int xsa_sizes[NR_HD << PARTN_BITS];	/* Size of the device, kb */
static int xsa_blocksizes[NR_HD << PARTN_BITS];	/* Block size, bytes */
static int xsa_hardsectsizes[NR_HD << PARTN_BITS];	/* Sector size, bytes */
static int xsa_maxsect[NR_HD << PARTN_BITS];	/* Max request size, sectors */
static struct hd_struct xsa_hd[NR_HD << PARTN_BITS];	/* Partition Table */

/*
 * In general, requests enter this driver through xsysace_do_request()
 * which then schedules the xsa_thread.  The xsa_thread sends the
 * request down to the Xilinx OS independent layer.  When the request
 * completes, EventHandler() will get called as a result of an
 * interrupt.  The following variables support this flow.
 */
static struct task_struct *xsa_task = NULL;	/* xsa_thread pointer */
static struct completion task_sync;	/* xsa_thread start/stop syncing */
static char task_shutdown = 0;	/* Set to non-zero when task should quit.  */

/*
 * req_fnc will be either NULL or a pointer to XSysAce_SectorRead or
 * XSysAce_SectorWrite.  It will be set to point to one of the XSysAce*
 * functions by xsysace_do_request and then xsa_thread will be scheduled.
 * The xsa_thread will then NULL req_fnc after it has copied the pointer.
 */
static XStatus(*req_fnc) (XSysAce * InstancePtr, u32 StartSector,
			  int NumSectors, u8 * BufferPtr);
/* xsa_thread waits on req_wait until xsysace_do_request does wake_up on it */
static DECLARE_WAIT_QUEUE_HEAD(req_wait);
/* req_active is a simple flag that says a request is being serviced. */
static char req_active = 0;
/* req_str will be used for errors and will be either "reading" or "writing" */
static char *req_str;


/* SAATODO: Xilinx is going to add this function.  Nuke when they do. */
unsigned int
XSysAce_GetCfgAddr(XSysAce * InstancePtr)
{
	u32 Status;

	XASSERT_NONVOID(InstancePtr != NULL);
	XASSERT_NONVOID(InstancePtr->IsReady == XCOMPONENT_IS_READY);

	Status = XSysAce_mGetControlReg(InstancePtr->BaseAddress);
	if (!(Status & XSA_CR_FORCECFGADDR_MASK))
		Status = XSysAce_mGetStatusReg(InstancePtr->BaseAddress);

	return (unsigned int) ((Status & XSA_SR_CFGADDR_MASK) >>
			       XSA_CR_CFGADDR_SHIFT);
}

/* SAATODO: Nuke the following line when Config stuff moved out. */
extern XSysAce_Config XSysAce_ConfigTable[];
/* SAATODO: This function will be moved into the Xilinx code. */
/*****************************************************************************/
/**
*
* Lookup the device configuration based on the sysace instance.  The table
* XSysAce_ConfigTable contains the configuration info for each device in the system.
*
* @param Instance is the index of the interface being looked up.
*
* @return
*
* A pointer to the configuration table entry corresponding to the given
* device ID, or NULL if no match is found.
*
* @note
*
* None.
*
******************************************************************************/
XSysAce_Config *
XSysAce_GetConfig(int Instance)
{
	if (Instance < 0 || Instance >= XPAR_XSYSACE_NUM_INSTANCES) {
		return NULL;
	}

	return &XSysAce_ConfigTable[Instance];
}

/*
 * The following block of code implements the reset handling.  The first
 * part implements /proc/xsysace/cfgaddr.  When read, it will yield a
 * number from 0 to 7 that represents which configuration will be used
 * next (the configuration address).  Writing a number to it will change
 * the configuration address.  After that is the function that is hooked
 * into the system's reset handler.
 */
#ifndef CONFIG_PROC_FS
#define proc_init() 0
#define proc_cleanup()
#else
#define CFGADDR_NAME "cfgaddr"

static struct proc_dir_entry *xsysace_dir = NULL;
static struct proc_dir_entry *cfgaddr_file = NULL;

static int
cfgaddr_read(char *page, char **start,
	     off_t off, int count, int *eof, void *data)
{
	unsigned int cfgaddr;

	/* Make sure we have room for a digit (0-7), a newline and a NULL */
	if (count < 3)
		return -EINVAL;

	MOD_INC_USE_COUNT;

	cfgaddr = XSysAce_GetCfgAddr(&SysAce);

	count = sprintf(page + off, "%d\n", cfgaddr);
	*eof = 1;

	MOD_DEC_USE_COUNT;

	return count;
}

static int
cfgaddr_write(struct file *file,
	      const char *buffer, unsigned long count, void *data)
{
	char val[2];

	if (count < 1 || count > 2)
		return -EINVAL;

	MOD_INC_USE_COUNT;

	if (copy_from_user(val, buffer, count)) {
		MOD_DEC_USE_COUNT;
		return -EFAULT;
	}

	if (val[0] < '0' || val[0] > '7' || (count == 2 && !(val[1] == '\n' ||
							     val[1] == '\0'))) {
		MOD_DEC_USE_COUNT;
		return -EINVAL;
	}
#endif

	XSysAce_SetCfgAddr(&SysAce, val[0] - '0');

	MOD_DEC_USE_COUNT;

	return count;
}

static int
proc_init(void)
{
	xsysace_dir = proc_mkdir(MAJOR_NAME, NULL);
	if (!xsysace_dir)
		return -ENOMEM;
	xsysace_dir->owner = THIS_MODULE;

	cfgaddr_file = create_proc_entry(CFGADDR_NAME, 0644, xsysace_dir);
	if (!cfgaddr_file) {
		remove_proc_entry(MAJOR_NAME, NULL);
		return -ENOMEM;
	}
	cfgaddr_file->read_proc = cfgaddr_read;
	cfgaddr_file->write_proc = cfgaddr_write;
	cfgaddr_file->owner = THIS_MODULE;
	return 0;
}

static void
proc_cleanup(void)
{
	if (cfgaddr_file)
		remove_proc_entry(CFGADDR_NAME, xsysace_dir);
	if (xsysace_dir)
		remove_proc_entry(MAJOR_NAME, NULL);
}

#ifdef CONFIG_VIRTEX_II_PRO
/*
 * The XSysAce_ResetCfg function causes the SystemACE to reset the
 * Xilinx chain that is attached to it. If I am a Virtex II Pro, then
 * presumably that includes me. Thus, The ResetCfg will ultimately
 * reset me, the processor, end of story.
 */
static void
xsysace_restart(char *cmd)
{
	printk(KERN_INFO "Using SystemACE to restart stystem ...\n");
	XSysAce_ResetCfg(&SysAce);

	/* Wait for reset. */
	for (;;) ;
}
#endif

/*
 * The code to handle the block device starts here.
 */

/*
 * This is just a small helper function to clean up a request that has
 * been given to the xsa_thread.
 */
static void
xsa_complete_request(int uptodate)
{
	unsigned long flags;

	XSysAce_Unlock(&SysAce);
	spin_lock_irqsave(&io_request_lock, flags);
	end_request(uptodate);
	req_active = 0;
	/* If there's something in the queue, */
	if (!QUEUE_EMPTY)
		xsysace_do_request(NULL);	/* handle it. */
	spin_unlock_irqrestore(&io_request_lock, flags);
}

/* Small helper function used inside polling loops. */
static inline void
xsa_short_delay(void)
{
	/* If someone else needs the CPU, go to sleep. */
	if (dont_spin || current->need_resched) {
		set_current_state(TASK_INTERRUPTIBLE);
		schedule_timeout(HZ / 100);
	}
}

/* Simple function that hands an interrupt to the Xilinx code. */
static void
xsysace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
	XSysAce_InterruptHandler(&SysAce);
}

/* Called by the Xilinx interrupt handler to give us an event. */
static void
EventHandler(void *CallbackRef, int Event)
{
	u32 ErrorMask;

	switch (Event) {
	case XSA_EVENT_DATA_DONE:
		xsa_complete_request(1);	/* The request succeeded. */
		break;

	case XSA_EVENT_ERROR:
		ErrorMask = XSysAce_GetErrors(&SysAce);

		/* Print out what went wrong. */
		if (ErrorMask & XSA_ER_CARD_RESET)
			printk(KERN_ERR "CompactFlash failed to reset\n");
		if (ErrorMask & XSA_ER_CARD_READY)
			printk(KERN_ERR "CompactFlash failed to ready\n");
		if (ErrorMask & XSA_ER_CARD_READ)
			printk(KERN_ERR "CompactFlash read command failed\n");
		if (ErrorMask & XSA_ER_CARD_WRITE)
			printk(KERN_ERR "CompactFlash write command failed\n");
		if (ErrorMask & XSA_ER_SECTOR_READY)
			printk(KERN_ERR
			       "CompactFlash sector failed to ready\n");
		if (ErrorMask & XSA_ER_BAD_BLOCK)
			printk(KERN_ERR "CompactFlash bad block detected\n");
		if (ErrorMask & XSA_ER_UNCORRECTABLE)
			printk(KERN_ERR "CompactFlash uncorrectable error\n");
		if (ErrorMask & XSA_ER_SECTOR_ID)
			printk(KERN_ERR "CompactFlash sector ID not found\n");
		if (ErrorMask & XSA_ER_ABORT)
			printk(KERN_ERR "CompactFlash command aborted\n");
		if (ErrorMask & XSA_ER_GENERAL)
			printk(KERN_ERR "CompactFlash general error\n");

		if (ErrorMask & XSA_ER_CFG_READ)
			printk(KERN_ERR
			       "JTAG controller couldn't read configuration from the CompactFlash\n");
		if (ErrorMask & XSA_ER_CFG_ADDR)
			printk(KERN_ERR
			       "Invalid address given to JTAG controller\n");
		if (ErrorMask & XSA_ER_CFG_FAIL)
			printk(KERN_ERR
			       "JTAG controller failed to configure a device\n");
		if (ErrorMask & XSA_ER_CFG_INSTR)
			printk(KERN_ERR
			       "Invalid instruction during JTAG configuration\n");
		if (ErrorMask & XSA_ER_CFG_INIT)
			printk(KERN_ERR "JTAG CFGINIT pin error\n");

		/* Check for errors that should reset the CompactFlash */
		if (ErrorMask & (XSA_ER_CARD_RESET |
				 XSA_ER_CARD_READY |
				 XSA_ER_CARD_READ |
				 XSA_ER_CARD_WRITE |
				 XSA_ER_SECTOR_READY |
				 XSA_ER_BAD_BLOCK |
				 XSA_ER_UNCORRECTABLE |
				 XSA_ER_SECTOR_ID | XSA_ER_ABORT |
				 XSA_ER_GENERAL)) {
			if (XSysAce_ResetCF(&SysAce) != XST_SUCCESS)
				printk(KERN_ERR
				       "Could not reset CompactFlash\n");
			xsa_complete_request(0); /* The request failed. */
		}
		break;
	case XSA_EVENT_CFG_DONE:
		printk(KERN_WARNING "XSA_EVENT_CFG_DONE not handled yet.\n");
		break;
	default:
		printk(KERN_ERR "%s: unrecognized event %d\n",
		       DEVICE_NAME, Event);
		break;
	}
}

/*
 * This task takes care of sending requests down to the Xilinx OS independent
 * code.  A task is necessary because there isn't an interrupt telling us
 * when the hardware is ready to accept another request, so we have to poll.
 */
static int
xsa_thread(void *arg)
{
	XStatus stat;
	unsigned long sector;

	struct task_struct *tsk = current;
	DECLARE_WAITQUEUE(wait, tsk);
	xsa_task = tsk;

	daemonize();
	reparent_to_init();
	strcpy(xsa_task->comm, MAJOR_NAME);
	xsa_task->tty = NULL;

	/* only want to receive SIGKILL */
	spin_lock_irq(&xsa_task->sigmask_lock);
	siginitsetinv(&xsa_task->blocked, sigmask(SIGKILL));
	recalc_sigpending(xsa_task);
	spin_unlock_irq(&xsa_task->sigmask_lock);

	complete(&task_sync);

	add_wait_queue(&req_wait, &wait);
	for (;;) {
		XStatus(*cur_req) (XSysAce * InstancePtr, u32 StartSector,
				   int NumSectors, u8 * BufferPtr);

		/* Block waiting for request */
		for (;;) {
			set_task_state(tsk, TASK_INTERRUPTIBLE);
			cur_req = req_fnc;
			if (cur_req != NULL) {
				req_fnc = NULL;
				break;	/* We've got a request. */
			}
			while (signal_pending(tsk)) {
				siginfo_t info;

				/* Only honor the signal if we're cleaning up */
				if (task_shutdown)
					goto exit;
				/*
				 * Someone else sent us a kill (probably
				 * the shutdown scripts "Sending all
				 * processes the KILL signal").  Just
				 * dequeue it and ignore it.
				 */
				spin_lock_irq(&current->sigmask_lock);
				(void)dequeue_signal(&current->blocked, &info);
				spin_unlock_irq(&current->sigmask_lock);
			}
			schedule();
		}
		set_task_state(tsk, TASK_RUNNING);

		/* We have a request. */
		sector = (CURRENT->sector +
			  xsa_hd[MINOR(CURRENT->rq_dev)].start_sect);

		while ((stat = XSysAce_Lock(&SysAce, 0)) == XST_DEVICE_BUSY)
			xsa_short_delay();
		if (stat != XST_SUCCESS) {
			printk(KERN_ERR "%s: Error %d when locking.\n",
			       DEVICE_NAME, stat);
			xsa_complete_request(0);	/* Request failed. */
		}

		while ((stat = cur_req(&SysAce, sector,
				       CURRENT->current_nr_sectors,
				       CURRENT->buffer)) == XST_DEVICE_BUSY)
			xsa_short_delay();
		/*
		 * If the stat is XST_SUCCESS, we have successfully
		 * gotten the request started on the hardware.  The
		 * completion (or error) interrupt will unlock the
		 * CompactFlash and complete the request, so we don't
		 * need to do anything except just loop around and wait
		 * for the next request.  If the status is not
		 * XST_SUCCESS, we need to finish the request with an
		 * error before waiting for the next request.
		 */
		if (stat != XST_SUCCESS) {
			printk(KERN_ERR "%s: Error %d when %s sector %lu.\n",
			       DEVICE_NAME, stat, req_str, sector);
			xsa_complete_request(0);	/* Request failed. */
		}

		if ((!xsa_use_interrupts) && (stat == XST_SUCCESS)) {
			debugk("RIQC: request complete.\n");
			xsa_complete_request(1);
		}
	}

      exit:
	remove_wait_queue(&req_wait, &wait);

	xsa_task = NULL;
	complete_and_exit(&task_sync, 0);
}

static void
xsysace_do_request(request_queue_t * q)
{
	/* We're already handling a request.  Don't accept another. */
	if (req_active)
		return;

	for (;;) {
		INIT_REQUEST;

		switch (CURRENT->cmd) {
		case READ:
			req_str = "reading";
			req_fnc = XSysAce_SectorRead;
			break;
		case WRITE:
			req_str = "writing";
			req_fnc = XSysAce_SectorWrite;
			break;
		default:
			printk(KERN_CRIT "%s: unknown request %d.\n",
			       DEVICE_NAME, CURRENT->cmd);
			end_request(0);	/* Bad request.  End it and onwards. */
			continue;	/* Go on to the next request. */
		}

		req_active = 1;
		wake_up(&req_wait);	/* Schedule task to take care of it */
		/*
		 * It is up to the task or interrupt handler to complete
		 * the request.  We return now so the io_request_lock
		 * will get cleared and requests can be queued.
		 */
		return;
	}
}

extern struct gendisk xsa_gendisk;

static int
xsa_revalidate(kdev_t kdev, int max_access)
{
	int target, max_p, start, i;
	long flags;

	target = DEVICE_NR(kdev);

	save_flags(flags);
	cli();
	if (revalidating || access_count > max_access) {
		restore_flags(flags);
		return -EBUSY;
	}
	revalidating = 1;
	restore_flags(flags);

	max_p = xsa_gendisk.max_p;
	start = target << PARTN_BITS;
	for (i = max_p - 1; i >= 0; i--) {
		int minor = start + i;
		invalidate_device(MKDEV(MAJOR_NR, minor), 1);
		xsa_gendisk.part[minor].start_sect = 0;
		xsa_gendisk.part[minor].nr_sects = 0;
	}

	grok_partitions(&xsa_gendisk, target, NR_HD << PARTN_BITS,
			(long) cylinders * (long) heads * (long) sectors);
	revalidating = 0;
	wake_up(&revalidate_wait);
	return 0;
}

/*
 * For right now, there isn't a way to tell the hardware to spin down
 * the drive.  For IBM Microdrives, which is what the ML300 ships with,
 * removing them without a spindown is probably not very good.  Thus, we
 * don't even want to have the System ACE driver handle removable media.
 * For now, placeholder code has been surrounded by ifdef XSA_REMOVABLE
 * (which is not defined) in a few places in this file.  Something that
 * is not handled in the placeholder code is identifying the new drive.
 */
#ifdef XSA_REMOVABLE
static int
xsysace_revalidate(kdev_t kdev)
{
	return xsa_revalidate(kdev, 0);
}

static int
xsysace_check_change(kdev_t kdev)
{
	/*
	 * If and when we do support removable media, we'll need to
	 * figure out how to tell if the media was changed.  For now,
	 * just always say that the media was changed, which is safe,
	 * but not optimal.
	 */
	return 1;
}
#endif

static int
xsysace_open(struct inode *inode, struct file *file)
{
	wait_event(revalidate_wait, !revalidating);
	access_count++;

	MOD_INC_USE_COUNT;
	return 0;
}

static int
xsysace_release(struct inode *inode, struct file *file)
{
	access_count--;

	MOD_DEC_USE_COUNT;
	return 0;
}

static int
xsysace_ioctl(struct inode *inode, struct file *file,
	      unsigned int cmd, unsigned long arg)
{
	if (!inode || !inode->i_rdev)
		return -EINVAL;

	switch (cmd) {
	case BLKGETSIZE:
		return put_user(xsa_hd[MINOR(inode->i_rdev)].nr_sects,
				(unsigned long *) arg);
	case BLKGETSIZE64:
		return put_user((u64) xsa_hd[MINOR(inode->i_rdev)].
				nr_sects, (u64 *) arg);
	case BLKRRPART:
		if (!capable(CAP_SYS_ADMIN))
			return -EACCES;

		return xsa_revalidate(inode->i_rdev, 1);

	case HDIO_GETGEO:
		{
			struct hd_geometry *loc, g;
			loc = (struct hd_geometry *) arg;
			if (!loc)
				return -EINVAL;
			g.heads = heads;
			g.sectors = sectors;
			g.cylinders = cylinders;
			g.start = xsa_hd[MINOR(inode->i_rdev)].start_sect;
			return copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0;
		}
	default:
		/* Let the block layer handle all the others. */
		return blk_ioctl(inode->i_rdev, cmd, arg);
	}
}

static struct block_device_operations xsa_fops = {
	open:xsysace_open,
	release:xsysace_release,
	ioctl:xsysace_ioctl,
#ifdef XSA_REMOVABLE
	check_media_change:xsysace_check_change,
	revalidate:xsysace_revalidate
#endif
};

static struct gendisk xsa_gendisk = {	/* Generic Hard Disk */
	major_name:MAJOR_NAME,
	minor_shift:PARTN_BITS,
	max_p:NR_HD << PARTN_BITS,
	part:xsa_hd,
	sizes:xsa_sizes,
	fops:&xsa_fops
};

#define XSA_IRQ (31 - XPAR_INTC_0_SYSACE_0_VEC_ID)

static void
cleanup(void)
{
	XSysAce_Config *cfg;
	int i;

	/* Make sure everything is flushed. */
	for (i = 0; i < (NR_HD << PARTN_BITS); i++)
		fsync_dev(MKDEV(xsa_major, i));

	proc_cleanup();

	if (registered) {
		blk_cleanup_queue(BLK_DEFAULT_QUEUE(xsa_major));
		del_gendisk(&xsa_gendisk);
		if (devfs_unregister_blkdev(xsa_major, DEVICE_NAME) != 0) {
			printk(KERN_ERR "%s: unable to release major %d\n",
			       DEVICE_NAME, xsa_major);
		}
	}

	/* Tidy up a little. */
	read_ahead[xsa_major] = 0;
	blk_size[xsa_major] = NULL;
	blksize_size[xsa_major] = NULL;
	hardsect_size[xsa_major] = NULL;
	max_sectors[xsa_major] = NULL;

	if (xsa_task) {
		task_shutdown = 1;
		send_sig(SIGKILL, xsa_task, 1);
		wait_for_completion(&task_sync);
	}

	if (reqirq) {
		XSysAce_DisableInterrupt(&SysAce);
		disable_irq(XSA_IRQ);
		free_irq(XSA_IRQ, NULL);
	}

	cfg = XSysAce_GetConfig(0);
	iounmap((void *) cfg->BaseAddress);
	cfg->BaseAddress = save_BaseAddress;

#ifdef CONFIG_VIRTEX_II_PRO
	if (old_restart)
		ppc_md.restart = old_restart;
#endif
}

static int __init
xsysace_init(void)
{
	static const unsigned long remap_size
	    = XPAR_SYSACE_0_HIGHADDR - XPAR_SYSACE_0_BASEADDR + 1;
	XSysAce_Config *cfg;
	XSysAce_CFParameters ident;
	XStatus stat;
	long size;
	int i;

	/* Find the config for our device. */
	cfg = XSysAce_GetConfig(0);
	if (!cfg)
		return -ENODEV;

	/* Change the addresses to be virtual; save the old ones to restore. */
	save_BaseAddress = cfg->BaseAddress;
	cfg->BaseAddress = (u32) ioremap(save_BaseAddress, remap_size);

	/* Tell the Xilinx code to bring this interface up. */
	if (XSysAce_Initialize(&SysAce, cfg->DeviceId) != XST_SUCCESS) {
		printk(KERN_ERR "%s: Could not initialize device.\n",
		       DEVICE_NAME);
		cleanup();
		return -ENODEV;
	}

	if (xsa_use_interrupts) {
		i = request_irq(XSA_IRQ, xsysace_interrupt, 0, DEVICE_NAME, NULL);
		if (i) {
			printk(KERN_ERR "%s: Could not allocate interrupt %d.\n",
				DEVICE_NAME, XSA_IRQ);
			cleanup();
			return i;
		}
		reqirq = 1;
	}

	XSysAce_SetEventHandler(&SysAce, EventHandler, (void *) NULL);

	if (xsa_use_interrupts) {
		XSysAce_EnableInterrupt(&SysAce);
	} else {
		XSysAce_DisableInterrupt(&SysAce);
	}

	/* Time to identify the drive. */
	while (XSysAce_Lock(&SysAce, 0) == XST_DEVICE_BUSY)
		xsa_short_delay();
	while ((stat = XSysAce_IdentifyCF(&SysAce, &ident)) == XST_DEVICE_BUSY)
		xsa_short_delay();
	XSysAce_Unlock(&SysAce);
	if (stat != XST_SUCCESS) {
		printk(KERN_ERR "%s: Could not send identify command.\n",
		       DEVICE_NAME);
		cleanup();
		return -ENODEV;
	}

	/* Fill in what we learned. */
	heads = ident.NumHeads;
	sectors = ident.NumSectorsPerTrack;
	cylinders = ident.NumCylinders;
	size = (long) cylinders * (long) heads * (long) sectors;

	/* Start up our task. */
	init_completion(&task_sync);
	if ((i = kernel_thread(xsa_thread, 0, 0)) < 0) {
		cleanup();
		return i;
	}
	wait_for_completion(&task_sync);

	i = devfs_register_blkdev(xsa_major, DEVICE_NAME, &xsa_fops);
	if (i < 0) {
		printk(KERN_ERR "%s: Unable to register device\n", DEVICE_NAME);
		cleanup();
		return i;
	}
	if (xsa_major == 0)
		xsa_major = i;
	registered = 1;
	xsa_gendisk.major = xsa_major;

	blk_init_queue(BLK_DEFAULT_QUEUE(xsa_major), xsysace_do_request);

	read_ahead[xsa_major] = 8;	/* 8 sector (4kB) read-ahead */
	add_gendisk(&xsa_gendisk);

	/* Start with zero-sized partitions, and correctly sized unit */
	memset(xsa_sizes, 0, sizeof(xsa_sizes));
	xsa_sizes[0] = size / 2;	/* convert sectors to kilobytes */
	blk_size[xsa_major] = xsa_sizes;
	memset(xsa_hd, 0, sizeof(xsa_hd));
	xsa_hd[0].nr_sects = size;
	for (i = 0; i < (NR_HD << PARTN_BITS); i++) {
		xsa_blocksizes[i] = 1024;
		xsa_hardsectsizes[i] = 512;
		/* XSysAce_Sector{Read,Write} will allow up to 256 sectors.
		 *
		 * HOWEVER, the driver code will assert on an absolute sector
		 * count > 255 because to the driver, 0 means 256 sectors.
		 * Rather than fix this bug at a lower level by masking the
		 * sector transfer count with 0xff, I chose to simply limit
		 * the maximum number of sectors transferred to < 0xff - KJO
		 */
		xsa_maxsect[i] = 250;
	}
	blksize_size[xsa_major] = xsa_blocksizes;
	hardsect_size[xsa_major] = xsa_hardsectsizes;
	max_sectors[xsa_major] = xsa_maxsect;

	xsa_gendisk.nr_real = NR_HD;

	register_disk(&xsa_gendisk, MKDEV(xsa_major, 0),
		      NR_HD << PARTN_BITS, &xsa_fops, size);

	if (xsa_use_interrupts) {
		printk(KERN_INFO
			"%s at 0x%08X mapped to 0x%08X, irq=%d, %ldKB CF card\n",
			DEVICE_NAME, save_BaseAddress, cfg->BaseAddress, XSA_IRQ,
			size / 2);
	} else {
		printk(KERN_INFO
			"%s at 0x%08X mapped to 0x%08X, polled I/O, %ldKB CF card\n",
			DEVICE_NAME, save_BaseAddress, cfg->BaseAddress, size / 2);
	}

#ifdef CONFIG_VIRTEX_II_PRO
	/* Hook our reset function into system's restart code. */
	old_restart = ppc_md.restart;
	ppc_md.restart = xsysace_restart;
#endif

	if (proc_init())
		printk(KERN_WARNING "%s: Could not register /proc interface.\n",
		       DEVICE_NAME);

	return 0;
}

static void __exit
xsysace_exit(void)
{
	cleanup();
}

EXPORT_NO_SYMBOLS;

module_init(xsysace_init);
module_exit(xsysace_exit);

^ permalink raw reply

* Re: Linux hanging on Xilinx SystemACE
From: Jeff Angielski @ 2006-08-16 22:07 UTC (permalink / raw)
  To: Clint Thomas; +Cc: linuxppc-embedded
In-Reply-To: <3C02138692C13C4BB675FE7EA240952918DBED@bluefin.Soneticom.local>

On Wed, 2006-08-16 at 17:06 -0400, Clint Thomas wrote:

> Using the powerpc development tree of Linux 2.4, I am trying to boot
> my system from CompactFlash using Xilinx SystemACE. My compact flash
> card has two partitions, a 16MB FAT16 that holds the combination FPGA
> image / Linux Kernel ELF file, and an Ext2 partition that holds the
> root file system. The system starts the boot process, uncompresses the
> Linux kernel and begins loading drivers. Part way into this process,
> it conducts a partition check of the drive being reported to it by
> SystemACE, however, it hangs at that point. No kernel panic, no error
> message, it simply hangs. Here is the output at that point...
> 
> Partition check:
>  xsysacea:
>  
> what I am trying to find out is if this problem has been seen/fixed in
> the past? or did I format the CF card incorrectly?

Can u-boot see the partition formatted with ext2? 

Can you mount an NFS root filesystem and access the card normally?  Or
is it just when you use it as your rootfs?

How did you create you partitions and format the CF card?

And like somebody else mentioned, if you are really going to use this
for an embedded system, you are going to want to rethink your
partitioning scheme.

Maybe something like:

p1 fat12 - kernel and binary image
p2 ext2 - read only rootfs
p3 ext3 - non volatile, slow rate data rootfs
p4 tmpfs - volatile, high rate data rootfs


Jeff Angielski
The PTR Group

^ permalink raw reply

* Re: [PATCH 1/2]: powerpc/cell spidernet bottom half
From: Arnd Bergmann @ 2006-08-16 22:16 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: akpm, jeff, netdev, jklewis, linux-kernel, Jens.Osterkamp,
	David Miller
In-Reply-To: <20060816.143203.11626235.davem@davemloft.net>

Am Wednesday 16 August 2006 23:32 schrieb David Miller:
> Can spidernet be told these kinds of parameters? =A0"N packets or
> X usecs"?

It can not do exactly this but probably we can get close to it by

1.) Setting a one-time interrupt to fire x*10=B5s after putting a
   packet into the TX queue.

and

2.a) Enabling end of TX queue interrupts whenever more than y frames
     have been queued for TX.

or

2.b) Marking frame number y in the TX to fire an interrupt when it
     has been transmitted, and move the mark whenever we clean up
     TX descriptors.

or

2.c) Marking frame number y to generate an interrupt, but counting
     y from the end of the queue, and update the mark whenever we
     add frames to the queue tail.

I'm not sure which version of 2. would give us the best approximation.

	Arnd <><

^ permalink raw reply

* Re: [PATCH 1/2]: powerpc/cell spidernet bottom half
From: David Miller @ 2006-08-16 22:29 UTC (permalink / raw)
  To: arnd
  Cc: akpm, jeff, netdev, jklewis, linux-kernel, linuxppc-dev,
	Jens.Osterkamp
In-Reply-To: <200608170016.47072.arnd@arndb.de>

From: Arnd Bergmann <arnd@arndb.de>
Date: Thu, 17 Aug 2006 00:16:46 +0200

> Am Wednesday 16 August 2006 23:32 schrieb David Miller:
> > Can spidernet be told these kinds of parameters? =A0"N packets or
> > X usecs"?
> =

> It can not do exactly this but probably we can get close to it by

Oh, you can only control TX packet counts using bits in the TX ring
entries :(

Tigon3 can even be told to use different interrupt mitigation
parameters when the cpu is actively servicing an interrupt for
the chip.

Didn't you say spidernet's facilities were sophisticated? :)
This Tigon3 stuff is like 5+ year old technology.

^ permalink raw reply

* Re: [PATCH 1/2]: powerpc/cell spidernet bottom half
From: Arnd Bergmann @ 2006-08-16 22:47 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: akpm, jeff, netdev, jklewis, linux-kernel, Jens.Osterkamp,
	David Miller
In-Reply-To: <20060816.152919.88472383.davem@davemloft.net>

Am Thursday 17 August 2006 00:29 schrieb David Miller:
> Didn't you say spidernet's facilities were sophisticated? :)
> This Tigon3 stuff is like 5+ year old technology.

I was rather overwhelmed by the 34 different interrupts that
the chip can create, that does not mean they chose the right
events for generating them.
Interestingly, spidernet has five different counters you can
set up to generate interrupts after a number of received frames,
but none for transmit...

	Arnd <><

^ permalink raw reply

* Re: [PATCH 1/2]: powerpc/cell spidernet bottom half
From: Linas Vepstas @ 2006-08-16 22:55 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: akpm, jeff, netdev, jklewis, linux-kernel, linuxppc-dev,
	Jens.Osterkamp, David Miller
In-Reply-To: <200608162324.47235.arnd@arndb.de>

On Wed, Aug 16, 2006 at 11:24:46PM +0200, Arnd Bergmann wrote:
> 
> it only
> seems to be hard to make it go fast using any of them. 

Last round of measurements seemed linear for packet sizes between
60 and 600 bytes, suggesting that the hardware can handle a 
maximum of 120K descriptors/second, independent of packet size.
I don't know why this is.

> That may
> be the fault of strange locking rules 

My fault; a few months ago, we were in panic mode trying to get
the thing functioning reliably, and I put locks around anything
and everything.  This last patch removes those locks, and protects
only a few pointers (the incrementing of the head and the tail 
pointers, and the location ofthe low watermark) that actually 
needed protection. They need protection because the code can 
get called in various different ways.

> Cleaning up the TX queue only from ->poll() like all the others

I'll try this ... 

> sounds like the right approach to simplify the code.

Its not a big a driver. 'wc' says its 2.3 loc, which 
is 1/3 or 1/5 the size of tg3.c or the e1000*c files.

--linas

^ permalink raw reply

* Re: [PATCH 1/2]: powerpc/cell spidernet bottom half
From: Arnd Bergmann @ 2006-08-16 23:03 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: akpm, jeff, netdev, jklewis, linux-kernel, Jens.Osterkamp,
	David Miller
In-Reply-To: <20060816225558.GM20551@austin.ibm.com>

Am Thursday 17 August 2006 00:55 schrieb Linas Vepstas:
> > it only
> > seems to be hard to make it go fast using any of them.
>
> Last round of measurements seemed linear for packet sizes between
> 60 and 600 bytes, suggesting that the hardware can handle a
> maximum of 120K descriptors/second, independent of packet size.
> I don't know why this is.

Could well be related to latencies when going to the remote
node for descriptor DMAs. Have you tried if the hch's NUMA
patch or using numactl makes a difference here?

> > sounds like the right approach to simplify the code.
>
> Its not a big a driver. 'wc' says its 2.3 loc, which
> is 1/3 or 1/5 the size of tg3.c or the e1000*c files.

Right, I was thinking of removing a lock or another, not
throwing out half of the driver ;-)

	Arnd <><

^ permalink raw reply

* Re: SMP in 32-bit arch/powerpc
From: Benjamin Herrenschmidt @ 2006-08-16 23:12 UTC (permalink / raw)
  To: Jon Loeliger; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <E1G8HvV-0007o7-0C@jdl.com>

On Wed, 2006-08-02 at 09:42 -0500, Jon Loeliger wrote:
> So, like, the other day Adrian Cox mumbled:
> > Is anybody else having problems with 32-bit SMP support in arch/powerpc?
> > I'm using 2.6.17 as my current base, because I've not yet merged the
> > latest mpic changes.
> > 
> > I'm currently bringing up a dual-7448 board, and when I build the kernel
> > with CONFIG_SMP, the bootmem allocator corrupts the device tree. The
> > strange thing is, this still happens when I don't start the second CPU.
> > Kernels built without CONFIG_SMP run flawlessly on the same hardware.
> 
> As a point of reference, the 32-bit 8641 HPCN seems to be working fine
> with both CONFIG_SMP and the device tree mechanism in place.  It was working
> both before and after the IRQ changes.
> 
> Can you nail down any more specifics on how it is failing or where
> the corruption happens?

For completeness, there is a known bug with 32 bits and SMP regarding
icache coherency.... If you have random SIGILL/SEGV under load, that's
probably what you are hitting. The problem is due to the way we do the
coherency and isn't trivial to fix unfortunately, though it's also
fairly rare.

Ben.

^ permalink raw reply

* Re: [PATCH] Convert to mac-address for ethernet MAC address data.
From: Benjamin Herrenschmidt @ 2006-08-16 23:15 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linuxppc-dev@ozlabs.org
In-Reply-To: <0D9BEF4A-F8A5-42C5-9962-8C88322C9F50@kernel.crashing.org>

On Thu, 2006-08-03 at 16:49 -0500, Kumar Gala wrote:
> On Aug 3, 2006, at 4:25 PM, Jon Loeliger wrote:
> 
> > onvert to mac-address for ethernet MAC address data.
> >
> > Also accept "local-mac-address".  However the old "address"
> > is now obsolete, but accepted for backwards compatibility.
> > It should be removed after all device trees have been
> > converted to use "mac-address".

Why not stick to local-mac-address as this is the OF standard ?

Cheers,
Ben.

^ permalink raw reply

* Re: [PATCH 1/2]: powerpc/cell spidernet bottom half
From: Rick Jones @ 2006-08-16 23:08 UTC (permalink / raw)
  To: Linas Vepstas
  Cc: akpm, Arnd Bergmann, jeff, netdev, jklewis, linux-kernel,
	linuxppc-dev, Jens.Osterkamp, David Miller
In-Reply-To: <20060816225558.GM20551@austin.ibm.com>

Linas Vepstas wrote:
> On Wed, Aug 16, 2006 at 11:24:46PM +0200, Arnd Bergmann wrote:
> 
>>it only
>>seems to be hard to make it go fast using any of them. 
> 
> 
> Last round of measurements seemed linear for packet sizes between
> 60 and 600 bytes, suggesting that the hardware can handle a 
> maximum of 120K descriptors/second, independent of packet size.
> I don't know why this is.

DMA overhead perhaps?  If it takes so many micro/nanoseconds to get a 
DMA going....  That used to be a reason the Tigon2 had such low PPS 
rates and issues with multiple buffer packets and a 1500 byte MTU - it 
had rather high DMA setup latency, and then if you put it into a system 
with highish DMA read/write latency... well that didn't make it any 
better :)

rick jones

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox