LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 2/2] celleb: split machine definition
From: Arnd Bergmann @ 2007-12-13 12:10 UTC (permalink / raw)
  To: Ishizaki Kou; +Cc: linuxppc-dev, paulus
In-Reply-To: <20071213.191314.-1350525689.kouish@swc.toshiba.co.jp>

On Thursday 13 December 2007, Ishizaki Kou wrote:
> This patch splits machine definition for celleb into two definitoins,
> one is for celleb_beat, and another is for celleb_native. Though this
> patch looks complex because of sorting some functions, there are no
> more semantic changes than that for the splitting.

Looks good, thanks!

> Signed-off-by: Kou Ishizaki <Kou.Ishizaki@toshiba.co.jp>

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* [PATCH 2/6] PS3: gelic: Add endianness macros
From: Masakazu Mokuno @ 2007-12-13 12:07 UTC (permalink / raw)
  To: netdev; +Cc: Linux/PPC Development
In-Reply-To: <20071213181146.BF69.MOKUNO@sm.sony.co.jp>

PS3: gelic: Add endianness macros

Mark the members of the structure for DMA descriptor proper endian
and use appropriate accessor macros.
As gelic driver works only on PS3, all these macros will be
expanded null.

Signed-off-by: Masakazu Mokuno <mokuno@sm.sony.co.jp>
---
 drivers/net/ps3_gelic_net.c |   70 ++++++++++++++++++++++++--------------------
 drivers/net/ps3_gelic_net.h |   16 +++++-----
 2 files changed, 47 insertions(+), 39 deletions(-)

--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -98,7 +98,7 @@ gelic_net_get_descr_status(struct gelic_
 {
 	u32 cmd_status;
 
-	cmd_status = descr->dmac_cmd_status;
+	cmd_status = be32_to_cpu(descr->dmac_cmd_status);
 	cmd_status >>= GELIC_NET_DESCR_IND_PROC_SHIFT;
 	return cmd_status;
 }
@@ -117,13 +117,13 @@ static void gelic_net_set_descr_status(s
 	u32 cmd_status;
 
 	/* read the status */
-	cmd_status = descr->dmac_cmd_status;
+	cmd_status = be32_to_cpu(descr->dmac_cmd_status);
 	/* clean the upper 4 bits */
 	cmd_status &= GELIC_NET_DESCR_IND_PROC_MASKO;
 	/* add the status to it */
 	cmd_status |= ((u32)status) << GELIC_NET_DESCR_IND_PROC_SHIFT;
 	/* and write it back */
-	descr->dmac_cmd_status = cmd_status;
+	descr->dmac_cmd_status = cpu_to_be32(cmd_status);
 	/*
 	 * dma_cmd_status field is used to indicate whether the descriptor
 	 * is valid or not.
@@ -193,7 +193,7 @@ static int gelic_net_init_chain(struct g
 	/* chain bus addr of hw descriptor */
 	descr = start_descr;
 	for (i = 0; i < no; i++, descr++) {
-		descr->next_descr_addr = descr->next->bus_addr;
+		descr->next_descr_addr = cpu_to_be32(descr->next->bus_addr);
 	}
 
 	chain->head = start_descr;
@@ -245,7 +245,7 @@ static int gelic_net_prepare_rx_descr(st
 			 "%s:allocate skb failed !!\n", __func__);
 		return -ENOMEM;
 	}
-	descr->buf_size = bufsize;
+	descr->buf_size = cpu_to_be32(bufsize);
 	descr->dmac_cmd_status = 0;
 	descr->result_size = 0;
 	descr->valid_size = 0;
@@ -256,9 +256,10 @@ static int gelic_net_prepare_rx_descr(st
 	if (offset)
 		skb_reserve(descr->skb, GELIC_NET_RXBUF_ALIGN - offset);
 	/* io-mmu-map the skb */
-	descr->buf_addr = dma_map_single(ctodev(card), descr->skb->data,
-					 GELIC_NET_MAX_MTU,
-					 DMA_FROM_DEVICE);
+	descr->buf_addr = cpu_to_be32(dma_map_single(ctodev(card),
+						     descr->skb->data,
+						     GELIC_NET_MAX_MTU,
+						     DMA_FROM_DEVICE));
 	if (!descr->buf_addr) {
 		dev_kfree_skb_any(descr->skb);
 		descr->skb = NULL;
@@ -284,7 +285,7 @@ static void gelic_net_release_rx_chain(s
 	do {
 		if (descr->skb) {
 			dma_unmap_single(ctodev(card),
-					 descr->buf_addr,
+					 be32_to_cpu(descr->buf_addr),
 					 descr->skb->len,
 					 DMA_FROM_DEVICE);
 			descr->buf_addr = 0;
@@ -353,10 +354,11 @@ static void gelic_net_release_tx_descr(s
 {
 	struct sk_buff *skb = descr->skb;
 
-	BUG_ON(!(descr->data_status & (1 << GELIC_NET_TXDESC_TAIL)));
+	BUG_ON(!(be32_to_cpu(descr->data_status) &
+		 (1 << GELIC_NET_TXDESC_TAIL)));
 
-	dma_unmap_single(ctodev(card), descr->buf_addr, skb->len,
-			 DMA_TO_DEVICE);
+	dma_unmap_single(ctodev(card),
+			 be32_to_cpu(descr->buf_addr), skb->len, DMA_TO_DEVICE);
 	dev_kfree_skb_any(skb);
 
 	descr->buf_addr = 0;
@@ -610,28 +612,29 @@ static void gelic_net_set_txdescr_cmdsta
 					  struct sk_buff *skb)
 {
 	if (skb->ip_summed != CHECKSUM_PARTIAL)
-		descr->dmac_cmd_status = GELIC_NET_DMAC_CMDSTAT_NOCS |
-			GELIC_NET_DMAC_CMDSTAT_END_FRAME;
+		descr->dmac_cmd_status =
+			cpu_to_be32(GELIC_NET_DMAC_CMDSTAT_NOCS |
+				    GELIC_NET_DMAC_CMDSTAT_END_FRAME);
 	else {
 		/* is packet ip?
 		 * if yes: tcp? udp? */
 		if (skb->protocol == htons(ETH_P_IP)) {
 			if (ip_hdr(skb)->protocol == IPPROTO_TCP)
 				descr->dmac_cmd_status =
-					GELIC_NET_DMAC_CMDSTAT_TCPCS |
-					GELIC_NET_DMAC_CMDSTAT_END_FRAME;
+				cpu_to_be32(GELIC_NET_DMAC_CMDSTAT_TCPCS |
+					    GELIC_NET_DMAC_CMDSTAT_END_FRAME);
 
 			else if (ip_hdr(skb)->protocol == IPPROTO_UDP)
 				descr->dmac_cmd_status =
-					GELIC_NET_DMAC_CMDSTAT_UDPCS |
-					GELIC_NET_DMAC_CMDSTAT_END_FRAME;
+				cpu_to_be32(GELIC_NET_DMAC_CMDSTAT_UDPCS |
+					    GELIC_NET_DMAC_CMDSTAT_END_FRAME);
 			else	/*
 				 * the stack should checksum non-tcp and non-udp
 				 * packets on his own: NETIF_F_IP_CSUM
 				 */
 				descr->dmac_cmd_status =
-					GELIC_NET_DMAC_CMDSTAT_NOCS |
-					GELIC_NET_DMAC_CMDSTAT_END_FRAME;
+				cpu_to_be32(GELIC_NET_DMAC_CMDSTAT_NOCS |
+					    GELIC_NET_DMAC_CMDSTAT_END_FRAME);
 		}
 	}
 }
@@ -694,8 +697,8 @@ static int gelic_net_prepare_tx_descr_v(
 		return -ENOMEM;
 	}
 
-	descr->buf_addr = buf;
-	descr->buf_size = skb->len;
+	descr->buf_addr = cpu_to_be32(buf);
+	descr->buf_size = cpu_to_be32(skb->len);
 	descr->skb = skb;
 	descr->data_status = 0;
 	descr->next_descr_addr = 0; /* terminate hw descr */
@@ -774,7 +777,7 @@ static int gelic_net_xmit(struct sk_buff
 	 * link this prepared descriptor to previous one
 	 * to achieve high performance
 	 */
-	descr->prev->next_descr_addr = descr->bus_addr;
+	descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr);
 	/*
 	 * as hardware descriptor is modified in the above lines,
 	 * ensure that the hardware sees it
@@ -814,19 +817,23 @@ static void gelic_net_pass_skb_up(struct
 	struct net_device *netdev;
 	u32 data_status, data_error;
 
-	data_status = descr->data_status;
-	data_error = descr->data_error;
+	data_status = be32_to_cpu(descr->data_status);
+	data_error = be32_to_cpu(descr->data_error);
 	netdev = card->netdev;
 	/* unmap skb buffer */
 	skb = descr->skb;
-	dma_unmap_single(ctodev(card), descr->buf_addr, GELIC_NET_MAX_MTU,
+	dma_unmap_single(ctodev(card),
+			 be32_to_cpu(descr->buf_addr), GELIC_NET_MAX_MTU,
 			 DMA_FROM_DEVICE);
 
-	skb_put(skb, descr->valid_size? descr->valid_size : descr->result_size);
+	skb_put(skb, descr->valid_size ?
+		be32_to_cpu(descr->valid_size) :
+		be32_to_cpu(descr->result_size));
 	if (!descr->valid_size)
 		dev_info(ctodev(card), "buffer full %x %x %x\n",
-			 descr->result_size, descr->buf_size,
-			 descr->dmac_cmd_status);
+			 be32_to_cpu(descr->result_size),
+			 be32_to_cpu(descr->buf_size),
+			 be32_to_cpu(descr->dmac_cmd_status));
 
 	descr->skb = NULL;
 	/*
@@ -873,7 +880,8 @@ static int gelic_net_decode_one_descr(st
 	status = gelic_net_get_descr_status(descr);
 	/* is this descriptor terminated with next_descr == NULL? */
 	dmac_chain_ended =
-		descr->dmac_cmd_status & GELIC_NET_DMAC_CMDSTAT_RXDCEIS;
+		be32_to_cpu(descr->dmac_cmd_status) &
+		GELIC_NET_DMAC_CMDSTAT_RXDCEIS;
 
 	if (status == GELIC_NET_DESCR_CARDOWNED)
 		return 0;
@@ -940,7 +948,7 @@ refill:
 	/*
 	 * Set this descriptor the end of the chain.
 	 */
-	descr->prev->next_descr_addr = descr->bus_addr;
+	descr->prev->next_descr_addr = cpu_to_be32(descr->bus_addr);
 
 	/*
 	 * If dmac chain was met, DMAC stopped.
--- a/drivers/net/ps3_gelic_net.h
+++ b/drivers/net/ps3_gelic_net.h
@@ -169,14 +169,14 @@ enum gelic_net_descr_status {
 #define GELIC_NET_DESCR_SIZE	(32)
 struct gelic_net_descr {
 	/* as defined by the hardware */
-	u32 buf_addr;
-	u32 buf_size;
-	u32 next_descr_addr;
-	u32 dmac_cmd_status;
-	u32 result_size;
-	u32 valid_size;	/* all zeroes for tx */
-	u32 data_status;
-	u32 data_error;	/* all zeroes for tx */
+	__be32 buf_addr;
+	__be32 buf_size;
+	__be32 next_descr_addr;
+	__be32 dmac_cmd_status;
+	__be32 result_size;
+	__be32 valid_size;	/* all zeroes for tx */
+	__be32 data_status;
+	__be32 data_error;	/* all zeroes for tx */
 
 	/* used in the driver */
 	struct sk_buff *skb;

^ permalink raw reply

* Re: [PATCH 1/2] cleanup calling mmio_nvram_init
From: Arnd Bergmann @ 2007-12-13 12:07 UTC (permalink / raw)
  To: Ishizaki Kou; +Cc: linuxppc-dev, paulus
In-Reply-To: <20071213.191136.-1300517100.kouish@swc.toshiba.co.jp>

On Thursday 13 December 2007, Ishizaki Kou wrote:
> This patch adds conditional initialization for mmio_nvram_init().

Thanks!

> Signed-off-by: Kou Ishizaki <Kou.Ishizaki@toshiba.co.jp>

Acked-by: Arnd Bergmann <arnd@arndb.de>

^ permalink raw reply

* [PATCH 1/6] PS3: gelic: Fix the wrong dev_id passed
From: Masakazu Mokuno @ 2007-12-13 12:05 UTC (permalink / raw)
  To: netdev; +Cc: Linux/PPC Development
In-Reply-To: <20071213181146.BF69.MOKUNO@sm.sony.co.jp>

PS3: gelic: Fix the wrong dev_id passed

The device id for lv1_net_set_interrupt_status_indicator() would be wrong.
This path would be invoked only in the case of the initialization failure.

Signed-off-by: Masakazu Mokuno <mokuno@sm.sony.co.jp>
---
 drivers/net/ps3_gelic_net.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- a/drivers/net/ps3_gelic_net.c
+++ b/drivers/net/ps3_gelic_net.c
@@ -1512,7 +1512,7 @@ static int ps3_gelic_driver_probe (struc
 
 fail_setup_netdev:
 	lv1_net_set_interrupt_status_indicator(bus_id(card),
-					       bus_id(card),
+					       dev_id(card),
 					       0 , 0);
 fail_status_indicator:
 	ps3_dma_region_free(dev->d_region);

^ permalink raw reply

* Re: apm_emulation regression
From: Johannes Berg @ 2007-12-13 11:40 UTC (permalink / raw)
  To: benh; +Cc: Rafael J. Wysocki, linuxppc-dev list, linux-pm, ralf
In-Reply-To: <1197482587.6558.145.camel@johannes.berg>

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


> > That basically means X will break. That's why X broke on the latest
> > ubuntu until I whacked some new scripts in them to force console
> > switching, among other things. Possibly other apps that relied
> > on /dev/apm_bios to be notified of system suspend/resume broke as well.
> 
> Ah. I guess I never noticed because I had the scripts to do console
> switching all along.

Actually, it just occurred to me that the *kernel* does a console switch
when we use /sys/power/state, so maybe that is why I never had a problem
rather than userspace doing a console switch (which it only started
doing very recently)

johannes

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]

^ permalink raw reply

* Re: [RFC] ehea: kdump support using new shutdown hook
From: Subrata Modak @ 2007-12-13 11:36 UTC (permalink / raw)
  To: Thomas Klein
  Cc: ltp-list, Michael Neuling, Jan-Bernd Themann, netdev, linux-ppc,
	Christoph Raisch, Paul Mackerras, Marcus Eder, Stefan Roscher
In-Reply-To: <200712121753.43543.osstklei@de.ibm.com>

Do you think we can improve upon our own LTP-KDUMP test cases housed
here:
http://ltp.cvs.sourceforge.net/ltp/ltp/testcases/kdump/,

because of your changes below:

--Subrata

On Wed, 2007-12-12 at 17:53 +0100, Thomas Klein wrote:
> This patch adds kdump support using the new PPC crash shutdown hook to the
> ehea driver. The driver now keeps a list of firmware handles which have to
> be freed in case of a crash. The crash handler does the minimum required: it
> frees the firmware resource handles plus broadcast/multicast registrations.
> 
> Please comment.
> 
> Shutdown hook patches:
>   http://ozlabs.org/pipermail/linuxppc-dev/2007-December/048058.html
>   http://ozlabs.org/pipermail/linuxppc-dev/2007-December/048059.html
> 
> 
> Signed-off-by: Thomas Klein <tklein@de.ibm.com>
> 
> ---
> diff -Nurp -X dontdiff linux-2.6.24-rc5/drivers/net/ehea/ehea.h patched_kernel/drivers/net/ehea/ehea.h
> --- linux-2.6.24-rc5/drivers/net/ehea/ehea.h	2007-12-11 04:48:43.000000000 +0100
> +++ patched_kernel/drivers/net/ehea/ehea.h	2007-12-12 17:30:53.000000000 +0100
> @@ -40,7 +40,7 @@
>  #include <asm/io.h>
> 
>  #define DRV_NAME	"ehea"
> -#define DRV_VERSION	"EHEA_0083"
> +#define DRV_VERSION	"EHEA_0084"
> 
>  /* eHEA capability flags */
>  #define DLPAR_PORT_ADD_REM 1
> @@ -386,6 +386,7 @@ struct ehea_port_res {
> 
> 
>  #define EHEA_MAX_PORTS 16
> +#define EHEA_MAX_RES_HANDLES (100 * EHEA_MAX_PORTS + 10)
>  struct ehea_adapter {
>  	u64 handle;
>  	struct of_device *ofdev;
> @@ -397,6 +398,7 @@ struct ehea_adapter {
>  	u64 max_mc_mac;            /* max number of multicast mac addresses */
>  	int active_ports;
>  	struct list_head list;
> +	u64 res_handles[EHEA_MAX_RES_HANDLES];
>  };
> 
> 
> diff -Nurp -X dontdiff linux-2.6.24-rc5/drivers/net/ehea/ehea_main.c patched_kernel/drivers/net/ehea/ehea_main.c
> --- linux-2.6.24-rc5/drivers/net/ehea/ehea_main.c	2007-12-11 04:48:43.000000000 +0100
> +++ patched_kernel/drivers/net/ehea/ehea_main.c	2007-12-12 17:30:53.000000000 +0100
> @@ -35,6 +35,7 @@
>  #include <linux/if_ether.h>
>  #include <linux/notifier.h>
>  #include <linux/reboot.h>
> +#include <asm-powerpc/kexec.h>
> 
>  #include <net/ip.h>
> 
> @@ -2256,6 +2257,33 @@ static int ehea_clean_all_portres(struct
>  	return ret;
>  }
> 
> +static void ehea_update_adapter_handles(struct ehea_adapter *adapter)
> +{
> +	int i, k;
> +	int j = 0;
> +
> +	memset(adapter->res_handles, sizeof(adapter->res_handles), 0);
> +
> +	for (k = 0; k < EHEA_MAX_PORTS; k++) {
> +		struct ehea_port *port = adapter->port[k];
> +
> +		if (!port || (port->state != EHEA_PORT_UP))
> +			continue;
> +
> +		for(i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) {
> +			struct ehea_port_res *pr = &port->port_res[i];
> +
> +			adapter->res_handles[j++] = pr->qp->fw_handle;
> +			adapter->res_handles[j++] = pr->send_cq->fw_handle;
> +			adapter->res_handles[j++] = pr->recv_cq->fw_handle;
> +			adapter->res_handles[j++] = pr->eq->fw_handle;
> +			adapter->res_handles[j++] = pr->send_mr.handle;
> +			adapter->res_handles[j++] = pr->recv_mr.handle;
> +		}
> +		adapter->res_handles[j++] = port->qp_eq->fw_handle;
> +	}
> +}
> +
>  static void ehea_remove_adapter_mr(struct ehea_adapter *adapter)
>  {
>  	if (adapter->active_ports)
> @@ -2318,6 +2346,7 @@ static int ehea_up(struct net_device *de
> 
>  	ret = 0;
>  	port->state = EHEA_PORT_UP;
> +	ehea_update_adapter_handles(port->adapter);
>  	goto out;
> 
>  out_free_irqs:
> @@ -2387,6 +2416,8 @@ static int ehea_down(struct net_device *
>  		ehea_info("Failed freeing resources for %s. ret=%i",
>  			  dev->name, ret);
> 
> +	ehea_update_adapter_handles(port->adapter);
> +
>  	return ret;
>  }
> 
> @@ -3302,6 +3333,71 @@ static int __devexit ehea_remove(struct 
>  	return 0;
>  }
> 
> +void ehea_crash_deregister(void)
> +{
> +	struct ehea_adapter *adapter;
> +	int i;
> +	u64 hret;
> +	u8 reg_type;
> +
> +	list_for_each_entry(adapter, &adapter_list, list) {
> +		for (i = 0; i < EHEA_MAX_PORTS; i++) {
> +			struct ehea_port *port = adapter->port[i];
> +			if (port->state == EHEA_PORT_UP) {
> +				struct ehea_mc_list *mc_entry = port->mc_list;
> +				struct list_head *pos;
> +				struct list_head *temp;
> +
> +				/* Undo multicast registrations */
> +				list_for_each_safe(pos, temp,
> +						   &(port->mc_list->list)) {
> +					mc_entry = list_entry(pos,
> +							    struct ehea_mc_list,
> +							    list);
> +					ehea_multicast_reg_helper(port,
> +							      mc_entry->macaddr,
> +							      H_DEREG_BCMC);
> +				}
> +
> +				/* Undo broad registration */
> +				reg_type = EHEA_BCMC_BROADCAST |
> +					   EHEA_BCMC_UNTAGGED;
> +				ehea_h_reg_dereg_bcmc(port->adapter->handle,
> +						      port->logical_port_id,
> +						      reg_type, port->mac_addr,
> +						      0, H_DEREG_BCMC);
> +
> +				reg_type = EHEA_BCMC_BROADCAST |
> +					   EHEA_BCMC_VLANID_ALL;
> +				ehea_h_reg_dereg_bcmc(port->adapter->handle,
> +						      port->logical_port_id,
> +						      reg_type, port->mac_addr,
> +						      0, H_DEREG_BCMC);
> +			}
> +		}
> +		for (i = 0; i < EHEA_MAX_RES_HANDLES; i++) {
> +			u64 handle = adapter->res_handles[i];
> +			if (handle) {
> +				hret = ehea_h_free_resource(adapter->handle,
> +							    handle,
> +							    FORCE_FREE);
> +			}
> +		}
> +
> +		if (adapter->neq) {
> +			hret = ehea_h_free_resource(adapter->handle,
> +						    adapter->neq->fw_handle,
> +						    FORCE_FREE);
> +		}
> +
> +		if (adapter->mr.handle) {
> +			hret = ehea_h_free_resource(adapter->handle,
> +						    adapter->mr.handle,
> +						    FORCE_FREE);
> +		}
> +	}
> +}
> +
>  static int ehea_reboot_notifier(struct notifier_block *nb,
>  				unsigned long action, void *unused)
>  {
> @@ -3373,6 +3469,9 @@ int __init ehea_module_init(void)
>  		goto out;
> 
>  	register_reboot_notifier(&ehea_reboot_nb);
> +	ret = crash_shutdown_register(&ehea_crash_deregister);
> +	if (ret)
> +		ehea_info("failed registering crash handler");
> 
>  	ret = ibmebus_register_driver(&ehea_driver);
>  	if (ret) {
> @@ -3386,6 +3485,7 @@ int __init ehea_module_init(void)
>  		ehea_error("failed to register capabilities attribute, ret=%d",
>  			   ret);
>  		unregister_reboot_notifier(&ehea_reboot_nb);
> +		crash_shutdown_unregister(&ehea_crash_deregister);
>  		ibmebus_unregister_driver(&ehea_driver);
>  		goto out;
>  	}
> @@ -3396,10 +3496,15 @@ out:
> 
>  static void __exit ehea_module_exit(void)
>  {
> +	int ret;
> +
>  	flush_scheduled_work();
>  	driver_remove_file(&ehea_driver.driver, &driver_attr_capabilities);
>  	ibmebus_unregister_driver(&ehea_driver);
>  	unregister_reboot_notifier(&ehea_reboot_nb);
> +	ret = crash_shutdown_unregister(&ehea_crash_deregister);
> +	if (ret)
> +		ehea_info("failed unregistering crash handler");
>  	ehea_destroy_busmap();
>  }
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/

^ permalink raw reply

* Re: cpu frequency governor regression (?)
From: Johannes Berg @ 2007-12-12 19:53 UTC (permalink / raw)
  To: Dave Jones, Tim Dijkstra
  Cc: Rafael J. Wysocki, linuxppc-dev list, linux-pm, cpufreq
In-Reply-To: <20071212173001.GA18973@redhat.com>

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

Ok, umm, sorry for bothering. This is actually a userspace problem.
Because I had it written up already below is the mail I was composing; I
was just checking whether the same would happen without the performance
module loaded, and voila, the same *did* happen which lead me to
investigate userspace. Turns out pm-utils is the cause of this problem.
Nothing but trouble with pm-utils on non-standard non-ACPI systems :/

The problem is this: pm-utils's hibernate_cpufreq() does:

savestate ${x}_governor $(cat $x/cpufreq/scaling_governor)
          ^^^^^

but thaw_cpufreq() does:

gov=$(restorestate $(echo cpu${x}_governor))
                          ^^^^^^^^

doh! Again, sorry, I really should have looked there first.

johannes

--- >% >% >% ---

> bizarre. It should default back to whatever CONFIG_CPU_FREQ_DEFAULT_* option
> was set.  (Arguably a bug in itself, as we don't track & restore them
> on resume, so if you changed from the default after booting: splat)

Ok I verified this again:

$ zgrep CPU_FREQ /proc/config.gz 
CONFIG_CPU_FREQ=y
CONFIG_CPU_FREQ_TABLE=y
CONFIG_CPU_FREQ_DEBUG=y
CONFIG_CPU_FREQ_STAT=y
# CONFIG_CPU_FREQ_STAT_DETAILS is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
CONFIG_CPU_FREQ_GOV_PERFORMANCE=m
CONFIG_CPU_FREQ_GOV_POWERSAVE=m
CONFIG_CPU_FREQ_GOV_USERSPACE=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=m
CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
CONFIG_CPU_FREQ_PMAC64=y

> Also, does /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor 
> have performance in *all* the cpus?

Yes, it does.

> Why you're getting the performance governor is puzzling though.
> Can you enable CONFIG_CPU_FREQ_DEBUG=y, and boot with cpufreq.debug=7
> and send the log from a transition across hibernate?

Ok, fresh boot with cpufreq.debug=7, so far I have "userspace" in all
scaling_governor files for the four CPUs.

Up to this point, I have the following in the log (dmesg | grep "freq"):

[    0.000000] time_init: decrementer frequency = 33.333333 MHz
[    0.000000] time_init: processor frequency   = 2500.000000 MHz
[    0.168566] Registering G5 CPU frequency driver
[    0.168583] cpufreq-core: trying to register driver powermac
[    0.168588] cpufreq-core: adding CPU 0
[    0.168597] freq-table: setting show_table for cpu 0 to c00000000054caf0
[    0.168601] freq-table: table entry 0: 2500000 kHz, 0 index
[    0.168605] freq-table: table entry 1: 1250000 kHz, 1 index
[    0.168751] cpufreq-core: CPU 1 already managed, adding link
[    0.168758] cpufreq-core: CPU 2 already managed, adding link
[    0.168766] cpufreq-core: CPU 3 already managed, adding link
[    0.168774] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[    0.168779] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[    0.168784] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[    0.168789] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[    0.168794] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[    0.168799] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[    0.168802] cpufreq-core: governor switch
[    0.168810] cpufreq-core: __cpufreq_governor for CPU 0, event 1
[    0.168823] cpufreq-core: governor: change or update limits
[    0.168827] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[    0.168837] cpufreq-core: target for CPU 0: 2500000 kHz, relation 0
[    0.168842] freq-table: request for target 2500000 kHz (relation: 0) for cpu 0
[    0.168846] freq-table: target is 0 (2500000 kHz, 0)
[    0.168849] cpufreq-core: initialization complete
[    0.168853] cpufreq-core: adding CPU 1
[    0.168856] cpufreq-core: adding CPU 2
[    0.168859] cpufreq-core: adding CPU 3
[    0.168865] cpufreq-core: driver powermac up and running
[    4.997986] cpufreq-core: updating policy for CPU 0
[    4.997992] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[    4.997998] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[    4.998003] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[    4.998009] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[    4.998013] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[    4.998029] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[    4.998032] cpufreq-core: governor: change or update limits
[    4.998036] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[    4.998048] cpufreq-core: target for CPU 0: 2500000 kHz, relation 0
[    4.998052] freq-table: request for target 2500000 kHz (relation: 0) for cpu 0
[    4.998056] freq-table: target is 0 (2500000 kHz, 0)
[    4.998061] cpufreq-core: updating policy for CPU 1
[    4.998065] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[    4.998070] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[    4.998075] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[    4.998080] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[    4.998085] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[    4.998090] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[    4.998093] cpufreq-core: governor: change or update limits
[    4.998097] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[    4.998108] cpufreq-core: target for CPU 0: 2500000 kHz, relation 0
[    4.998112] freq-table: request for target 2500000 kHz (relation: 0) for cpu 0
[    4.998116] freq-table: target is 0 (2500000 kHz, 0)
[    4.998120] cpufreq-core: updating policy for CPU 2
[    4.998125] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[    4.998130] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[    4.998135] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[    4.998140] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[    4.998145] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[    4.998149] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[    4.998153] cpufreq-core: governor: change or update limits
[    4.998157] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[    4.998167] cpufreq-core: target for CPU 0: 2500000 kHz, relation 0
[    4.998172] freq-table: request for target 2500000 kHz (relation: 0) for cpu 0
[    4.998175] freq-table: target is 0 (2500000 kHz, 0)
[    4.998180] cpufreq-core: updating policy for CPU 3
[    4.998184] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[    4.998189] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[    4.998194] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[    4.998199] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[    4.998204] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[    4.998208] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[    4.998212] cpufreq-core: governor: change or update limits
[    4.998216] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[    4.998226] cpufreq-core: target for CPU 0: 2500000 kHz, relation 0
[    4.998231] freq-table: request for target 2500000 kHz (relation: 0) for cpu 0
[    4.998235] freq-table: target is 0 (2500000 kHz, 0)
[   29.644593] userspace: cpufreq_set for cpu 0, freq 1250000 kHz
[   29.644602] cpufreq-core: target for CPU 0: 1250000 kHz, relation 0
[   29.644607] freq-table: request for target 1250000 kHz (relation: 0) for cpu 0
[   29.644660] freq-table: target is 1 (1250000 kHz, 1)
[   29.644665] cpufreq-core: notification 0 of frequency transition to 1250000 kHz
[   29.644670] userspace: saving cpu_cur_freq of cpu 0 to be 1250000 kHz
[   29.644688] cpufreq-core: notification 1 of frequency transition to 1250000 kHz
[   29.644697] userspace: saving cpu_cur_freq of cpu 0 to be 1250000 kHz
[   31.646503] userspace: cpufreq_set for cpu 0, freq 2500000 kHz
[   31.646521] cpufreq-core: target for CPU 0: 2500000 kHz, relation 0
[   37.653379] userspace: cpufreq_set for cpu 0, freq 2500000 kHz
[   47.661393] userspace: cpufreq_set for cpu 0, freq 2500000 kHz
[   47.661405] cpufreq-core: target for CPU 0: 2500000 kHz, relation 0
[   49.662323] userspace: cpufreq_set for cpu 0, freq 1250000 kHz
[   59.670718] userspace: cpufreq_set for cpu 0, freq 2500000 kHz
[   59.670730] cpufreq-core: target for CPU 0: 2500000 kHz, relation 0


Now I hibernate. Afterwards, I have "performance" in all four governor
files. The log across hibernate (a bit after above log I hibernated the
system) is (again | grep "freq"):

[  161.071430] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  161.071446] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  161.071456] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  161.071468] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  161.071479] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  161.071489] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  161.071496] cpufreq-core: governor switch
[  161.071504] cpufreq-core: __cpufreq_governor for CPU 0, event 2
[  161.087864] cpufreq-core: __cpufreq_governor for CPU 0, event 1
[  161.087882] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  161.087892] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  161.087901] freq-table: target is 0 (2500000 kHz, 0)
[  161.087910] cpufreq-core: notification 0 of frequency transition to 2500000 kHz
[  161.087929] cpufreq-core: notification 1 of frequency transition to 2500000 kHz
[  161.087934] cpufreq-core: governor: change or update limits
[  161.087938] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  161.087947] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  161.087951] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  161.087955] freq-table: target is 0 (2500000 kHz, 0)
[  161.098312] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  161.098326] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  161.098331] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  161.098338] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  161.098343] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  161.098348] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  161.098352] cpufreq-core: governor: change or update limits
[  161.098356] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  161.098503] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  161.098508] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  161.098512] freq-table: target is 0 (2500000 kHz, 0)
[  161.105644] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  161.105654] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  161.105659] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  161.105665] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  161.105670] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  161.105675] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  161.105679] cpufreq-core: governor: change or update limits
[  161.105683] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  161.105692] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  161.105697] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  161.105701] freq-table: target is 0 (2500000 kHz, 0)
[  161.114175] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  161.114185] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  161.114190] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  161.114196] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  161.114201] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  161.114206] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  161.114209] cpufreq-core: governor: change or update limits
[  161.114214] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  161.114223] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  161.114228] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  161.114232] freq-table: target is 0 (2500000 kHz, 0)
[  164.193568] cpufreq-core: unregistering CPU 1
[  164.193571] cpufreq-core: removing link
[  164.199711] cpufreq-core: unregistering CPU 2
[  164.199714] cpufreq-core: removing link
[  164.204755] cpufreq-core: unregistering CPU 3
[  164.204758] cpufreq-core: removing link
[  164.254908] cpufreq-core: suspending cpu 0
[  164.254912] cpufreq-core: suspending cpu 1
[  164.254915] cpufreq-core: suspending cpu 2
[  164.254918] cpufreq-core: suspending cpu 3
[  164.271294] cpufreq-core: resuming cpu 0
[  164.271304] cpufreq-core: resuming cpu 1
[  164.271307] cpufreq-core: resuming cpu 2
[  164.271310] cpufreq-core: resuming cpu 3
[  164.321819] cpufreq-core: handle_update for cpu 0 called
[  164.321824] cpufreq-core: updating policy for CPU 0
[  164.321829] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  164.321835] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  164.321840] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  164.321846] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  164.321851] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  164.321856] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  164.321860] cpufreq-core: governor: change or update limits
[  164.321864] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  164.321873] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  164.321878] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  164.321882] freq-table: target is 0 (2500000 kHz, 0)
[  164.349425] cpufreq-core: adding CPU 1
[  164.349432] freq-table: setting show_table for cpu 1 to c00000000054caf0
[  164.349436] freq-table: table entry 0: 2500000 kHz, 0 index
[  164.349440] freq-table: table entry 1: 1250000 kHz, 1 index
[  164.349444] cpufreq-core: CPU already managed, adding link
[  164.349457] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  164.349462] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  164.349467] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  164.349473] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  164.349478] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  164.349482] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  164.349486] cpufreq-core: governor: change or update limits
[  164.349490] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  164.349498] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  164.349503] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  164.349507] freq-table: target is 0 (2500000 kHz, 0)
[  164.376472] cpufreq-core: adding CPU 2
[  164.376477] freq-table: setting show_table for cpu 2 to c00000000054caf0
[  164.376481] freq-table: table entry 0: 2500000 kHz, 0 index
[  164.376485] freq-table: table entry 1: 1250000 kHz, 1 index
[  164.376490] cpufreq-core: CPU already managed, adding link
[  164.376501] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  164.376506] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  164.376511] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  164.376516] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  164.376521] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  164.376526] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  164.376529] cpufreq-core: governor: change or update limits
[  164.376533] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  164.376542] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  164.376546] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  164.376550] freq-table: target is 0 (2500000 kHz, 0)
[  164.403562] cpufreq-core: adding CPU 3
[  164.403568] freq-table: setting show_table for cpu 3 to c00000000054caf0
[  164.403573] freq-table: table entry 0: 2500000 kHz, 0 index
[  164.403576] freq-table: table entry 1: 1250000 kHz, 1 index
[  164.403581] cpufreq-core: CPU already managed, adding link
[  164.403592] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  164.403597] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  164.403602] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  164.403607] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  164.403612] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  164.403617] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  164.403621] cpufreq-core: governor: change or update limits
[  164.403624] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  164.403633] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  164.403637] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  164.403641] freq-table: target is 0 (2500000 kHz, 0)
[  165.337598] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  165.337608] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  165.337613] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  165.337619] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  165.337624] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  165.337629] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  165.337632] cpufreq-core: governor switch
[  165.337636] cpufreq-core: __cpufreq_governor for CPU 0, event 2
[  165.337641] cpufreq-core: __cpufreq_governor for CPU 0, event 1
[  165.337661] cpufreq-core: governor: change or update limits
[  165.337665] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  165.337676] cpufreq-core: target for CPU 0: 2500000 kHz, relation 0
[  165.337681] freq-table: request for target 2500000 kHz (relation: 0) for cpu 0
[  165.337685] freq-table: target is 0 (2500000 kHz, 0)
[  165.348578] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  165.348591] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  165.348597] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  165.348604] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  165.348609] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  165.348614] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  165.348617] cpufreq-core: governor switch
[  165.348621] cpufreq-core: __cpufreq_governor for CPU 0, event 2
[  165.358459] cpufreq-core: __cpufreq_governor for CPU 0, event 1
[  165.358468] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  165.358530] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  165.358534] freq-table: target is 0 (2500000 kHz, 0)
[  165.358538] cpufreq-core: governor: change or update limits
[  165.358541] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  165.358550] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  165.358554] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  165.358558] freq-table: target is 0 (2500000 kHz, 0)
[  165.365797] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  165.365809] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  165.365815] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  165.365873] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  165.365877] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  165.365882] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  165.365886] cpufreq-core: governor: change or update limits
[  165.365890] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  165.365898] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  165.365903] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  165.365907] freq-table: target is 0 (2500000 kHz, 0)
[  165.373083] cpufreq-core: setting new policy for CPU 0: 1250000 - 2500000 kHz
[  165.373096] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  165.373102] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  165.373160] freq-table: request for verification of policy (1250000 - 2500000 kHz) for cpu 0
[  165.373165] freq-table: verification lead to (1250000 - 2500000 kHz) for cpu 0
[  165.373169] cpufreq-core: new min and max freqs are 1250000 - 2500000 kHz
[  165.373173] cpufreq-core: governor: change or update limits
[  165.373177] cpufreq-core: __cpufreq_governor for CPU 0, event 3
[  165.373185] cpufreq-core: target for CPU 0: 2500000 kHz, relation 1
[  165.373190] freq-table: request for target 2500000 kHz (relation: 1) for cpu 0
[  165.373194] freq-table: target is 0 (2500000 kHz, 0)


I saw a "14 messages suppressed" message but I don't know if it came
from here.


[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 828 bytes --]

^ permalink raw reply

* Re: [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Benjamin Herrenschmidt @ 2007-12-13 11:12 UTC (permalink / raw)
  To: Stefan Roese; +Cc: linuxppc-dev
In-Reply-To: <200712131042.48354.sr@denx.de>


On Thu, 2007-12-13 at 10:42 +0100, Stefan Roese wrote:
> On Thursday 13 December 2007, Benjamin Herrenschmidt wrote:
> > This makes 4xx embedded platforms re-assign all PCI resources as we
> > pretty much never care about what the various firmwares have done on
> > these, it's generally not compatible with the way the kernel will map
> > the bridges.
> >
> > We still need to also enable bus renumbering on some of them, but I
> > will do that from a separate patch after I've fixed 4xx PCIe to handle
> > all bus numbers.
> 
> I just applied this series on top of Paulus's for-2.6.25 branch and I
> get the following error:
> 
> /home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilauea.c: In function 'kilauea_probe':
> /home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilauea.c:49: error: 'ppc_pci_flags' undeclared (first use in this function)
> /home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilauea.c:49: error: (Each undeclared identifier is reported only once
> /home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilauea.c:49: error: for each function it appears in.)
> /home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilauea.c:49: error: 'PPC_PCI_REASSIGN_ALL_RSRC' undeclared (first use in this function)
> make[3]: *** [arch/powerpc/platforms/40x/kilauea.o] Error 1

As discussed on IRC, that's just because you are missing the PCI
series of patches :-)

Cheers,
Ben.

^ permalink raw reply

* RE: Linux 2.6 from git.xilinx and XUPV2P
From: greenlean @ 2007-12-13 11:09 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <20071212171940.8D86B17B0067@mail230-blu.bigfish.com>


OK, now this morning (I'm working in Spain) I compiled the kernel using the
xparameters_xupv2p.h generated by edk, everything is OK, only a few
warnings. 

But as I told you yesterday I have the same problem, the xdm shell tell me
that it can't read the file, maybe it is corrupted, the error reported is
the ERROR(1053) I don't Know what it means.

Following your steps I try to verify that the elf file generated is an elf
file, I used the ppc_4xx-readelf -h zImage.elf command and it told me this
result:

$ppc_4xx-readelf -h arch/ppc/boot/images/zImage.elf
ELF Header:
  Magic:   7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, big endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           PowerPC 
  Version:                           0x1
  Entry point address:               0x400000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          1017144 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         17
  Section header string table index: 14

I'm not sure about what I supossed to do with objdump, any instruction about
what to look for,  because objdump works fine, it show me the instruction.

I'm going to search about the elf file, to ensure this is a good elf file.


Stephen Neuendorffer wrote:
> 
> The xparameters file is specific to your hardware design.
> You should change the name of the generated xparameters file to match
> xparameters_xupv2p.h 
> 
> Unfortunately, it's sort of an historical artifact that it was done this
> way...  In reality, all the different xparameters files should really
> just be one, since only one can be active at a time.
> 
> The last error sounds like you haven't actually generated an elf file?
> have you tried running objdump on it?
> 
> Steve
> 
>> -----Original Message-----
>> From: 
>> linuxppc-embedded-bounces+stephen=neuendorffer.name@ozlabs.org
>>  
>> [mailto:linuxppc-embedded-bounces+stephen=neuendorffer.name@oz
>> labs.org] On Behalf Of greenlean
>> Sent: Wednesday, December 12, 2007 9:05 AM
>> To: linuxppc-embedded@ozlabs.org
>> Subject: Re: Linux 2.6 from git.xilinx and XUPV2P
>> 
>> 
>> 
>> 
>> greenlean wrote:
>> > 
>> > Thanks both for the response, I've allready visited some of 
>> the links. 
>> > 
>> > Yes, you was right it's easear than I think, my problem was 
>> the .config
>> > file. Now, I have generated it from ml300_defconfig and 
>> after some changes
>> > it compiles, but I've two question:
>> > 
>> >  * I've chosen as platform the XUPV2P in Machine Type, 
>> instead of ML300,
>> > so the xparameters file that I'm using is the 
>> xparameters_xupv2p.h, but
>> > the xparameters file generated by the EDK is 
>> xparameters_ml300 despite I
>> > told it to use XUPV2P, so I can't overwrite it... 
>> > 
>> > Should I use the xparameters_ml300 generated by EDK or the
>> > xparameters_xupv2p included in the git kernel tree?.  I 
>> can't compile with
>> > the edk's xparameters_ml300 file because there's some 
>> definition that the
>> > compiler can't find, so I'm using the xparameters_xupv2p.
>> > 
>> >  * Second, if I compile using the xparameters_xupv2p, when 
>> I do the dow
>> > command to download the image to the board, the xmd shell tell me:
>> >            
>> >    XMD% dow zImage.elf
>> >            Failed to download ELF file
>> > 
>> >       ERROR(1053): UNABLE to Read Elf File. The Elf File 
>> Maybe Corrupted
>> >           : zImage.elf
>> > Maybe this error is due to the above asumption??. I'll post 
>> this second
>> > one on xilinx-support maybe it's realted with my system.....
>> > 
>> > 
>> > 
>> 
>> -- 
>> View this message in context: 
>> http://www.nabble.com/Linux-2.6-from-git.xilinx-and-XUPV2P-tp1
>> 4274035p14299307.html
>> Sent from the linuxppc-embedded mailing list archive at Nabble.com.
>> 
>> _______________________________________________
>> Linuxppc-embedded mailing list
>> Linuxppc-embedded@ozlabs.org
>> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>> 
>> 
> 
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
> 
> 

-- 
View this message in context: http://www.nabble.com/Linux-2.6-from-git.xilinx-and-XUPV2P-tp14274035p14313943.html
Sent from the linuxppc-embedded mailing list archive at Nabble.com.

^ permalink raw reply

* [PATCH 0/6] PS3: gelic: gelic updates for 2.6.25
From: Masakazu Mokuno @ 2007-12-13 10:38 UTC (permalink / raw)
  To: netdev; +Cc: Linux/PPC Development

	Hi,

Here is a set of updates for PS3 gelic network driver.
This patch set requires other patches which were already submitted by
Geert (http://marc.info/?l=linux-kernel&m=119626095605487).

	[1] PS3: gelic: Fix the wrong dev_id passed
	[2] PS3: gelic: Add endianness macros
	[3] PS3: gelic: Code cleanup
	[4] PS3: gelic: Remove duplicated ethtool handers
	[5] PS3: gelic: Add support for port link status
	[6] PS3: gelic: Add support for dual network interface

This is also a set of prerequisite for new wireless driver for PS3, which
I'll submit later. 

Thanks for reviewing!

-- 
Masakazu MOKUNO

^ permalink raw reply

* [PATCH 1/2] cleanup calling mmio_nvram_init
From: Ishizaki Kou @ 2007-12-13 10:11 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev, arnd

This patch adds conditional initialization for mmio_nvram_init().

Signed-off-by: Kou Ishizaki <Kou.Ishizaki@toshiba.co.jp>
---

Here is the previous discussion:
 http://ozlabs.org/pipermail/linuxppc-dev/2007-December/047435.html


Index: linux-powerpc-git/arch/powerpc/platforms/cell/setup.c
===================================================================
--- linux-powerpc-git.orig/arch/powerpc/platforms/cell/setup.c
+++ linux-powerpc-git/arch/powerpc/platforms/cell/setup.c
@@ -179,9 +179,7 @@ static void __init cell_setup_arch(void)
 	conswitchp = &dummy_con;
 #endif
 
-#ifdef CONFIG_MMIO_NVRAM
 	mmio_nvram_init();
-#endif
 }
 
 static int __init cell_probe(void)
Index: linux-powerpc-git/include/asm-powerpc/nvram.h
===================================================================
--- linux-powerpc-git.orig/include/asm-powerpc/nvram.h
+++ linux-powerpc-git/include/asm-powerpc/nvram.h
@@ -10,6 +10,8 @@
 #ifndef _ASM_POWERPC_NVRAM_H
 #define _ASM_POWERPC_NVRAM_H
 
+#include <linux/errno.h>
+
 #define NVRW_CNT 0x20
 #define NVRAM_HEADER_LEN 16 /* sizeof(struct nvram_header) */
 #define NVRAM_BLOCK_LEN 16
@@ -71,7 +73,16 @@ extern int nvram_clear_error_log(void);
 extern struct nvram_partition *nvram_find_partition(int sig, const char *name);
 
 extern int pSeries_nvram_init(void);
+
+#ifdef CONFIG_MMIO_NVRAM
 extern int mmio_nvram_init(void);
+#else
+static inline int mmio_nvram_init(void)
+{
+	return -ENODEV;
+}
+#endif
+
 #endif /* __KERNEL__ */
 
 /* PowerMac specific nvram stuffs */

^ permalink raw reply

* [PATCH 2/2] celleb: split machine definition
From: Ishizaki Kou @ 2007-12-13 10:13 UTC (permalink / raw)
  To: paulus; +Cc: linuxppc-dev, arnd

This patch splits machine definition for celleb into two definitoins,
one is for celleb_beat, and another is for celleb_native. Though this
patch looks complex because of sorting some functions, there are no
more semantic changes than that for the splitting.

Signed-off-by: Kou Ishizaki <Kou.Ishizaki@toshiba.co.jp>
---

Here is the previous discussion:
 http://ozlabs.org/pipermail/linuxppc-dev/2007-December/047436.html


Index: linux-powerpc-git/arch/powerpc/platforms/cell/iommu.c
===================================================================
--- linux-powerpc-git.orig/arch/powerpc/platforms/cell/iommu.c
+++ linux-powerpc-git/arch/powerpc/platforms/cell/iommu.c
@@ -700,8 +700,8 @@ static int __init cell_iommu_init(void)
 {
 	struct device_node *np;
 
-	if ((!machine_is(cell) && !machine_is(celleb)) ||
-	    firmware_has_feature(FW_FEATURE_LPAR))
+	if (!machine_is(cell) &&
+	    !machine_is(celleb_native))
 		return -ENODEV;
 
 	/* If IOMMU is disabled or we have little enough RAM to not need
Index: linux-powerpc-git/arch/powerpc/platforms/celleb/scc_uhc.c
===================================================================
--- linux-powerpc-git.orig/arch/powerpc/platforms/celleb/scc_uhc.c
+++ linux-powerpc-git/arch/powerpc/platforms/celleb/scc_uhc.c
@@ -47,7 +47,8 @@ static void enable_scc_uhc(struct pci_de
 	u32 val = 0;
 	int i;
 
-	if (!machine_is(celleb))
+	if (!machine_is(celleb_beat) &&
+	    !machine_is(celleb_native))
 		return;
 
 	uhc_base = ioremap(pci_resource_start(dev, 0),
Index: linux-powerpc-git/arch/powerpc/platforms/celleb/setup.c
===================================================================
--- linux-powerpc-git.orig/arch/powerpc/platforms/celleb/setup.c
+++ linux-powerpc-git/arch/powerpc/platforms/celleb/setup.c
@@ -93,30 +93,43 @@ static void celleb_progress(char *s, uns
 	printk("*** %04x : %s\n", hex, s ? s : "");
 }
 
-static void __init celleb_init_IRQ_native(void)
+static void __init celleb_setup_arch_common(void)
 {
-	iic_init_IRQ();
-	spider_init_IRQ();
+	/* init to some ~sane value until calibrate_delay() runs */
+	loops_per_jiffy = 50000000;
+
+#ifdef CONFIG_DUMMY_CONSOLE
+	conswitchp = &dummy_con;
+#endif
 }
 
-static void __init celleb_setup_arch_beat(void)
+static struct of_device_id celleb_bus_ids[] __initdata = {
+	{ .type = "scc", },
+	{ .type = "ioif", },	/* old style */
+	{},
+};
+
+static int __init celleb_publish_devices(void)
 {
-	ppc_md.restart		= beat_restart;
-	ppc_md.power_off	= beat_power_off;
-	ppc_md.halt		= beat_halt;
-	ppc_md.get_rtc_time	= beat_get_rtc_time;
-	ppc_md.set_rtc_time	= beat_set_rtc_time;
-	ppc_md.power_save	= beat_power_save;
-	ppc_md.nvram_size	= beat_nvram_get_size;
-	ppc_md.nvram_read	= beat_nvram_read;
-	ppc_md.nvram_write	= beat_nvram_write;
-	ppc_md.set_dabr		= beat_set_xdabr;
-	ppc_md.init_IRQ		= beatic_init_IRQ;
-	ppc_md.get_irq		= beatic_get_irq;
-#ifdef CONFIG_KEXEC
-	ppc_md.kexec_cpu_down	= beat_kexec_cpu_down;
-#endif
+	if (!machine_is(celleb_beat) &&
+	    !machine_is(celleb_native))
+		return -ENODEV;
+
+	/* Publish OF platform devices for southbridge IOs */
+	of_platform_bus_probe(NULL, celleb_bus_ids, NULL);
 
+	celleb_pci_workaround_init();
+
+	return 0;
+}
+device_initcall(celleb_publish_devices);
+
+
+/*
+ * functions for Celleb-Beat
+ */
+static void __init celleb_setup_arch_beat(void)
+{
 #ifdef CONFIG_SPU_BASE
 	spu_priv1_ops		= &spu_priv1_beat_ops;
 	spu_management_ops	= &spu_management_of_ops;
@@ -125,18 +138,36 @@ static void __init celleb_setup_arch_bea
 #ifdef CONFIG_SMP
 	smp_init_celleb();
 #endif
+
+	celleb_setup_arch_common();
 }
 
-static void __init celleb_setup_arch_native(void)
+static int __init celleb_probe_beat(void)
 {
-	ppc_md.restart		= rtas_restart;
-	ppc_md.power_off	= rtas_power_off;
-	ppc_md.halt		= rtas_halt;
-	ppc_md.get_boot_time	= rtas_get_boot_time;
-	ppc_md.get_rtc_time	= rtas_get_rtc_time;
-	ppc_md.set_rtc_time	= rtas_set_rtc_time;
-	ppc_md.init_IRQ		= celleb_init_IRQ_native;
+	unsigned long root = of_get_flat_dt_root();
+
+	if (!of_flat_dt_is_compatible(root, "Beat"))
+		return 0;
+
+	powerpc_firmware_features |= FW_FEATURE_CELLEB_ALWAYS
+		| FW_FEATURE_BEAT | FW_FEATURE_LPAR;
+	hpte_init_beat_v3();
+
+	return 1;
+}
 
+
+/*
+ * functions for Celleb-native
+ */
+static void __init celleb_init_IRQ_native(void)
+{
+	iic_init_IRQ();
+	spider_init_IRQ();
+}
+
+static void __init celleb_setup_arch_native(void)
+{
 #ifdef CONFIG_SPU_BASE
 	spu_priv1_ops		= &spu_priv1_mmio_ops;
 	spu_management_ops	= &spu_management_of_ops;
@@ -153,71 +184,75 @@ static void __init celleb_setup_arch_nat
 #endif
 
 	cbe_pervasive_init();
-}
 
-static void __init celleb_setup_arch(void)
-{
-	if (firmware_has_feature(FW_FEATURE_BEAT))
-		celleb_setup_arch_beat();
-	else
-		celleb_setup_arch_native();
+	/* XXX: nvram initialization should be added */
 
-	/* init to some ~sane value until calibrate_delay() runs */
-	loops_per_jiffy = 50000000;
-
-#ifdef CONFIG_DUMMY_CONSOLE
-	conswitchp = &dummy_con;
-#endif
+	celleb_setup_arch_common();
 }
 
-static int __init celleb_probe(void)
+static int __init celleb_probe_native(void)
 {
 	unsigned long root = of_get_flat_dt_root();
 
-	if (of_flat_dt_is_compatible(root, "Beat")) {
-		powerpc_firmware_features |= FW_FEATURE_CELLEB_ALWAYS
-			| FW_FEATURE_BEAT | FW_FEATURE_LPAR;
-		hpte_init_beat_v3();
-		return 1;
-	}
-	if (of_flat_dt_is_compatible(root, "TOSHIBA,Celleb")) {
-		powerpc_firmware_features |= FW_FEATURE_CELLEB_ALWAYS;
-		hpte_init_native();
-		return 1;
-	}
-
-	return 0;
-}
-
-static struct of_device_id celleb_bus_ids[] __initdata = {
-	{ .type = "scc", },
-	{ .type = "ioif", },	/* old style */
-	{},
-};
-
-static int __init celleb_publish_devices(void)
-{
-	if (!machine_is(celleb))
+	if (of_flat_dt_is_compatible(root, "Beat") ||
+	    !of_flat_dt_is_compatible(root, "TOSHIBA,Celleb"))
 		return 0;
 
-	/* Publish OF platform devices for southbridge IOs */
-	of_platform_bus_probe(NULL, celleb_bus_ids, NULL);
-
-	celleb_pci_workaround_init();
+	powerpc_firmware_features |= FW_FEATURE_CELLEB_ALWAYS;
+	hpte_init_native();
 
-	return 0;
+	return 1;
 }
-device_initcall(celleb_publish_devices);
 
-define_machine(celleb) {
-	.name			= "Cell Reference Set",
-	.probe			= celleb_probe,
-	.setup_arch		= celleb_setup_arch,
+
+/*
+ * machine definitions
+ */
+define_machine(celleb_beat) {
+	.name			= "Cell Reference Set (Beat)",
+	.probe			= celleb_probe_beat,
+	.setup_arch		= celleb_setup_arch_beat,
+	.show_cpuinfo		= celleb_show_cpuinfo,
+	.restart		= beat_restart,
+	.power_off		= beat_power_off,
+	.halt			= beat_halt,
+	.get_rtc_time		= beat_get_rtc_time,
+	.set_rtc_time		= beat_set_rtc_time,
+	.calibrate_decr		= generic_calibrate_decr,
+	.progress		= celleb_progress,
+	.power_save		= beat_power_save,
+	.nvram_size		= beat_nvram_get_size,
+	.nvram_read		= beat_nvram_read,
+	.nvram_write		= beat_nvram_write,
+	.set_dabr		= beat_set_xdabr,
+	.init_IRQ		= beatic_init_IRQ,
+	.get_irq		= beatic_get_irq,
+	.pci_probe_mode 	= celleb_pci_probe_mode,
+	.pci_setup_phb		= celleb_setup_phb,
+#ifdef CONFIG_KEXEC
+	.kexec_cpu_down		= beat_kexec_cpu_down,
+	.machine_kexec		= default_machine_kexec,
+	.machine_kexec_prepare	= default_machine_kexec_prepare,
+	.machine_crash_shutdown	= default_machine_crash_shutdown,
+#endif
+};
+
+define_machine(celleb_native) {
+	.name			= "Cell Reference Set (native)",
+	.probe			= celleb_probe_native,
+	.setup_arch		= celleb_setup_arch_native,
 	.show_cpuinfo		= celleb_show_cpuinfo,
+	.restart		= rtas_restart,
+	.power_off		= rtas_power_off,
+	.halt			= rtas_halt,
+	.get_boot_time		= rtas_get_boot_time,
+	.get_rtc_time		= rtas_get_rtc_time,
+	.set_rtc_time		= rtas_set_rtc_time,
 	.calibrate_decr		= generic_calibrate_decr,
 	.progress		= celleb_progress,
 	.pci_probe_mode 	= celleb_pci_probe_mode,
 	.pci_setup_phb		= celleb_setup_phb,
+	.init_IRQ		= celleb_init_IRQ_native,
 #ifdef CONFIG_KEXEC
 	.machine_kexec		= default_machine_kexec,
 	.machine_kexec_prepare	= default_machine_kexec_prepare,
Index: linux-powerpc-git/arch/powerpc/platforms/celleb/iommu.c
===================================================================
--- linux-powerpc-git.orig/arch/powerpc/platforms/celleb/iommu.c
+++ linux-powerpc-git/arch/powerpc/platforms/celleb/iommu.c
@@ -24,7 +24,7 @@
 #include <linux/pci.h>
 
 #include <asm/of_platform.h>
-#include <asm/firmware.h>
+#include <asm/machdep.h>
 
 #include "beat_wrapper.h"
 
@@ -92,7 +92,7 @@ static struct notifier_block celleb_of_b
 
 static int __init celleb_init_iommu(void)
 {
-	if (!firmware_has_feature(FW_FEATURE_BEAT))
+	if (!machine_is(celleb_beat))
 		return -ENODEV;
 
 	celleb_init_direct_mapping();

^ permalink raw reply

* [PATCH 2/2] kdump shutdown hook support
From: Michael Neuling @ 2007-12-13  9:59 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, THEMANN
In-Reply-To: <1197539957.623622.326790809699.qpush@coopers>

This adds hooks into the default_machine_crash_shutdown so drivers can
register a function to be run in the first kernel before we hand off
to the second kernel.  This should only be used in exceptional
circumstances, like where the device can't be reset in the second
kernel alone (as is the case with eHEA).  To emphasize this, the
number of handles allowed to be registered is currently #def to 1.

This uses the setjmp/longjmp code to call out to the registered hooks,
so any bogus exceptions we encounter will hopefully be recoverable.  

Tested with bogus data and instruction exceptions.

Signed-off-by: Michael Neuling <mikey@neuling.org>
---

 arch/powerpc/kernel/crash.c |  102 +++++++++++++++++++++++++++++++++++++++++---
 include/asm-powerpc/kexec.h |    3 +
 2 files changed, 100 insertions(+), 5 deletions(-)

Index: clone3/arch/powerpc/kernel/crash.c
===================================================================
--- clone3.orig/arch/powerpc/kernel/crash.c
+++ clone3/arch/powerpc/kernel/crash.c
@@ -32,6 +32,8 @@
 #include <asm/lmb.h>
 #include <asm/firmware.h>
 #include <asm/smp.h>
+#include <asm/system.h>
+#include <asm/setjmp.h>
 
 #ifdef DEBUG
 #include <asm/udbg.h>
@@ -45,6 +47,11 @@ int crashing_cpu = -1;
 static cpumask_t cpus_in_crash = CPU_MASK_NONE;
 cpumask_t cpus_in_sr = CPU_MASK_NONE;
 
+#define CRASH_HANDLER_MAX 1
+/* NULL terminated list of shutdown handles */
+static crash_shutdown_t crash_shutdown_handles[CRASH_HANDLER_MAX+1];
+static DEFINE_SPINLOCK(crash_handlers_lock);
+
 #ifdef CONFIG_SMP
 static atomic_t enter_on_soft_reset = ATOMIC_INIT(0);
 
@@ -285,9 +292,72 @@ static inline void crash_kexec_stop_spus
 }
 #endif /* CONFIG_SPU_BASE */
 
+/*
+ * Register a function to be called on shutdown.  Only use this if you
+ * can't reset your device in the second kernel.
+ */
+int crash_shutdown_register(crash_shutdown_t handler)
+{
+	unsigned int i, rc;
+
+	spin_lock(&crash_handlers_lock);
+	for (i = 0 ; i < CRASH_HANDLER_MAX; i++)
+		if (!crash_shutdown_handles[i]) {
+			/* Insert handle at first empty entry */
+			crash_shutdown_handles[i] = handler;
+			rc = 0;
+			break;
+		}
+
+	if (i == CRASH_HANDLER_MAX) {
+		printk(KERN_ERR "Crash shutdown handles full, "
+		       "not registered.\n");
+		rc = 1;
+	}
+
+	spin_unlock(&crash_handlers_lock);
+	return rc;
+}
+EXPORT_SYMBOL(crash_shutdown_register);
+
+int crash_shutdown_unregister(crash_shutdown_t handler)
+{
+	unsigned int i, rc;
+
+	spin_lock(&crash_handlers_lock);
+	for (i = 0 ; i < CRASH_HANDLER_MAX; i++)
+		if (crash_shutdown_handles[i] == handler)
+			break;
+
+	if (i == CRASH_HANDLER_MAX) {
+		printk(KERN_ERR "Crash shutdown handle not found\n");
+		rc = 1;
+	} else {
+		/* Shift handles down */
+		for (; crash_shutdown_handles[i]; i++)
+			crash_shutdown_handles[i] =
+				crash_shutdown_handles[i+1];
+		rc = 0;
+	}
+
+	spin_unlock(&crash_handlers_lock);
+	return rc;
+}
+EXPORT_SYMBOL(crash_shutdown_unregister);
+
+static unsigned long crash_shutdown_buf[SETJMP_BUF_LEN];
+
+static int handle_fault(struct pt_regs *regs)
+{
+	longjmp(crash_shutdown_buf, 1);
+	return 0;
+}
+
 void default_machine_crash_shutdown(struct pt_regs *regs)
 {
-	unsigned int irq;
+	unsigned int i;
+	int (*old_handler)(struct pt_regs *regs);
+
 
 	/*
 	 * This function is only called after the system
@@ -301,15 +371,37 @@ void default_machine_crash_shutdown(stru
 	 */
 	hard_irq_disable();
 
-	for_each_irq(irq) {
-		struct irq_desc *desc = irq_desc + irq;
+	for_each_irq(i) {
+		struct irq_desc *desc = irq_desc + i;
 
 		if (desc->status & IRQ_INPROGRESS)
-			desc->chip->eoi(irq);
+			desc->chip->eoi(i);
 
 		if (!(desc->status & IRQ_DISABLED))
-			desc->chip->disable(irq);
+			desc->chip->disable(i);
+	}
+
+	/*
+	 * Call registered shutdown routines savely.  Swap out
+	 * __debugger_fault_handler, and replace on exit.
+	 */
+	old_handler = __debugger_fault_handler;
+	__debugger_fault_handler = handle_fault;
+	for (i = 0; crash_shutdown_handles[i]; i++) {
+		if (setjmp(crash_shutdown_buf) == 0) {
+			/*
+			 * Insert syncs and delay to ensure
+			 * instructions in the dangerous region don't
+			 * leak away from this protected region.
+			 */
+			asm volatile("sync; isync");
+			/* dangerous region */
+			crash_shutdown_handles[i]();
+			asm volatile("sync; isync");
+			__delay(SETJMP_MACHINE_CHECK_DELAY);
+		}
 	}
+	__debugger_fault_handler = old_handler;
 
 	/*
 	 * Make a note of crashing cpu. Will be used in machine_kexec
Index: clone3/include/asm-powerpc/kexec.h
===================================================================
--- clone3.orig/include/asm-powerpc/kexec.h
+++ clone3/include/asm-powerpc/kexec.h
@@ -123,6 +123,9 @@ struct pt_regs;
 extern void default_machine_kexec(struct kimage *image);
 extern int default_machine_kexec_prepare(struct kimage *image);
 extern void default_machine_crash_shutdown(struct pt_regs *regs);
+typedef void (*crash_shutdown_t)(void);
+extern int crash_shutdown_register(crash_shutdown_t handler);
+extern int crash_shutdown_unregister(crash_shutdown_t handler);
 
 extern void machine_kexec_simple(struct kimage *image);
 extern void crash_kexec_secondary(struct pt_regs *regs);

^ permalink raw reply

* [PATCH 1/2] Make setjmp/longjmp code generic
From: Michael Neuling @ 2007-12-13  9:59 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, THEMANN
In-Reply-To: <1197539957.623622.326790809699.qpush@coopers>

This makes the setjmp/longjmp code used by xmon, generically available
to other code.  It also removes the requirement for debugger hooks to
be only called on 0x300 (data storage) exception and adds some
documentation.

Signed-off-by: Michael Neuling <mikey@neuling.org>
---

 arch/powerpc/kernel/misc.S   |  128 ++++++++++++++++++++++++++++++++++++++++
 arch/powerpc/mm/fault.c      |    6 -
 arch/powerpc/xmon/Makefile   |    2 
 arch/powerpc/xmon/setjmp.S   |  135 -------------------------------------------
 arch/powerpc/xmon/xmon.c     |   38 ++++--------
 include/asm-powerpc/setjmp.h |   19 ++++++
 6 files changed, 164 insertions(+), 164 deletions(-)

Index: clone3/arch/powerpc/kernel/misc.S
===================================================================
--- clone3.orig/arch/powerpc/kernel/misc.S
+++ clone3/arch/powerpc/kernel/misc.S
@@ -8,6 +8,8 @@
  * Adapted for iSeries by Mike Corrigan (mikejc@us.ibm.com)
  * PPC64 updates by Dave Engebretsen (engebret@us.ibm.com)
  *
+ * setjmp/longjmp and xmon_save_regs code by Paul Mackerras.
+ *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  * as published by the Free Software Foundation; either version
@@ -15,6 +17,8 @@
  */
 #include <asm/ppc_asm.h>
 #include <asm/unistd.h>
+#include <asm/asm-compat.h>
+#include <asm/asm-offsets.h>
 
 	.text
 
@@ -51,3 +55,127 @@ _GLOBAL(kernel_execve)
 	bnslr
 	neg	r3,r3
 	blr
+
+_GLOBAL(setjmp)
+	mflr	r0
+	PPC_STL	r0,0(r3)
+	PPC_STL	r1,SZL(r3)
+	PPC_STL	r2,2*SZL(r3)
+	mfcr	r0
+	PPC_STL	r0,3*SZL(r3)
+	PPC_STL	r13,4*SZL(r3)
+	PPC_STL	r14,5*SZL(r3)
+	PPC_STL	r15,6*SZL(r3)
+	PPC_STL	r16,7*SZL(r3)
+	PPC_STL	r17,8*SZL(r3)
+	PPC_STL	r18,9*SZL(r3)
+	PPC_STL	r19,10*SZL(r3)
+	PPC_STL	r20,11*SZL(r3)
+	PPC_STL	r21,12*SZL(r3)
+	PPC_STL	r22,13*SZL(r3)
+	PPC_STL	r23,14*SZL(r3)
+	PPC_STL	r24,15*SZL(r3)
+	PPC_STL	r25,16*SZL(r3)
+	PPC_STL	r26,17*SZL(r3)
+	PPC_STL	r27,18*SZL(r3)
+	PPC_STL	r28,19*SZL(r3)
+	PPC_STL	r29,20*SZL(r3)
+	PPC_STL	r30,21*SZL(r3)
+	PPC_STL	r31,22*SZL(r3)
+	li	r3,0
+	blr
+
+_GLOBAL(longjmp)
+	PPC_LCMPI r4,0
+	bne	1f
+	li	r4,1
+1:	PPC_LL	r13,4*SZL(r3)
+	PPC_LL	r14,5*SZL(r3)
+	PPC_LL	r15,6*SZL(r3)
+	PPC_LL	r16,7*SZL(r3)
+	PPC_LL	r17,8*SZL(r3)
+	PPC_LL	r18,9*SZL(r3)
+	PPC_LL	r19,10*SZL(r3)
+	PPC_LL	r20,11*SZL(r3)
+	PPC_LL	r21,12*SZL(r3)
+	PPC_LL	r22,13*SZL(r3)
+	PPC_LL	r23,14*SZL(r3)
+	PPC_LL	r24,15*SZL(r3)
+	PPC_LL	r25,16*SZL(r3)
+	PPC_LL	r26,17*SZL(r3)
+	PPC_LL	r27,18*SZL(r3)
+	PPC_LL	r28,19*SZL(r3)
+	PPC_LL	r29,20*SZL(r3)
+	PPC_LL	r30,21*SZL(r3)
+	PPC_LL	r31,22*SZL(r3)
+	PPC_LL	r0,3*SZL(r3)
+	mtcrf	0x38,r0
+	PPC_LL	r0,0(r3)
+	PPC_LL	r1,SZL(r3)
+	PPC_LL	r2,2*SZL(r3)
+	mtlr	r0
+	mr	r3,r4
+	blr
+
+#ifdef CONFIG_XMON
+/*
+ * Grab the register values as they are now.
+ * This won't do a particularily good job because we really
+ * want our caller's caller's registers, and our caller has
+ * already executed its prologue.
+ * ToDo: We could reach back into the caller's save area to do
+ * a better job of representing the caller's state (note that
+ * that will be different for 32-bit and 64-bit, because of the
+ * different ABIs, though).
+ */
+_GLOBAL(xmon_save_regs)
+	PPC_STL	r0,0*SZL(r3)
+	PPC_STL	r2,2*SZL(r3)
+	PPC_STL	r3,3*SZL(r3)
+	PPC_STL	r4,4*SZL(r3)
+	PPC_STL	r5,5*SZL(r3)
+	PPC_STL	r6,6*SZL(r3)
+	PPC_STL	r7,7*SZL(r3)
+	PPC_STL	r8,8*SZL(r3)
+	PPC_STL	r9,9*SZL(r3)
+	PPC_STL	r10,10*SZL(r3)
+	PPC_STL	r11,11*SZL(r3)
+	PPC_STL	r12,12*SZL(r3)
+	PPC_STL	r13,13*SZL(r3)
+	PPC_STL	r14,14*SZL(r3)
+	PPC_STL	r15,15*SZL(r3)
+	PPC_STL	r16,16*SZL(r3)
+	PPC_STL	r17,17*SZL(r3)
+	PPC_STL	r18,18*SZL(r3)
+	PPC_STL	r19,19*SZL(r3)
+	PPC_STL	r20,20*SZL(r3)
+	PPC_STL	r21,21*SZL(r3)
+	PPC_STL	r22,22*SZL(r3)
+	PPC_STL	r23,23*SZL(r3)
+	PPC_STL	r24,24*SZL(r3)
+	PPC_STL	r25,25*SZL(r3)
+	PPC_STL	r26,26*SZL(r3)
+	PPC_STL	r27,27*SZL(r3)
+	PPC_STL	r28,28*SZL(r3)
+	PPC_STL	r29,29*SZL(r3)
+	PPC_STL	r30,30*SZL(r3)
+	PPC_STL	r31,31*SZL(r3)
+	/* go up one stack frame for SP */
+	PPC_LL	r4,0(r1)
+	PPC_STL	r4,1*SZL(r3)
+	/* get caller's LR */
+	PPC_LL	r0,LRSAVE(r4)
+	PPC_STL	r0,_NIP-STACK_FRAME_OVERHEAD(r3)
+	PPC_STL	r0,_LINK-STACK_FRAME_OVERHEAD(r3)
+	mfmsr	r0
+	PPC_STL	r0,_MSR-STACK_FRAME_OVERHEAD(r3)
+	mfctr	r0
+	PPC_STL	r0,_CTR-STACK_FRAME_OVERHEAD(r3)
+	mfxer	r0
+	PPC_STL	r0,_XER-STACK_FRAME_OVERHEAD(r3)
+	mfcr	r0
+	PPC_STL	r0,_CCR-STACK_FRAME_OVERHEAD(r3)
+	li	r0,0
+	PPC_STL	r0,_TRAP-STACK_FRAME_OVERHEAD(r3)
+	blr
+#endif
Index: clone3/arch/powerpc/mm/fault.c
===================================================================
--- clone3.orig/arch/powerpc/mm/fault.c
+++ clone3/arch/powerpc/mm/fault.c
@@ -167,10 +167,8 @@ int __kprobes do_page_fault(struct pt_re
 	if (notify_page_fault(regs))
 		return 0;
 
-	if (trap == 0x300) {
-		if (debugger_fault_handler(regs))
-			return 0;
-	}
+	if (unlikely(debugger_fault_handler(regs)))
+		return 0;
 
 	/* On a kernel SLB miss we can only check for a valid exception entry */
 	if (!user_mode(regs) && (address >= TASK_SIZE))
Index: clone3/arch/powerpc/xmon/Makefile
===================================================================
--- clone3.orig/arch/powerpc/xmon/Makefile
+++ clone3/arch/powerpc/xmon/Makefile
@@ -4,7 +4,7 @@ ifdef CONFIG_PPC64
 EXTRA_CFLAGS += -mno-minimal-toc
 endif
 
-obj-y			+= xmon.o setjmp.o start.o nonstdio.o
+obj-y			+= xmon.o start.o nonstdio.o
 
 ifdef CONFIG_XMON_DISASSEMBLY
 obj-y			+= ppc-dis.o ppc-opc.o
Index: clone3/arch/powerpc/xmon/setjmp.S
===================================================================
--- clone3.orig/arch/powerpc/xmon/setjmp.S
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 1996 Paul Mackerras.
- *
- *      This program is free software; you can redistribute it and/or
- *      modify it under the terms of the GNU General Public License
- *      as published by the Free Software Foundation; either version
- *      2 of the License, or (at your option) any later version.
- *
- * NOTE: assert(sizeof(buf) > 23 * sizeof(long))
- */
-#include <asm/processor.h>
-#include <asm/ppc_asm.h>
-#include <asm/asm-offsets.h>
-
-_GLOBAL(xmon_setjmp)
-	mflr	r0
-	PPC_STL	r0,0(r3)
-	PPC_STL	r1,SZL(r3)
-	PPC_STL	r2,2*SZL(r3)
-	mfcr	r0
-	PPC_STL	r0,3*SZL(r3)
-	PPC_STL	r13,4*SZL(r3)
-	PPC_STL	r14,5*SZL(r3)
-	PPC_STL	r15,6*SZL(r3)
-	PPC_STL	r16,7*SZL(r3)
-	PPC_STL	r17,8*SZL(r3)
-	PPC_STL	r18,9*SZL(r3)
-	PPC_STL	r19,10*SZL(r3)
-	PPC_STL	r20,11*SZL(r3)
-	PPC_STL	r21,12*SZL(r3)
-	PPC_STL	r22,13*SZL(r3)
-	PPC_STL	r23,14*SZL(r3)
-	PPC_STL	r24,15*SZL(r3)
-	PPC_STL	r25,16*SZL(r3)
-	PPC_STL	r26,17*SZL(r3)
-	PPC_STL	r27,18*SZL(r3)
-	PPC_STL	r28,19*SZL(r3)
-	PPC_STL	r29,20*SZL(r3)
-	PPC_STL	r30,21*SZL(r3)
-	PPC_STL	r31,22*SZL(r3)
-	li	r3,0
-	blr
-
-_GLOBAL(xmon_longjmp)
-	PPC_LCMPI r4,0
-	bne	1f
-	li	r4,1
-1:	PPC_LL	r13,4*SZL(r3)
-	PPC_LL	r14,5*SZL(r3)
-	PPC_LL	r15,6*SZL(r3)
-	PPC_LL	r16,7*SZL(r3)
-	PPC_LL	r17,8*SZL(r3)
-	PPC_LL	r18,9*SZL(r3)
-	PPC_LL	r19,10*SZL(r3)
-	PPC_LL	r20,11*SZL(r3)
-	PPC_LL	r21,12*SZL(r3)
-	PPC_LL	r22,13*SZL(r3)
-	PPC_LL	r23,14*SZL(r3)
-	PPC_LL	r24,15*SZL(r3)
-	PPC_LL	r25,16*SZL(r3)
-	PPC_LL	r26,17*SZL(r3)
-	PPC_LL	r27,18*SZL(r3)
-	PPC_LL	r28,19*SZL(r3)
-	PPC_LL	r29,20*SZL(r3)
-	PPC_LL	r30,21*SZL(r3)
-	PPC_LL	r31,22*SZL(r3)
-	PPC_LL	r0,3*SZL(r3)
-	mtcrf	0x38,r0
-	PPC_LL	r0,0(r3)
-	PPC_LL	r1,SZL(r3)
-	PPC_LL	r2,2*SZL(r3)
-	mtlr	r0
-	mr	r3,r4
-	blr
-
-/*
- * Grab the register values as they are now.
- * This won't do a particularily good job because we really
- * want our caller's caller's registers, and our caller has
- * already executed its prologue.
- * ToDo: We could reach back into the caller's save area to do
- * a better job of representing the caller's state (note that
- * that will be different for 32-bit and 64-bit, because of the
- * different ABIs, though).
- */
-_GLOBAL(xmon_save_regs)
-	PPC_STL	r0,0*SZL(r3)
-	PPC_STL	r2,2*SZL(r3)
-	PPC_STL	r3,3*SZL(r3)
-	PPC_STL	r4,4*SZL(r3)
-	PPC_STL	r5,5*SZL(r3)
-	PPC_STL	r6,6*SZL(r3)
-	PPC_STL	r7,7*SZL(r3)
-	PPC_STL	r8,8*SZL(r3)
-	PPC_STL	r9,9*SZL(r3)
-	PPC_STL	r10,10*SZL(r3)
-	PPC_STL	r11,11*SZL(r3)
-	PPC_STL	r12,12*SZL(r3)
-	PPC_STL	r13,13*SZL(r3)
-	PPC_STL	r14,14*SZL(r3)
-	PPC_STL	r15,15*SZL(r3)
-	PPC_STL	r16,16*SZL(r3)
-	PPC_STL	r17,17*SZL(r3)
-	PPC_STL	r18,18*SZL(r3)
-	PPC_STL	r19,19*SZL(r3)
-	PPC_STL	r20,20*SZL(r3)
-	PPC_STL	r21,21*SZL(r3)
-	PPC_STL	r22,22*SZL(r3)
-	PPC_STL	r23,23*SZL(r3)
-	PPC_STL	r24,24*SZL(r3)
-	PPC_STL	r25,25*SZL(r3)
-	PPC_STL	r26,26*SZL(r3)
-	PPC_STL	r27,27*SZL(r3)
-	PPC_STL	r28,28*SZL(r3)
-	PPC_STL	r29,29*SZL(r3)
-	PPC_STL	r30,30*SZL(r3)
-	PPC_STL	r31,31*SZL(r3)
-	/* go up one stack frame for SP */
-	PPC_LL	r4,0(r1)
-	PPC_STL	r4,1*SZL(r3)
-	/* get caller's LR */
-	PPC_LL	r0,LRSAVE(r4)
-	PPC_STL	r0,_NIP-STACK_FRAME_OVERHEAD(r3)
-	PPC_STL	r0,_LINK-STACK_FRAME_OVERHEAD(r3)
-	mfmsr	r0
-	PPC_STL	r0,_MSR-STACK_FRAME_OVERHEAD(r3)
-	mfctr	r0
-	PPC_STL	r0,_CTR-STACK_FRAME_OVERHEAD(r3)
-	mfxer	r0
-	PPC_STL	r0,_XER-STACK_FRAME_OVERHEAD(r3)
-	mfcr	r0
-	PPC_STL	r0,_CCR-STACK_FRAME_OVERHEAD(r3)
-	li	r0,0
-	PPC_STL	r0,_TRAP-STACK_FRAME_OVERHEAD(r3)
-	blr
Index: clone3/arch/powerpc/xmon/xmon.c
===================================================================
--- clone3.orig/arch/powerpc/xmon/xmon.c
+++ clone3/arch/powerpc/xmon/xmon.c
@@ -40,6 +40,7 @@
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
 #include <asm/firmware.h>
+#include <asm/setjmp.h>
 
 #ifdef CONFIG_PPC64
 #include <asm/hvcall.h>
@@ -71,12 +72,9 @@ static unsigned long ncsum = 4096;
 static int termch;
 static char tmpstr[128];
 
-#define JMP_BUF_LEN	23
-static long bus_error_jmp[JMP_BUF_LEN];
+static long bus_error_jmp[SETJMP_BUF_LEN];
 static int catch_memory_errors;
 static long *xmon_fault_jmp[NR_CPUS];
-#define setjmp xmon_setjmp
-#define longjmp xmon_longjmp
 
 /* Breakpoint stuff */
 struct bpt {
@@ -162,8 +160,6 @@ int xmon_no_auto_backtrace;
 extern void xmon_enter(void);
 extern void xmon_leave(void);
 
-extern long setjmp(long *);
-extern void longjmp(long *, long);
 extern void xmon_save_regs(struct pt_regs *);
 
 #ifdef CONFIG_PPC64
@@ -338,7 +334,7 @@ static int xmon_core(struct pt_regs *reg
 {
 	int cmd = 0;
 	struct bpt *bp;
-	long recurse_jmp[JMP_BUF_LEN];
+	long recurse_jmp[SETJMP_BUF_LEN];
 	unsigned long offset;
 	unsigned long flags;
 #ifdef CONFIG_SMP
@@ -1428,7 +1424,7 @@ void prregs(struct pt_regs *fp)
 			sync();
 			regs = *(struct pt_regs *)base;
 			sync();
-			__delay(200);
+			__delay(SETJMP_MACHINE_CHECK_DELAY);
 		} else {
 			catch_memory_errors = 0;
 			printf("*** Error reading registers from "REG"\n",
@@ -1497,8 +1493,7 @@ void cacheflush(void)
 				cinval((void *) adrs);
 		}
 		sync();
-		/* wait a little while to see if we get a machine check */
-		__delay(200);
+		__delay(SETJMP_MACHINE_CHECK_DELAY);
 	}
 	catch_memory_errors = 0;
 }
@@ -1533,8 +1528,7 @@ read_spr(int n)
 		ret = code();
 
 		sync();
-		/* wait a little while to see if we get a machine check */
-		__delay(200);
+		__delay(SETJMP_MACHINE_CHECK_DELAY);
 		n = size;
 	}
 
@@ -1569,8 +1563,7 @@ write_spr(int n, unsigned long val)
 		code(val);
 
 		sync();
-		/* wait a little while to see if we get a machine check */
-		__delay(200);
+		__delay(SETJMP_MACHINE_CHECK_DELAY);
 		n = size;
 	}
 }
@@ -1676,8 +1669,7 @@ mread(unsigned long adrs, void *buf, int
 			}
 		}
 		sync();
-		/* wait a little while to see if we get a machine check */
-		__delay(200);
+		__delay(SETJMP_MACHINE_CHECK_DELAY);
 		n = size;
 	}
 	catch_memory_errors = 0;
@@ -1713,8 +1705,7 @@ mwrite(unsigned long adrs, void *buf, in
 			}
 		}
 		sync();
-		/* wait a little while to see if we get a machine check */
-		__delay(200);
+		__delay(SETJMP_MACHINE_CHECK_DELAY);
 		n = size;
 	} else {
 		printf("*** Error writing address %x\n", adrs + n);
@@ -2521,8 +2512,7 @@ static void xmon_print_symbol(unsigned l
 		name = kallsyms_lookup(address, &size, &offset, &modname,
 				       tmpstr);
 		sync();
-		/* wait a little while to see if we get a machine check */
-		__delay(200);
+		__delay(SETJMP_MACHINE_CHECK_DELAY);
 	}
 
 	catch_memory_errors = 0;
@@ -2777,7 +2767,7 @@ static void stop_spus(void)
 			spu_mfc_sr1_set(spu, tmp);
 
 			sync();
-			__delay(200);
+			__delay(SETJMP_MACHINE_CHECK_DELAY);
 
 			spu_info[i].stopped_ok = 1;
 
@@ -2817,7 +2807,7 @@ static void restart_spus(void)
 					spu_info[i].saved_spu_runcntl_RW);
 
 			sync();
-			__delay(200);
+			__delay(SETJMP_MACHINE_CHECK_DELAY);
 
 			printf("Restarted spu %.2d\n", i);
 		} else {
@@ -2837,7 +2827,7 @@ do {									\
 		printf("  %-*s = "format"\n", DUMP_WIDTH,		\
 				#field, value);				\
 		sync();							\
-		__delay(200);						\
+		__delay(SETJMP_MACHINE_CHECK_DELAY);			\
 	} else {							\
 		catch_memory_errors = 0;				\
 		printf("  %-*s = *** Error reading field.\n",		\
@@ -2899,7 +2889,7 @@ static void dump_spu_ls(unsigned long nu
 		sync();
 		ls_addr = (unsigned long)spu_info[num].spu->local_store;
 		sync();
-		__delay(200);
+		__delay(SETJMP_MACHINE_CHECK_DELAY);
 	} else {
 		catch_memory_errors = 0;
 		printf("*** Error: accessing spu info for spu %d\n", num);
Index: clone3/include/asm-powerpc/setjmp.h
===================================================================
--- /dev/null
+++ clone3/include/asm-powerpc/setjmp.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2007 Michael Neuling
+ *
+ *      This program is free software; you can redistribute it and/or
+ *      modify it under the terms of the GNU General Public License
+ *      as published by the Free Software Foundation; either version
+ *      2 of the License, or (at your option) any later version.
+ *
+ */
+#ifndef _ASM_POWERPC_SETJMP_H
+#define _ASM_POWERPC_SETJMP_H
+
+#define SETJMP_BUF_LEN    23
+#define SETJMP_MACHINE_CHECK_DELAY    200
+
+extern long setjmp(long *);
+extern void longjmp(long *, long);
+
+#endif /* _ASM_POWERPC_SETJMP_H */

^ permalink raw reply

* [PATCH 0/2] Add crashdump shutdown hooks
From: Michael Neuling @ 2007-12-13  9:59 UTC (permalink / raw)
  To: Paul Mackerras; +Cc: linuxppc-dev, RAISCH, THEMANN
In-Reply-To: <20071213051224.GA22378@lixom.net>

The following patches add crashdump shutdown hooks for POWERPC.
Signed-off-by: Michael Neuling <mikey@neuling.org>
---
Fixes stupid variable name noticed by Olof.

^ permalink raw reply

* Re: [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Stefan Roese @ 2007-12-13  9:56 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <200712131042.48354.sr@denx.de>

On Thursday 13 December 2007, Stefan Roese wrote:
> On Thursday 13 December 2007, Benjamin Herrenschmidt wrote:
> > This makes 4xx embedded platforms re-assign all PCI resources as we
> > pretty much never care about what the various firmwares have done on
> > these, it's generally not compatible with the way the kernel will map
> > the bridges.
> >
> > We still need to also enable bus renumbering on some of them, but I
> > will do that from a separate patch after I've fixed 4xx PCIe to handle
> > all bus numbers.
>
> I just applied this series on top of Paulus's for-2.6.25 branch and I
> get the following error:
>
> /home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilaue
>a.c: In function 'kilauea_probe':
> /home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilaue
>a.c:49: error: 'ppc_pci_flags' undeclared (first use in this function)
> /home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilaue
>a.c:49: error: (Each undeclared identifier is reported only once
> /home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilaue
>a.c:49: error: for each function it appears in.)
> /home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilaue
>a.c:49: error: 'PPC_PCI_REASSIGN_ALL_RSRC' undeclared (first use in this
> function) make[3]: *** [arch/powerpc/platforms/40x/kilauea.o] Error 1

Sorry for the noise, but this was my problem. I didn't apply Ben's PCI patch 
series.

Ciao,
Stefan

^ permalink raw reply

* Re: [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Stefan Roese @ 2007-12-13  9:42 UTC (permalink / raw)
  To: linuxppc-dev
In-Reply-To: <20071213073851.C321FDDFC9@ozlabs.org>

On Thursday 13 December 2007, Benjamin Herrenschmidt wrote:
> This makes 4xx embedded platforms re-assign all PCI resources as we
> pretty much never care about what the various firmwares have done on
> these, it's generally not compatible with the way the kernel will map
> the bridges.
>
> We still need to also enable bus renumbering on some of them, but I
> will do that from a separate patch after I've fixed 4xx PCIe to handle
> all bus numbers.

I just applied this series on top of Paulus's for-2.6.25 branch and I
get the following error:

/home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilauea.c: In function 'kilauea_probe':
/home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilauea.c:49: error: 'ppc_pci_flags' undeclared (first use in this function)
/home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilauea.c:49: error: (Each undeclared identifier is reported only once
/home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilauea.c:49: error: for each function it appears in.)
/home/stefan/git/linux-2.6/paulus-powerpc/arch/powerpc/platforms/40x/kilauea.c:49: error: 'PPC_PCI_REASSIGN_ALL_RSRC' undeclared (first use in this function)
make[3]: *** [arch/powerpc/platforms/40x/kilauea.o] Error 1

Seems like the patch:

    powerpc: pci32: Add flags modifying the PCI code behaviour
    
    This adds to the 32 bits PCI code some flags, replacing the old
    pci_assign_all_busses global, that allow to control various
    aspects of the PCI probing, such as whether to re-assign all
    resources or not, or to not try to assign anything at all.
    
    This also adds the flag x86 already has to avoid ISA alignment
    on bridges that don't have ISA forwarding enabled (no legacy
    devices on the top level bus) and sets it for PowerMacs.
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>


is missing.

Thanks.

Ciao,
Stefan

^ permalink raw reply

* RE: Linux 2.6 from git.xilinx and XUPV2P
From: greenlean @ 2007-12-13  9:15 UTC (permalink / raw)
  To: linuxppc-embedded
In-Reply-To: <20071212171940.8D86B17B0067@mail230-blu.bigfish.com>


I'm going to generate the kernel using the file generated by EDK, and if I
still have the same problem I'll tell you, maybe the problem is realted with
the xparamters configuration file, I don't want to waste your time. 

I think I should change my category from beginner to beginest .. :)

I'm not sure how to use objdump or better what to search in the elf file,
but I've used readelf to extract some info:

$ppc_4xx-readelf -h zImage.elf 
ELF Header:
  Magic:   7f 45 4c 46 01 02 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, big endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           PowerPC
  Version:                           0x1
  Entry point address:               0x400000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          1048856 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         17
  Section header string table index: 14

Everything seems to be fine..... I really don't know.



Stephen Neuendorffer wrote:
> 
> The xparameters file is specific to your hardware design.
> You should change the name of the generated xparameters file to match
> xparameters_xupv2p.h 
> 
> Unfortunately, it's sort of an historical artifact that it was done this
> way...  In reality, all the different xparameters files should really
> just be one, since only one can be active at a time.
> 
> The last error sounds like you haven't actually generated an elf file?
> have you tried running objdump on it?
> 
> Steve
> 
>> -----Original Message-----
>> From: 
>> linuxppc-embedded-bounces+stephen=neuendorffer.name@ozlabs.org
>>  
>> [mailto:linuxppc-embedded-bounces+stephen=neuendorffer.name@oz
>> labs.org] On Behalf Of greenlean
>> Sent: Wednesday, December 12, 2007 9:05 AM
>> To: linuxppc-embedded@ozlabs.org
>> Subject: Re: Linux 2.6 from git.xilinx and XUPV2P
>> 
>> 
>> 
>> 
>> greenlean wrote:
>> > 
>> > Thanks both for the response, I've allready visited some of 
>> the links. 
>> > 
>> > Yes, you was right it's easear than I think, my problem was 
>> the .config
>> > file. Now, I have generated it from ml300_defconfig and 
>> after some changes
>> > it compiles, but I've two question:
>> > 
>> >  * I've chosen as platform the XUPV2P in Machine Type, 
>> instead of ML300,
>> > so the xparameters file that I'm using is the 
>> xparameters_xupv2p.h, but
>> > the xparameters file generated by the EDK is 
>> xparameters_ml300 despite I
>> > told it to use XUPV2P, so I can't overwrite it... 
>> > 
>> > Should I use the xparameters_ml300 generated by EDK or the
>> > xparameters_xupv2p included in the git kernel tree?.  I 
>> can't compile with
>> > the edk's xparameters_ml300 file because there's some 
>> definition that the
>> > compiler can't find, so I'm using the xparameters_xupv2p.
>> > 
>> >  * Second, if I compile using the xparameters_xupv2p, when 
>> I do the dow
>> > command to download the image to the board, the xmd shell tell me:
>> >            
>> >    XMD% dow zImage.elf
>> >            Failed to download ELF file
>> > 
>> >       ERROR(1053): UNABLE to Read Elf File. The Elf File 
>> Maybe Corrupted
>> >           : zImage.elf
>> > Maybe this error is due to the above asumption??. I'll post 
>> this second
>> > one on xilinx-support maybe it's realted with my system.....
>> > 
>> > 
>> > 
>> 
>> -- 
>> View this message in context: 
>> http://www.nabble.com/Linux-2.6-from-git.xilinx-and-XUPV2P-tp1
>> 4274035p14299307.html
>> Sent from the linuxppc-embedded mailing list archive at Nabble.com.
>> 
>> _______________________________________________
>> Linuxppc-embedded mailing list
>> Linuxppc-embedded@ozlabs.org
>> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>> 
>> 
> 
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
> 
> 

-- 
View this message in context: http://www.nabble.com/Linux-2.6-from-git.xilinx-and-XUPV2P-tp14274035p14312417.html
Sent from the linuxppc-embedded mailing list archive at Nabble.com.

^ permalink raw reply

* Re: [ewg] Re: [PATCH] IB/ehca: Serialize HCA-related hCalls on POWER5
From: Or Gerlitz @ 2007-12-13  8:30 UTC (permalink / raw)
  To: Roland Dreier
  Cc: Arnd Bergmann, Joachim Fenkes, LKML, linuxppc-dev,
	Christoph Raisch, OF-General, Stefan Roscher
In-Reply-To: <adabq8v91co.fsf@cisco.com>

Roland Dreier wrote:
> I think the right fix for iSER would be to make iSER work even for
> devices that don't support FMRs.  For example cxgb3 doesn't implement
> FMRs so if anyone ever updates iSER to work on iWARP and not just IB,
> then this is something that has to be tackled anyway.  Then ehca could
> just get rid of the FMR support it has.

OK, The iSER design took into account the case of many initiators 
running on strong/modern machines talking to possibly lightweight 
embedded target for which the processing cost per I/O at the target side 
should be minimized, that is at most --one-- RDMA operation should be 
issued by the target to serve an I/O request.

For that end, iSER works with one descriptor (called stag in iWARP and 
rkey in IB) per I/O direction sent from the initiator to the target and 
hence can't work without some sort of FMR implementation.

The current implementation of the open iscsi initiator makes sure to 
issue commands in thread (sleepable) context, see iscsi_xmitworker and 
references to it in drivers/scsi/libiscsi.c , so this keeps ehca users 
safe for the time being.

Or.

^ permalink raw reply

* [PATCH 3/3] Add memory mapping support to rionet driver.
From: Zhang Wei @ 2007-12-13  7:58 UTC (permalink / raw)
  To: mporter, paulus, galak; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <11975327073961-git-send-email-wei.zhang@freescale.com>

Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
---
 drivers/net/Kconfig  |   10 ++
 drivers/net/rionet.c |  337 +++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 345 insertions(+), 2 deletions(-)

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index e8d69b0..b1129cc 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2637,6 +2637,16 @@ config RIONET_RX_SIZE
 	depends on RIONET
 	default "128"
 
+config RIONET_MEMMAP
+	bool "Use memory map instead of message"
+	depends on RIONET
+	default n
+
+config RIONET_DMA
+	bool "Use DMA for memory mapping data transfer"
+	depends on RIONET_MEMMAP && FSL_DMA
+	default y
+
 config FDDI
 	bool "FDDI driver support"
 	depends on (PCI || EISA || TC)
diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c
index e7fd08a..53b53a8 100644
--- a/drivers/net/rionet.c
+++ b/drivers/net/rionet.c
@@ -1,6 +1,13 @@
 /*
  * rionet - Ethernet driver over RapidIO messaging services
  *
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ * Author: Zhang Wei, wei.zhang@freescale.com, Jun 2007
+ *
+ * Changelog:
+ * Jun 2007 Zhang Wei <wei.zhang@freescale.com>
+ * - Added the support to RapidIO memory driver. 2007.
+ *
  * Copyright 2005 MontaVista Software, Inc.
  * Matt Porter <mporter@kernel.crashing.org>
  *
@@ -8,6 +15,7 @@
  * under  the terms of  the GNU General  Public License as published by the
  * Free Software Foundation;  either version 2 of the  License, or (at your
  * option) any later version.
+ *
  */
 
 #include <linux/module.h>
@@ -23,6 +31,7 @@
 #include <linux/skbuff.h>
 #include <linux/crc32.h>
 #include <linux/ethtool.h>
+#include <linux/dmaengine.h>
 
 #define DRV_NAME        "rionet"
 #define DRV_VERSION     "0.2"
@@ -40,13 +49,47 @@ MODULE_LICENSE("GPL");
 			 NETIF_MSG_TX_ERR)
 
 #define RIONET_DOORBELL_JOIN	0x1000
+#ifdef CONFIG_RIONET_MEMMAP
+#define RIONET_DOORBELL_SEND	0x1001
+#define RIONET_DOORBELL_LEAVE	0x1002
+#else
 #define RIONET_DOORBELL_LEAVE	0x1001
+#endif
 
 #define RIONET_MAILBOX		0
 
 #define RIONET_TX_RING_SIZE	CONFIG_RIONET_TX_SIZE
 #define RIONET_RX_RING_SIZE	CONFIG_RIONET_RX_SIZE
 
+#define ERR(fmt, arg...) \
+	printk(KERN_ERR "ERROR %s - %s: " fmt,  __FILE__, __FUNCTION__, ## arg)
+
+#ifdef CONFIG_RIONET_MEMMAP
+/* Definitions for rionet memory map driver */
+#define RIONET_DRVID		0x101
+#define RIONET_MAX_SK_DATA_SIZE	0x1000
+#define RIONET_TX_RX_BUFF_SIZE	(0x1000 * (128 + 128))
+#define RIONET_QUEUE_NEXT(x)	(((x) < 127) ? ((x) + 1) : 0)
+#define RIONET_QUEUE_INC(x)	(x = RIONET_QUEUE_NEXT(x))
+
+struct sk_data {
+	u8	data[0x1000];
+};
+
+#define RIONET_SKDATA_EN	0x80000000
+struct rionet_tx_rx_buff {
+	volatile int	enqueue;		/* enqueue point */
+	volatile int	dequeue;		/* dequeue point */
+	u32		size[128];		/* size[i] is skdata[i] size
+						 * the most high bit [31] is
+						 * enable bit. The
+						 * max size is 4096.
+						 */
+	u8		rev1[3576];
+	struct sk_data	skdata[128];		/* all size are 0x1000 * 128 */
+};
+#endif /* CONFIG_RIONET_MEMMAP */
+
 static LIST_HEAD(rionet_peers);
 
 struct rionet_private {
@@ -60,6 +103,18 @@ struct rionet_private {
 	spinlock_t lock;
 	spinlock_t tx_lock;
 	u32 msg_enable;
+#ifdef CONFIG_RIONET_MEMMAP
+	struct rionet_tx_rx_buff *rxbuff;
+	struct rionet_tx_rx_buff __iomem *txbuff;
+	struct rio_mem *rxmem;
+	struct rio_mem *txmem;
+#ifdef CONFIG_RIONET_DMA
+	struct dma_chan *txdmachan;
+	struct dma_chan *rxdmachan;
+	struct dma_client rio_dma_client;
+	spinlock_t rio_dma_event_lock;
+#endif
+#endif
 };
 
 struct rionet_peer {
@@ -77,7 +132,7 @@ static int rionet_capable = 1;
  * could be made into a hash table to save memory depending
  * on system trade-offs.
  */
-static struct rio_dev *rionet_active[RIO_MAX_ROUTE_ENTRIES];
+static struct rio_dev **rionet_active;
 
 #define is_rionet_capable(pef, src_ops, dst_ops)		\
 			((pef & RIO_PEF_INB_MBOX) &&		\
@@ -108,9 +163,11 @@ static int rionet_rx_clean(struct net_device *ndev)
 
 		rnet->rx_skb[i]->data = data;
 		skb_put(rnet->rx_skb[i], RIO_MAX_MSG_SIZE);
+		rnet->rx_skb[i]->dev = ndev;
 		rnet->rx_skb[i]->protocol =
 		    eth_type_trans(rnet->rx_skb[i], ndev);
 		error = netif_rx(rnet->rx_skb[i]);
+		rnet->rx_skb[i] = NULL;
 
 		if (error == NET_RX_DROP) {
 			ndev->stats.rx_dropped++;
@@ -141,19 +198,96 @@ static void rionet_rx_fill(struct net_device *ndev, int end)
 		if (!rnet->rx_skb[i])
 			break;
 
+#ifndef CONFIG_RIONET_MEMMAP
 		rio_add_inb_buffer(rnet->mport, RIONET_MAILBOX,
 				   rnet->rx_skb[i]->data);
+#endif
 	} while ((i = (i + 1) % RIONET_RX_RING_SIZE) != end);
 
 	rnet->rx_slot = i;
 }
 
+#ifdef CONFIG_RIONET_MEMMAP
+static int rio_send_mem(struct sk_buff *skb,
+				struct net_device *ndev, struct rio_dev *rdev)
+{
+	struct rionet_private *rnet = ndev->priv;
+	int enqueue, dequeue;
+	int err;
+
+	if (!rdev)
+		return -EFAULT;
+
+	if (skb->len > RIONET_MAX_SK_DATA_SIZE) {
+		printk("Net frame len more than RIONET max sk_data size!\n");
+		return -EINVAL;
+	}
+
+	err = rio_space_find_mem(rnet->mport, rdev->destid, RIONET_DRVID,
+					&rnet->txmem->riores);
+	if (err) {
+		ndev->stats.tx_dropped++;
+		printk("err %d\n", err);
+		return -EBUSY;
+	}
+	rio_map_outb_region(rnet->mport, rdev->destid, rnet->txmem, 0);
+
+	enqueue = in_be32(&rnet->txbuff->enqueue);
+	dequeue = in_be32(&rnet->txbuff->dequeue);
+
+	if (!(in_be32(&rnet->txbuff->size[enqueue]) & RIONET_SKDATA_EN)
+			&& (RIONET_QUEUE_NEXT(enqueue) != dequeue)) {
+#ifdef CONFIG_RIONET_DMA
+		struct dma_device *dmadev;
+		struct dma_async_tx_descriptor *tx;
+		dma_cookie_t tx_cookie = 0;
+
+		dmadev = rnet->txdmachan->device;
+		tx = dmadev->device_prep_dma_memcpy(rnet->txdmachan, skb->len,
+							0);
+		if (!tx)
+			return;
+		tx->ack = 1;
+		tx->tx_set_dest((void *)rnet->txbuff->skdata[enqueue].data
+				- (void *)rnet->txbuff
+				+ rnet->txmem->iores.start, tx, 0);
+		tx->tx_set_src(dma_map_single(&ndev->dev, skb->data, skb->len,
+					DMA_TO_DEVICE), tx, 0);
+		tx_cookie = tx->tx_submit(tx);
+
+		dma_async_memcpy_issue_pending(rnet->txdmachan);
+		while (dma_async_memcpy_complete(rnet->txdmachan,
+					tx_cookie, NULL, NULL) == DMA_IN_PROGRESS) ;
+#else
+		memcpy(rnet->txbuff->skdata[enqueue].data, skb->data, skb->len);
+#endif /* CONFIG_RIONET_DMA */
+		out_be32(&rnet->txbuff->size[enqueue],
+						RIONET_SKDATA_EN | skb->len);
+		out_be32(&rnet->txbuff->enqueue,
+						RIONET_QUEUE_NEXT(enqueue));
+		in_be32(&rnet->txbuff->enqueue);	/* verify read */
+	} else if (netif_msg_tx_err(rnet))
+		printk("txbuff is busy!\n");
+
+	rio_unmap_outb_region(rnet->mport, rnet->txmem);
+	rio_send_doorbell(rdev, RIONET_DOORBELL_SEND);
+	return 0;
+}
+#endif
+
 static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev,
 			       struct rio_dev *rdev)
 {
 	struct rionet_private *rnet = ndev->priv;
 
+#ifdef CONFIG_RIONET_MEMMAP
+	int ret = 0;
+	ret = rio_send_mem(skb, ndev, rdev);
+	if (ret)
+		return ret;
+#else
 	rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len);
+#endif
 	rnet->tx_skb[rnet->tx_slot] = skb;
 
 	ndev->stats.tx_packets++;
@@ -165,6 +299,19 @@ static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev,
 	++rnet->tx_slot;
 	rnet->tx_slot &= (RIONET_TX_RING_SIZE - 1);
 
+#ifdef CONFIG_RIONET_MEMMAP
+	while (rnet->tx_cnt && (rnet->ack_slot != rnet->tx_slot)) {
+		/* dma unmap single */
+		dev_kfree_skb_any(rnet->tx_skb[rnet->ack_slot]);
+		rnet->tx_skb[rnet->ack_slot] = NULL;
+		++rnet->ack_slot;
+		rnet->ack_slot &= (RIONET_TX_RING_SIZE - 1);
+		rnet->tx_cnt--;
+	}
+
+	if (rnet->tx_cnt < RIONET_TX_RING_SIZE)
+		netif_wake_queue(ndev);
+#endif
 	if (netif_msg_tx_queued(rnet))
 		printk(KERN_INFO "%s: queued skb %8.8x len %8.8x\n", DRV_NAME,
 		       (u32) skb, skb->len);
@@ -195,7 +342,8 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	}
 
 	if (eth->h_dest[0] & 0x01) {
-		for (i = 0; i < RIO_MAX_ROUTE_ENTRIES; i++)
+		for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size);
+				i++)
 			if (rionet_active[i])
 				rionet_queue_tx_msg(skb, ndev,
 						    rionet_active[i]);
@@ -210,6 +358,92 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 	return 0;
 }
 
+#ifdef CONFIG_RIONET_MEMMAP
+static void rio_recv_mem(struct net_device *ndev)
+{
+	struct rionet_private *rnet = (struct rionet_private *)ndev->priv;
+	struct sk_buff *skb;
+	u32 enqueue, dequeue, size;
+	int error = 0;
+	dma_cookie_t rx_cookie = 0;
+#ifdef CONFIG_RIONET_DMA
+	struct dma_device *dmadev;
+	struct dma_async_tx_descriptor *tx;
+#endif
+
+	dequeue = rnet->rxbuff->dequeue;
+	enqueue = rnet->rxbuff->enqueue;
+
+	while (enqueue != dequeue) {
+		size = rnet->rxbuff->size[dequeue];
+		if (!(size & RIONET_SKDATA_EN))
+			return;
+		size &= ~RIONET_SKDATA_EN;
+
+		if (!(skb = dev_alloc_skb(size + 2)))
+			return;
+
+#ifdef CONFIG_RIONET_DMA
+		dmadev = rnet->rxdmachan->device;
+		tx = dmadev->device_prep_dma_memcpy(rnet->rxdmachan, size, 0);
+		if (!tx)
+			return;
+		tx->ack = 1;
+		tx->tx_set_dest(dma_map_single(&ndev->dev, skb_put(skb, size),
+					size, DMA_FROM_DEVICE), tx, 0);
+		tx->tx_set_src((void *)rnet->rxbuff->skdata[dequeue].data
+				- (void *)rnet->rxbuff
+				+ rnet->rxmem->iores.start, tx, 0);
+		rx_cookie = tx->tx_submit(tx);
+		dma_async_memcpy_issue_pending(rnet->rxdmachan);
+		while (dma_async_memcpy_complete(rnet->rxdmachan,
+				rx_cookie, NULL, NULL) == DMA_IN_PROGRESS) ;
+#else
+		memcpy(skb_put(skb, size),
+				rnet->rxbuff->skdata[dequeue].data,
+				size);
+#endif /* CONFIG_RIONET_DMA */
+		skb->dev = ndev;
+		skb->protocol = eth_type_trans(skb, ndev);
+		skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+		error = netif_rx(skb);
+
+		rnet->rxbuff->size[dequeue] &= ~RIONET_SKDATA_EN;
+		rnet->rxbuff->dequeue = RIONET_QUEUE_NEXT(dequeue);
+		dequeue = RIONET_QUEUE_NEXT(dequeue);
+
+		if (error == NET_RX_DROP) {
+			ndev->stats.rx_dropped++;
+		} else if (error == NET_RX_BAD) {
+			if (netif_msg_rx_err(rnet))
+				printk(KERN_WARNING "%s: bad rx packet\n",
+				       DRV_NAME);
+			ndev->stats.rx_errors++;
+		} else {
+			ndev->stats.rx_packets++;
+			ndev->stats.rx_bytes += RIO_MAX_MSG_SIZE;
+		}
+	}
+}
+
+static void rionet_inb_recv_event(struct rio_mport *mport, void *dev_id)
+{
+	struct net_device *ndev = dev_id;
+	struct rionet_private *rnet = (struct rionet_private *)ndev->priv;
+	unsigned long flags;
+
+	if (netif_msg_intr(rnet))
+		printk(KERN_INFO "%s: inbound memory data receive event\n",
+		       DRV_NAME);
+
+	spin_lock_irqsave(&rnet->lock, flags);
+	rio_recv_mem(ndev);
+	spin_unlock_irqrestore(&rnet->lock, flags);
+}
+#endif
+
+
 static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u16 tid,
 			       u16 info)
 {
@@ -231,6 +465,10 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u
 		}
 	} else if (info == RIONET_DOORBELL_LEAVE) {
 		rionet_active[sid] = NULL;
+#ifdef CONFIG_RIONET_MEMMAP
+	} else if (info == RIONET_DOORBELL_SEND) {
+		rionet_inb_recv_event(mport, ndev);
+#endif
 	} else {
 		if (netif_msg_intr(rnet))
 			printk(KERN_WARNING "%s: unhandled doorbell\n",
@@ -238,6 +476,7 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u
 	}
 }
 
+#ifndef CONFIG_RIONET_MEMMAP
 static void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot)
 {
 	int n;
@@ -280,6 +519,58 @@ static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbo
 
 	spin_unlock(&rnet->lock);
 }
+#endif
+
+#ifdef CONFIG_RIONET_DMA
+static enum dma_state_client rionet_dma_event(struct dma_client *client,
+		struct dma_chan *chan, enum dma_state state)
+{
+	struct rionet_private *rnet = container_of(client,
+			struct rionet_private, rio_dma_client);
+	enum dma_state_client ack = DMA_DUP;
+
+	spin_lock(&rnet->lock);
+	switch (state) {
+	case DMA_RESOURCE_AVAILABLE:
+		if (!rnet->txdmachan) {
+			ack = DMA_ACK;
+			rnet->txdmachan = chan;
+		} else if (!rnet->rxdmachan) {
+			ack = DMA_ACK;
+			rnet->rxdmachan = chan;
+		}
+		break;
+	case DMA_RESOURCE_REMOVED:
+		if (rnet->txdmachan == chan) {
+			ack = DMA_ACK;
+			rnet->txdmachan = NULL;
+		} else if (rnet->rxdmachan == chan) {
+			ack = DMA_ACK;
+			rnet->rxdmachan = NULL;
+		}
+		break;
+	default:
+		break;
+	}
+	spin_unlock(&rnet->lock);
+	return ack;
+}
+
+static int rionet_dma_register(struct rionet_private *rnet)
+{
+	int rc = 0;
+	spin_lock_init(&rnet->rio_dma_event_lock);
+	rnet->rio_dma_client.event_callback = rionet_dma_event;
+	dma_cap_set(DMA_MEMCPY, rnet->rio_dma_client.cap_mask);
+	dma_async_client_register(&rnet->rio_dma_client);
+	dma_async_client_chan_request(&rnet->rio_dma_client);
+
+	if (!rnet->txdmachan || !rnet->rxdmachan)
+		rc = -ENODEV;
+
+	return rc;
+}
+#endif
 
 static int rionet_open(struct net_device *ndev)
 {
@@ -298,6 +589,26 @@ static int rionet_open(struct net_device *ndev)
 					rionet_dbell_event)) < 0)
 		goto out;
 
+#ifdef CONFIG_RIONET_MEMMAP
+	if (!(rnet->rxmem = rio_request_inb_region(rnet->mport, NULL,
+		  RIONET_TX_RX_BUFF_SIZE, "rionet_rx_buff", RIONET_DRVID))) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	rnet->rxbuff = rnet->rxmem->virt;
+
+	if (!(rnet->txmem = rio_prepare_io_mem(rnet->mport, NULL,
+				RIONET_TX_RX_BUFF_SIZE, "rionet_tx_buff"))) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	rnet->txbuff = rnet->txmem->virt;
+#ifdef CONFIG_RIONET_DMA
+	rc = rionet_dma_register(rnet);
+	if (rc)
+		goto out;
+#endif /* CONFIG_RIONET_DMA */
+#else
 	if ((rc = rio_request_inb_mbox(rnet->mport,
 				       (void *)ndev,
 				       RIONET_MAILBOX,
@@ -311,6 +622,7 @@ static int rionet_open(struct net_device *ndev)
 					RIONET_TX_RING_SIZE,
 					rionet_outb_msg_event)) < 0)
 		goto out;
+#endif
 
 	/* Initialize inbound message ring */
 	for (i = 0; i < RIONET_RX_RING_SIZE; i++)
@@ -374,8 +686,18 @@ static int rionet_close(struct net_device *ndev)
 
 	rio_release_inb_dbell(rnet->mport, RIONET_DOORBELL_JOIN,
 			      RIONET_DOORBELL_LEAVE);
+#ifdef CONFIG_RIONET_MEMMAP
+	rio_release_inb_region(rnet->mport, rnet->rxmem);
+	rio_release_outb_region(rnet->mport, rnet->txmem);
+	rnet->rxbuff = NULL;
+	rnet->txbuff = NULL;
+#ifdef CONFIG_RIONET_DMA
+	dma_async_client_unregister(&rnet->rio_dma_client);
+#endif
+#else
 	rio_release_inb_mbox(rnet->mport, RIONET_MAILBOX);
 	rio_release_outb_mbox(rnet->mport, RIONET_MAILBOX);
+#endif
 
 	return 0;
 }
@@ -385,6 +707,8 @@ static void rionet_remove(struct rio_dev *rdev)
 	struct net_device *ndev = NULL;
 	struct rionet_peer *peer, *tmp;
 
+	free_pages((unsigned long)rionet_active, rdev->net->hport->sys_size ?
+					__ilog2(sizeof(void *)) + 4 : 0);
 	unregister_netdev(ndev);
 	kfree(ndev);
 
@@ -443,6 +767,15 @@ static int rionet_setup_netdev(struct rio_mport *mport)
 		goto out;
 	}
 
+	if (!(rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL,
+				mport->sys_size ? __ilog2(sizeof(void *)) + 4
+				: 0))) {
+		rc = -ENOMEM;
+		goto out;
+	}
+	memset((void *)rionet_active, 0, sizeof(void *) *
+				RIO_MAX_ROUTE_ENTRIES(mport->sys_size));
+
 	/* Set up private area */
 	rnet = (struct rionet_private *)ndev->priv;
 	rnet->mport = mport;
-- 
1.5.2

^ permalink raw reply related

* [PATCH 1/3] Move arch/ppc/syslib/ppc85xx_rio.c to arch/powerpc/sysdev/fsl_rio.c
From: Zhang Wei @ 2007-12-13  7:58 UTC (permalink / raw)
  To: mporter, paulus, galak; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <11975326982876-git-send-email-wei.zhang@freescale.com>

Signed-off-by: Zhang Wei <wei.zhang@freescale.com>
---
 arch/powerpc/sysdev/fsl_rio.c |  932 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 932 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/sysdev/fsl_rio.c

diff --git a/arch/powerpc/sysdev/fsl_rio.c b/arch/powerpc/sysdev/fsl_rio.c
new file mode 100644
index 0000000..af2425e
--- /dev/null
+++ b/arch/powerpc/sysdev/fsl_rio.c
@@ -0,0 +1,932 @@
+/*
+ * MPC85xx RapidIO support
+ *
+ * Copyright 2005 MontaVista Software, Inc.
+ * Matt Porter <mporter@kernel.crashing.org>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/rio.h>
+#include <linux/rio_drv.h>
+
+#include <asm/io.h>
+
+#define RIO_REGS_BASE		(CCSRBAR + 0xc0000)
+#define RIO_ATMU_REGS_OFFSET	0x10c00
+#define RIO_MSG_REGS_OFFSET	0x11000
+#define RIO_MAINT_WIN_SIZE	0x400000
+#define RIO_DBELL_WIN_SIZE	0x1000
+
+#define RIO_MSG_OMR_MUI		0x00000002
+#define RIO_MSG_OSR_TE		0x00000080
+#define RIO_MSG_OSR_QOI		0x00000020
+#define RIO_MSG_OSR_QFI		0x00000010
+#define RIO_MSG_OSR_MUB		0x00000004
+#define RIO_MSG_OSR_EOMI	0x00000002
+#define RIO_MSG_OSR_QEI		0x00000001
+
+#define RIO_MSG_IMR_MI		0x00000002
+#define RIO_MSG_ISR_TE		0x00000080
+#define RIO_MSG_ISR_QFI		0x00000010
+#define RIO_MSG_ISR_DIQI	0x00000001
+
+#define RIO_MSG_DESC_SIZE	32
+#define RIO_MSG_BUFFER_SIZE	4096
+#define RIO_MIN_TX_RING_SIZE	2
+#define RIO_MAX_TX_RING_SIZE	2048
+#define RIO_MIN_RX_RING_SIZE	2
+#define RIO_MAX_RX_RING_SIZE	2048
+
+#define DOORBELL_DMR_DI		0x00000002
+#define DOORBELL_DSR_TE		0x00000080
+#define DOORBELL_DSR_QFI	0x00000010
+#define DOORBELL_DSR_DIQI	0x00000001
+#define DOORBELL_TID_OFFSET	0x03
+#define DOORBELL_SID_OFFSET	0x05
+#define DOORBELL_INFO_OFFSET	0x06
+
+#define DOORBELL_MESSAGE_SIZE	0x08
+#define DBELL_SID(x)		(*(u8 *)(x + DOORBELL_SID_OFFSET))
+#define DBELL_TID(x)		(*(u8 *)(x + DOORBELL_TID_OFFSET))
+#define DBELL_INF(x)		(*(u16 *)(x + DOORBELL_INFO_OFFSET))
+
+struct rio_atmu_regs {
+	u32 rowtar;
+	u32 pad1;
+	u32 rowbar;
+	u32 pad2;
+	u32 rowar;
+	u32 pad3[3];
+};
+
+struct rio_msg_regs {
+	u32 omr;
+	u32 osr;
+	u32 pad1;
+	u32 odqdpar;
+	u32 pad2;
+	u32 osar;
+	u32 odpr;
+	u32 odatr;
+	u32 odcr;
+	u32 pad3;
+	u32 odqepar;
+	u32 pad4[13];
+	u32 imr;
+	u32 isr;
+	u32 pad5;
+	u32 ifqdpar;
+	u32 pad6;
+	u32 ifqepar;
+	u32 pad7[250];
+	u32 dmr;
+	u32 dsr;
+	u32 pad8;
+	u32 dqdpar;
+	u32 pad9;
+	u32 dqepar;
+	u32 pad10[26];
+	u32 pwmr;
+	u32 pwsr;
+	u32 pad11;
+	u32 pwqbar;
+};
+
+struct rio_tx_desc {
+	u32 res1;
+	u32 saddr;
+	u32 dport;
+	u32 dattr;
+	u32 res2;
+	u32 res3;
+	u32 dwcnt;
+	u32 res4;
+};
+
+static u32 regs_win;
+static struct rio_atmu_regs *atmu_regs;
+static struct rio_atmu_regs *maint_atmu_regs;
+static struct rio_atmu_regs *dbell_atmu_regs;
+static u32 dbell_win;
+static u32 maint_win;
+static struct rio_msg_regs *msg_regs;
+
+static struct rio_dbell_ring {
+	void *virt;
+	dma_addr_t phys;
+} dbell_ring;
+
+static struct rio_msg_tx_ring {
+	void *virt;
+	dma_addr_t phys;
+	void *virt_buffer[RIO_MAX_TX_RING_SIZE];
+	dma_addr_t phys_buffer[RIO_MAX_TX_RING_SIZE];
+	int tx_slot;
+	int size;
+	void *dev_id;
+} msg_tx_ring;
+
+static struct rio_msg_rx_ring {
+	void *virt;
+	dma_addr_t phys;
+	void *virt_buffer[RIO_MAX_RX_RING_SIZE];
+	int rx_slot;
+	int size;
+	void *dev_id;
+} msg_rx_ring;
+
+/**
+ * mpc85xx_rio_doorbell_send - Send a MPC85xx doorbell message
+ * @index: ID of RapidIO interface
+ * @destid: Destination ID of target device
+ * @data: 16-bit info field of RapidIO doorbell message
+ *
+ * Sends a MPC85xx doorbell message. Returns %0 on success or
+ * %-EINVAL on failure.
+ */
+static int mpc85xx_rio_doorbell_send(int index, u16 destid, u16 data)
+{
+	pr_debug("mpc85xx_doorbell_send: index %d destid %4.4x data %4.4x\n",
+		 index, destid, data);
+	out_be32((void *)&dbell_atmu_regs->rowtar, destid << 22);
+	out_be16((void *)(dbell_win), data);
+
+	return 0;
+}
+
+/**
+ * mpc85xx_local_config_read - Generate a MPC85xx local config space read
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be read into
+ *
+ * Generates a MPC85xx local configuration space read. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int mpc85xx_local_config_read(int index, u32 offset, int len, u32 * data)
+{
+	pr_debug("mpc85xx_local_config_read: index %d offset %8.8x\n", index,
+		 offset);
+	*data = in_be32((void *)(regs_win + offset));
+
+	return 0;
+}
+
+/**
+ * mpc85xx_local_config_write - Generate a MPC85xx local config space write
+ * @index: ID of RapdiIO interface
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @data: Value to be written
+ *
+ * Generates a MPC85xx local configuration space write. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int mpc85xx_local_config_write(int index, u32 offset, int len, u32 data)
+{
+	pr_debug
+	    ("mpc85xx_local_config_write: index %d offset %8.8x data %8.8x\n",
+	     index, offset, data);
+	out_be32((void *)(regs_win + offset), data);
+
+	return 0;
+}
+
+/**
+ * mpc85xx_rio_config_read - Generate a MPC85xx read maintenance transaction
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Location to be read into
+ *
+ * Generates a MPC85xx read maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int
+mpc85xx_rio_config_read(int index, u16 destid, u8 hopcount, u32 offset, int len,
+			u32 * val)
+{
+	u8 *data;
+
+	pr_debug
+	    ("mpc85xx_rio_config_read: index %d destid %d hopcount %d offset %8.8x len %d\n",
+	     index, destid, hopcount, offset, len);
+	out_be32((void *)&maint_atmu_regs->rowtar,
+		 (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+
+	data = (u8 *) maint_win + offset;
+	switch (len) {
+	case 1:
+		*val = in_8((u8 *) data);
+		break;
+	case 2:
+		*val = in_be16((u16 *) data);
+		break;
+	default:
+		*val = in_be32((u32 *) data);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * mpc85xx_rio_config_write - Generate a MPC85xx write maintenance transaction
+ * @index: ID of RapdiIO interface
+ * @destid: Destination ID of transaction
+ * @hopcount: Number of hops to target device
+ * @offset: Offset into configuration space
+ * @len: Length (in bytes) of the maintenance transaction
+ * @val: Value to be written
+ *
+ * Generates an MPC85xx write maintenance transaction. Returns %0 on
+ * success or %-EINVAL on failure.
+ */
+static int
+mpc85xx_rio_config_write(int index, u16 destid, u8 hopcount, u32 offset,
+			 int len, u32 val)
+{
+	u8 *data;
+	pr_debug
+	    ("mpc85xx_rio_config_write: index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n",
+	     index, destid, hopcount, offset, len, val);
+	out_be32((void *)&maint_atmu_regs->rowtar,
+		 (destid << 22) | (hopcount << 12) | ((offset & ~0x3) >> 9));
+
+	data = (u8 *) maint_win + offset;
+	switch (len) {
+	case 1:
+		out_8((u8 *) data, val);
+		break;
+	case 2:
+		out_be16((u16 *) data, val);
+		break;
+	default:
+		out_be32((u32 *) data, val);
+		break;
+	}
+
+	return 0;
+}
+
+/**
+ * rio_hw_add_outb_message - Add message to the MPC85xx outbound message queue
+ * @mport: Master port with outbound message queue
+ * @rdev: Target of outbound message
+ * @mbox: Outbound mailbox
+ * @buffer: Message to add to outbound queue
+ * @len: Length of message
+ *
+ * Adds the @buffer message to the MPC85xx outbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int
+rio_hw_add_outb_message(struct rio_mport *mport, struct rio_dev *rdev, int mbox,
+			void *buffer, size_t len)
+{
+	u32 omr;
+	struct rio_tx_desc *desc =
+	    (struct rio_tx_desc *)msg_tx_ring.virt + msg_tx_ring.tx_slot;
+	int ret = 0;
+
+	pr_debug
+	    ("RIO: rio_hw_add_outb_message(): destid %4.4x mbox %d buffer %8.8x len %8.8x\n",
+	     rdev->destid, mbox, (int)buffer, len);
+
+	if ((len < 8) || (len > RIO_MAX_MSG_SIZE)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* Copy and clear rest of buffer */
+	memcpy(msg_tx_ring.virt_buffer[msg_tx_ring.tx_slot], buffer, len);
+	if (len < (RIO_MAX_MSG_SIZE - 4))
+		memset((void *)((u32) msg_tx_ring.
+				virt_buffer[msg_tx_ring.tx_slot] + len), 0,
+		       RIO_MAX_MSG_SIZE - len);
+
+	/* Set mbox field for message */
+	desc->dport = mbox & 0x3;
+
+	/* Enable EOMI interrupt, set priority, and set destid */
+	desc->dattr = 0x28000000 | (rdev->destid << 2);
+
+	/* Set transfer size aligned to next power of 2 (in double words) */
+	desc->dwcnt = is_power_of_2(len) ? len : 1 << get_bitmask_order(len);
+
+	/* Set snooping and source buffer address */
+	desc->saddr = 0x00000004 | msg_tx_ring.phys_buffer[msg_tx_ring.tx_slot];
+
+	/* Increment enqueue pointer */
+	omr = in_be32((void *)&msg_regs->omr);
+	out_be32((void *)&msg_regs->omr, omr | RIO_MSG_OMR_MUI);
+
+	/* Go to next descriptor */
+	if (++msg_tx_ring.tx_slot == msg_tx_ring.size)
+		msg_tx_ring.tx_slot = 0;
+
+      out:
+	return ret;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_add_outb_message);
+
+/**
+ * mpc85xx_rio_tx_handler - MPC85xx outbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ *
+ * Handles outbound message interrupts. Executes a register outbound
+ * mailbox event handler and acks the interrupt occurrence.
+ */
+static irqreturn_t
+mpc85xx_rio_tx_handler(int irq, void *dev_instance)
+{
+	int osr;
+	struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+	osr = in_be32((void *)&msg_regs->osr);
+
+	if (osr & RIO_MSG_OSR_TE) {
+		pr_info("RIO: outbound message transmission error\n");
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_TE);
+		goto out;
+	}
+
+	if (osr & RIO_MSG_OSR_QOI) {
+		pr_info("RIO: outbound message queue overflow\n");
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_QOI);
+		goto out;
+	}
+
+	if (osr & RIO_MSG_OSR_EOMI) {
+		u32 dqp = in_be32((void *)&msg_regs->odqdpar);
+		int slot = (dqp - msg_tx_ring.phys) >> 5;
+		port->outb_msg[0].mcback(port, msg_tx_ring.dev_id, -1, slot);
+
+		/* Ack the end-of-message interrupt */
+		out_be32((void *)&msg_regs->osr, RIO_MSG_OSR_EOMI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * rio_open_outb_mbox - Initialize MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @dev_id: Device specific pointer to pass on event
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the outbound mailbox ring
+ *
+ * Initializes buffer ring, request the outbound message interrupt,
+ * and enables the outbound message unit. Returns %0 on success and
+ * %-EINVAL or %-ENOMEM on failure.
+ */
+int rio_open_outb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
+{
+	int i, j, rc = 0;
+
+	if ((entries < RIO_MIN_TX_RING_SIZE) ||
+	    (entries > RIO_MAX_TX_RING_SIZE) || (!is_power_of_2(entries))) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Initialize shadow copy ring */
+	msg_tx_ring.dev_id = dev_id;
+	msg_tx_ring.size = entries;
+
+	for (i = 0; i < msg_tx_ring.size; i++) {
+		if (!
+		    (msg_tx_ring.virt_buffer[i] =
+		     dma_alloc_coherent(NULL, RIO_MSG_BUFFER_SIZE,
+					&msg_tx_ring.phys_buffer[i],
+					GFP_KERNEL))) {
+			rc = -ENOMEM;
+			for (j = 0; j < msg_tx_ring.size; j++)
+				if (msg_tx_ring.virt_buffer[j])
+					dma_free_coherent(NULL,
+							  RIO_MSG_BUFFER_SIZE,
+							  msg_tx_ring.
+							  virt_buffer[j],
+							  msg_tx_ring.
+							  phys_buffer[j]);
+			goto out;
+		}
+	}
+
+	/* Initialize outbound message descriptor ring */
+	if (!(msg_tx_ring.virt = dma_alloc_coherent(NULL,
+						    msg_tx_ring.size *
+						    RIO_MSG_DESC_SIZE,
+						    &msg_tx_ring.phys,
+						    GFP_KERNEL))) {
+		rc = -ENOMEM;
+		goto out_dma;
+	}
+	memset(msg_tx_ring.virt, 0, msg_tx_ring.size * RIO_MSG_DESC_SIZE);
+	msg_tx_ring.tx_slot = 0;
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->odqdpar, msg_tx_ring.phys);
+	out_be32((void *)&msg_regs->odqepar, msg_tx_ring.phys);
+
+	/* Configure for snooping */
+	out_be32((void *)&msg_regs->osar, 0x00000004);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->osr, 0x000000b3);
+
+	/* Hook up outbound message handler */
+	if ((rc =
+	     request_irq(MPC85xx_IRQ_RIO_TX, mpc85xx_rio_tx_handler, 0,
+			 "msg_tx", (void *)mport)) < 0)
+		goto out_irq;
+
+	/*
+	 * Configure outbound message unit
+	 *      Snooping
+	 *      Interrupts (all enabled, except QEIE)
+	 *      Chaining mode
+	 *      Disable
+	 */
+	out_be32((void *)&msg_regs->omr, 0x00100220);
+
+	/* Set number of entries */
+	out_be32((void *)&msg_regs->omr,
+		 in_be32((void *)&msg_regs->omr) |
+		 ((get_bitmask_order(entries) - 2) << 12));
+
+	/* Now enable the unit */
+	out_be32((void *)&msg_regs->omr, in_be32((void *)&msg_regs->omr) | 0x1);
+
+      out:
+	return rc;
+
+      out_irq:
+	dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+			  msg_tx_ring.virt, msg_tx_ring.phys);
+
+      out_dma:
+	for (i = 0; i < msg_tx_ring.size; i++)
+		dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE,
+				  msg_tx_ring.virt_buffer[i],
+				  msg_tx_ring.phys_buffer[i]);
+
+	return rc;
+}
+
+/**
+ * rio_close_outb_mbox - Shut down MPC85xx outbound mailbox
+ * @mport: Master port implementing the outbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the outbound message unit, free all buffers, and
+ * frees the outbound message interrupt.
+ */
+void rio_close_outb_mbox(struct rio_mport *mport, int mbox)
+{
+	/* Disable inbound message unit */
+	out_be32((void *)&msg_regs->omr, 0);
+
+	/* Free ring */
+	dma_free_coherent(NULL, msg_tx_ring.size * RIO_MSG_DESC_SIZE,
+			  msg_tx_ring.virt, msg_tx_ring.phys);
+
+	/* Free interrupt */
+	free_irq(MPC85xx_IRQ_RIO_TX, (void *)mport);
+}
+
+/**
+ * mpc85xx_rio_rx_handler - MPC85xx inbound message interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ *
+ * Handles inbound message interrupts. Executes a registered inbound
+ * mailbox event handler and acks the interrupt occurrence.
+ */
+static irqreturn_t
+mpc85xx_rio_rx_handler(int irq, void *dev_instance)
+{
+	int isr;
+	struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+	isr = in_be32((void *)&msg_regs->isr);
+
+	if (isr & RIO_MSG_ISR_TE) {
+		pr_info("RIO: inbound message reception error\n");
+		out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_TE);
+		goto out;
+	}
+
+	/* XXX Need to check/dispatch until queue empty */
+	if (isr & RIO_MSG_ISR_DIQI) {
+		/*
+		 * We implement *only* mailbox 0, but can receive messages
+		 * for any mailbox/letter to that mailbox destination. So,
+		 * make the callback with an unknown/invalid mailbox number
+		 * argument.
+		 */
+		port->inb_msg[0].mcback(port, msg_rx_ring.dev_id, -1, -1);
+
+		/* Ack the queueing interrupt */
+		out_be32((void *)&msg_regs->isr, RIO_MSG_ISR_DIQI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * rio_open_inb_mbox - Initialize MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @dev_id: Device specific pointer to pass on event
+ * @mbox: Mailbox to open
+ * @entries: Number of entries in the inbound mailbox ring
+ *
+ * Initializes buffer ring, request the inbound message interrupt,
+ * and enables the inbound message unit. Returns %0 on success
+ * and %-EINVAL or %-ENOMEM on failure.
+ */
+int rio_open_inb_mbox(struct rio_mport *mport, void *dev_id, int mbox, int entries)
+{
+	int i, rc = 0;
+
+	if ((entries < RIO_MIN_RX_RING_SIZE) ||
+	    (entries > RIO_MAX_RX_RING_SIZE) || (!is_power_of_2(entries))) {
+		rc = -EINVAL;
+		goto out;
+	}
+
+	/* Initialize client buffer ring */
+	msg_rx_ring.dev_id = dev_id;
+	msg_rx_ring.size = entries;
+	msg_rx_ring.rx_slot = 0;
+	for (i = 0; i < msg_rx_ring.size; i++)
+		msg_rx_ring.virt_buffer[i] = NULL;
+
+	/* Initialize inbound message ring */
+	if (!(msg_rx_ring.virt = dma_alloc_coherent(NULL,
+						    msg_rx_ring.size *
+						    RIO_MAX_MSG_SIZE,
+						    &msg_rx_ring.phys,
+						    GFP_KERNEL))) {
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->ifqdpar, (u32) msg_rx_ring.phys);
+	out_be32((void *)&msg_regs->ifqepar, (u32) msg_rx_ring.phys);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->isr, 0x00000091);
+
+	/* Hook up inbound message handler */
+	if ((rc =
+	     request_irq(MPC85xx_IRQ_RIO_RX, mpc85xx_rio_rx_handler, 0,
+			 "msg_rx", (void *)mport)) < 0) {
+		dma_free_coherent(NULL, RIO_MSG_BUFFER_SIZE,
+				  msg_tx_ring.virt_buffer[i],
+				  msg_tx_ring.phys_buffer[i]);
+		goto out;
+	}
+
+	/*
+	 * Configure inbound message unit:
+	 *      Snooping
+	 *      4KB max message size
+	 *      Unmask all interrupt sources
+	 *      Disable
+	 */
+	out_be32((void *)&msg_regs->imr, 0x001b0060);
+
+	/* Set number of queue entries */
+	out_be32((void *)&msg_regs->imr,
+		 in_be32((void *)&msg_regs->imr) |
+		 ((get_bitmask_order(entries) - 2) << 12));
+
+	/* Now enable the unit */
+	out_be32((void *)&msg_regs->imr, in_be32((void *)&msg_regs->imr) | 0x1);
+
+      out:
+	return rc;
+}
+
+/**
+ * rio_close_inb_mbox - Shut down MPC85xx inbound mailbox
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Mailbox to close
+ *
+ * Disables the inbound message unit, free all buffers, and
+ * frees the inbound message interrupt.
+ */
+void rio_close_inb_mbox(struct rio_mport *mport, int mbox)
+{
+	/* Disable inbound message unit */
+	out_be32((void *)&msg_regs->imr, 0);
+
+	/* Free ring */
+	dma_free_coherent(NULL, msg_rx_ring.size * RIO_MAX_MSG_SIZE,
+			  msg_rx_ring.virt, msg_rx_ring.phys);
+
+	/* Free interrupt */
+	free_irq(MPC85xx_IRQ_RIO_RX, (void *)mport);
+}
+
+/**
+ * rio_hw_add_inb_buffer - Add buffer to the MPC85xx inbound message queue
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ * @buf: Buffer to add to inbound queue
+ *
+ * Adds the @buf buffer to the MPC85xx inbound message queue. Returns
+ * %0 on success or %-EINVAL on failure.
+ */
+int rio_hw_add_inb_buffer(struct rio_mport *mport, int mbox, void *buf)
+{
+	int rc = 0;
+
+	pr_debug("RIO: rio_hw_add_inb_buffer(), msg_rx_ring.rx_slot %d\n",
+		 msg_rx_ring.rx_slot);
+
+	if (msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot]) {
+		printk(KERN_ERR
+		       "RIO: error adding inbound buffer %d, buffer exists\n",
+		       msg_rx_ring.rx_slot);
+		rc = -EINVAL;
+		goto out;
+	}
+
+	msg_rx_ring.virt_buffer[msg_rx_ring.rx_slot] = buf;
+	if (++msg_rx_ring.rx_slot == msg_rx_ring.size)
+		msg_rx_ring.rx_slot = 0;
+
+      out:
+	return rc;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_add_inb_buffer);
+
+/**
+ * rio_hw_get_inb_message - Fetch inbound message from the MPC85xx message unit
+ * @mport: Master port implementing the inbound message unit
+ * @mbox: Inbound mailbox number
+ *
+ * Gets the next available inbound message from the inbound message queue.
+ * A pointer to the message is returned on success or NULL on failure.
+ */
+void *rio_hw_get_inb_message(struct rio_mport *mport, int mbox)
+{
+	u32 imr;
+	u32 phys_buf, virt_buf;
+	void *buf = NULL;
+	int buf_idx;
+
+	phys_buf = in_be32((void *)&msg_regs->ifqdpar);
+
+	/* If no more messages, then bail out */
+	if (phys_buf == in_be32((void *)&msg_regs->ifqepar))
+		goto out2;
+
+	virt_buf = (u32) msg_rx_ring.virt + (phys_buf - msg_rx_ring.phys);
+	buf_idx = (phys_buf - msg_rx_ring.phys) / RIO_MAX_MSG_SIZE;
+	buf = msg_rx_ring.virt_buffer[buf_idx];
+
+	if (!buf) {
+		printk(KERN_ERR
+		       "RIO: inbound message copy failed, no buffers\n");
+		goto out1;
+	}
+
+	/* Copy max message size, caller is expected to allocate that big */
+	memcpy(buf, (void *)virt_buf, RIO_MAX_MSG_SIZE);
+
+	/* Clear the available buffer */
+	msg_rx_ring.virt_buffer[buf_idx] = NULL;
+
+      out1:
+	imr = in_be32((void *)&msg_regs->imr);
+	out_be32((void *)&msg_regs->imr, imr | RIO_MSG_IMR_MI);
+
+      out2:
+	return buf;
+}
+
+EXPORT_SYMBOL_GPL(rio_hw_get_inb_message);
+
+/**
+ * mpc85xx_rio_dbell_handler - MPC85xx doorbell interrupt handler
+ * @irq: Linux interrupt number
+ * @dev_instance: Pointer to interrupt-specific data
+ *
+ * Handles doorbell interrupts. Parses a list of registered
+ * doorbell event handlers and executes a matching event handler.
+ */
+static irqreturn_t
+mpc85xx_rio_dbell_handler(int irq, void *dev_instance)
+{
+	int dsr;
+	struct rio_mport *port = (struct rio_mport *)dev_instance;
+
+	dsr = in_be32((void *)&msg_regs->dsr);
+
+	if (dsr & DOORBELL_DSR_TE) {
+		pr_info("RIO: doorbell reception error\n");
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_TE);
+		goto out;
+	}
+
+	if (dsr & DOORBELL_DSR_QFI) {
+		pr_info("RIO: doorbell queue full\n");
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_QFI);
+		goto out;
+	}
+
+	/* XXX Need to check/dispatch until queue empty */
+	if (dsr & DOORBELL_DSR_DIQI) {
+		u32 dmsg =
+		    (u32) dbell_ring.virt +
+		    (in_be32((void *)&msg_regs->dqdpar) & 0xfff);
+		u32 dmr;
+		struct rio_dbell *dbell;
+		int found = 0;
+
+		pr_debug
+		    ("RIO: processing doorbell, sid %2.2x tid %2.2x info %4.4x\n",
+		     DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
+
+		list_for_each_entry(dbell, &port->dbells, node) {
+			if ((dbell->res->start <= DBELL_INF(dmsg)) &&
+			    (dbell->res->end >= DBELL_INF(dmsg))) {
+				found = 1;
+				break;
+			}
+		}
+		if (found) {
+			dbell->dinb(port, dbell->dev_id, DBELL_SID(dmsg), DBELL_TID(dmsg),
+				    DBELL_INF(dmsg));
+		} else {
+			pr_debug
+			    ("RIO: spurious doorbell, sid %2.2x tid %2.2x info %4.4x\n",
+			     DBELL_SID(dmsg), DBELL_TID(dmsg), DBELL_INF(dmsg));
+		}
+		dmr = in_be32((void *)&msg_regs->dmr);
+		out_be32((void *)&msg_regs->dmr, dmr | DOORBELL_DMR_DI);
+		out_be32((void *)&msg_regs->dsr, DOORBELL_DSR_DIQI);
+	}
+
+      out:
+	return IRQ_HANDLED;
+}
+
+/**
+ * mpc85xx_rio_doorbell_init - MPC85xx doorbell interface init
+ * @mport: Master port implementing the inbound doorbell unit
+ *
+ * Initializes doorbell unit hardware and inbound DMA buffer
+ * ring. Called from mpc85xx_rio_setup(). Returns %0 on success
+ * or %-ENOMEM on failure.
+ */
+static int mpc85xx_rio_doorbell_init(struct rio_mport *mport)
+{
+	int rc = 0;
+
+	/* Map outbound doorbell window immediately after maintenance window */
+	if (!(dbell_win =
+	      (u32) ioremap(mport->iores.start + RIO_MAINT_WIN_SIZE,
+			    RIO_DBELL_WIN_SIZE))) {
+		printk(KERN_ERR
+		       "RIO: unable to map outbound doorbell window\n");
+		rc = -ENOMEM;
+		goto out;
+	}
+
+	/* Initialize inbound doorbells */
+	if (!(dbell_ring.virt = dma_alloc_coherent(NULL,
+						   512 * DOORBELL_MESSAGE_SIZE,
+						   &dbell_ring.phys,
+						   GFP_KERNEL))) {
+		printk(KERN_ERR "RIO: unable allocate inbound doorbell ring\n");
+		rc = -ENOMEM;
+		iounmap((void *)dbell_win);
+		goto out;
+	}
+
+	/* Point dequeue/enqueue pointers at first entry in ring */
+	out_be32((void *)&msg_regs->dqdpar, (u32) dbell_ring.phys);
+	out_be32((void *)&msg_regs->dqepar, (u32) dbell_ring.phys);
+
+	/* Clear interrupt status */
+	out_be32((void *)&msg_regs->dsr, 0x00000091);
+
+	/* Hook up doorbell handler */
+	if ((rc =
+	     request_irq(MPC85xx_IRQ_RIO_BELL, mpc85xx_rio_dbell_handler, 0,
+			 "dbell_rx", (void *)mport) < 0)) {
+		iounmap((void *)dbell_win);
+		dma_free_coherent(NULL, 512 * DOORBELL_MESSAGE_SIZE,
+				  dbell_ring.virt, dbell_ring.phys);
+		printk(KERN_ERR
+		       "MPC85xx RIO: unable to request inbound doorbell irq");
+		goto out;
+	}
+
+	/* Configure doorbells for snooping, 512 entries, and enable */
+	out_be32((void *)&msg_regs->dmr, 0x00108161);
+
+      out:
+	return rc;
+}
+
+static char *cmdline = NULL;
+
+static int mpc85xx_rio_get_hdid(int index)
+{
+	/* XXX Need to parse multiple entries in some format */
+	if (!cmdline)
+		return -1;
+
+	return simple_strtol(cmdline, NULL, 0);
+}
+
+static int mpc85xx_rio_get_cmdline(char *s)
+{
+	if (!s)
+		return 0;
+
+	cmdline = s;
+	return 1;
+}
+
+__setup("riohdid=", mpc85xx_rio_get_cmdline);
+
+/**
+ * mpc85xx_rio_setup - Setup MPC85xx RapidIO interface
+ * @law_start: Starting physical address of RapidIO LAW
+ * @law_size: Size of RapidIO LAW
+ *
+ * Initializes MPC85xx RapidIO hardware interface, configures
+ * master port with system-specific info, and registers the
+ * master port with the RapidIO subsystem.
+ */
+void mpc85xx_rio_setup(int law_start, int law_size)
+{
+	struct rio_ops *ops;
+	struct rio_mport *port;
+
+	ops = kmalloc(sizeof(struct rio_ops), GFP_KERNEL);
+	ops->lcread = mpc85xx_local_config_read;
+	ops->lcwrite = mpc85xx_local_config_write;
+	ops->cread = mpc85xx_rio_config_read;
+	ops->cwrite = mpc85xx_rio_config_write;
+	ops->dsend = mpc85xx_rio_doorbell_send;
+
+	port = kmalloc(sizeof(struct rio_mport), GFP_KERNEL);
+	port->id = 0;
+	port->index = 0;
+	INIT_LIST_HEAD(&port->dbells);
+	port->iores.start = law_start;
+	port->iores.end = law_start + law_size;
+	port->iores.flags = IORESOURCE_MEM;
+
+	rio_init_dbell_res(&port->riores[RIO_DOORBELL_RESOURCE], 0, 0xffff);
+	rio_init_mbox_res(&port->riores[RIO_INB_MBOX_RESOURCE], 0, 0);
+	rio_init_mbox_res(&port->riores[RIO_OUTB_MBOX_RESOURCE], 0, 0);
+	strcpy(port->name, "RIO0 mport");
+
+	port->ops = ops;
+	port->host_deviceid = mpc85xx_rio_get_hdid(port->id);
+
+	rio_register_mport(port);
+
+	regs_win = (u32) ioremap(RIO_REGS_BASE, 0x20000);
+	atmu_regs = (struct rio_atmu_regs *)(regs_win + RIO_ATMU_REGS_OFFSET);
+	maint_atmu_regs = atmu_regs + 1;
+	dbell_atmu_regs = atmu_regs + 2;
+	msg_regs = (struct rio_msg_regs *)(regs_win + RIO_MSG_REGS_OFFSET);
+
+	/* Configure maintenance transaction window */
+	out_be32((void *)&maint_atmu_regs->rowbar, 0x000c0000);
+	out_be32((void *)&maint_atmu_regs->rowar, 0x80077015);
+
+	maint_win = (u32) ioremap(law_start, RIO_MAINT_WIN_SIZE);
+
+	/* Configure outbound doorbell window */
+	out_be32((void *)&dbell_atmu_regs->rowbar, 0x000c0400);
+	out_be32((void *)&dbell_atmu_regs->rowar, 0x8004200b);
+	mpc85xx_rio_doorbell_init(port);
+}
-- 
1.5.2

^ permalink raw reply related

* [0/3] Add RapidIO support to powerpc architecture with memory mapping
From: Zhang Wei @ 2007-12-13  7:58 UTC (permalink / raw)
  To: mporter, paulus, galak; +Cc: linuxppc-dev, linux-kernel

Hi,

Those patches add RapidIO support to powerpc archiecture with
memory mapping as below:

[1/3] Copy the arch/ppc RapidIO support to arch/powerpc
[2/3] Make the arch/powerpc RapidIO support workable with of-device
      and add memory mapping support.
[3/3] Add the memory mapping support to rionet driver.

Best Regards,
Zhang Wei

^ permalink raw reply

* [PATCH 20/20] [POWERPC] 4xx: Add 440SPe revA runtime detection to PCIe
From: Benjamin Herrenschmidt @ 2007-12-13  7:38 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev

From: Stefan Roese <sr@denx.de>

This patch adds runtime detection of the 440SPe revision A chips. These
chips are equipped with a slighly different PCIe core and need special/
different initialization. The compatible node is changed to
"plb-pciex-440spe" ("A" and "B" dropped). This is needed for boards that
can be equipped with both PPC revisions like the AMCC Yucca.

Signed-off-by: Stefan Roese <sr@denx.de>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

 arch/powerpc/boot/dts/katmai.dts |    6 +++---
 arch/powerpc/sysdev/ppc4xx_pci.c |   25 +++++++++++++++++--------
 2 files changed, 20 insertions(+), 11 deletions(-)

--- linux-merge.orig/arch/powerpc/boot/dts/katmai.dts	2007-12-11 17:11:37.000000000 +1100
+++ linux-merge/arch/powerpc/boot/dts/katmai.dts	2007-12-11 17:11:37.000000000 +1100
@@ -268,7 +268,7 @@
 			#interrupt-cells = <1>;
 			#size-cells = <2>;
 			#address-cells = <3>;
-			compatible = "ibm,plb-pciex-440speB", "ibm,plb-pciex";
+			compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex";
 			primary;
 			port = <0>; /* port number */
 			reg = <d 00000000 20000000	/* Config space access */
@@ -309,7 +309,7 @@
 			#interrupt-cells = <1>;
 			#size-cells = <2>;
 			#address-cells = <3>;
-			compatible = "ibm,plb-pciex-440speB", "ibm,plb-pciex";
+			compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex";
 			primary;
 			port = <1>; /* port number */
 			reg = <d 20000000 20000000	/* Config space access */
@@ -350,7 +350,7 @@
 			#interrupt-cells = <1>;
 			#size-cells = <2>;
 			#address-cells = <3>;
-			compatible = "ibm,plb-pciex-440speB", "ibm,plb-pciex";
+			compatible = "ibm,plb-pciex-440spe", "ibm,plb-pciex";
 			primary;
 			port = <2>; /* port number */
 			reg = <d 40000000 20000000	/* Config space access */
Index: linux-merge/arch/powerpc/sysdev/ppc4xx_pci.c
===================================================================
--- linux-merge.orig/arch/powerpc/sysdev/ppc4xx_pci.c	2007-12-11 17:11:37.000000000 +1100
+++ linux-merge/arch/powerpc/sysdev/ppc4xx_pci.c	2007-12-11 17:11:37.000000000 +1100
@@ -49,6 +49,15 @@ extern unsigned long total_memory;
 #define RES_TO_U32_HIGH(val)	(0)
 #endif
 
+static inline int ppc440spe_revA(void)
+{
+	/* Catch both 440SPe variants, with and without RAID6 support */
+        if ((mfspr(SPRN_PVR) & 0xffefffff) == 0x53421890)
+                return 1;
+        else
+                return 0;
+}
+
 static void fixup_ppc4xx_pci_bridge(struct pci_dev *dev)
 {
 	struct pci_controller *hose;
@@ -516,8 +525,7 @@ static void __init ppc4xx_probe_pcix_bri
  *
  * We support 3 parts currently based on the compatible property:
  *
- * ibm,plb-pciex-440speA
- * ibm,plb-pciex-440speB
+ * ibm,plb-pciex-440spe
  * ibm,plb-pciex-405ex
  *
  * Anything else will be rejected for now as they are all subtly
@@ -688,7 +696,7 @@ static int ppc440spe_pciex_init_port_hw(
 
 	mtdcri(SDR0, port->sdr_base + PESDRn_DLPSET, val);
 	mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET1, 0x20222222);
-	if (of_device_is_compatible(port->node, "ibm,plb-pciex-440speA"))
+	if (ppc440spe_revA())
 		mtdcri(SDR0, port->sdr_base + PESDRn_UTLSET2, 0x11000000);
 	mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL0SET1, 0x35000000);
 	mtdcri(SDR0, port->sdr_base + PESDRn_440SPE_HSSL1SET1, 0x35000000);
@@ -767,7 +775,6 @@ static struct ppc4xx_pciex_hwops ppc440s
 	.setup_utl	= ppc440speB_pciex_init_utl,
 };
 
-
 #endif /* CONFIG_44x */
 
 #ifdef CONFIG_40x
@@ -881,10 +888,12 @@ static int __init ppc4xx_pciex_check_cor
 		return 0;
 
 #ifdef CONFIG_44x
-	if (of_device_is_compatible(np, "ibm,plb-pciex-440speA"))
-		ppc4xx_pciex_hwops = &ppc440speA_pcie_hwops;
-	else if (of_device_is_compatible(np, "ibm,plb-pciex-440speB"))
-		ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops;
+	if (of_device_is_compatible(np, "ibm,plb-pciex-440spe")) {
+		if (ppc440spe_revA())
+			ppc4xx_pciex_hwops = &ppc440speA_pcie_hwops;
+		else
+			ppc4xx_pciex_hwops = &ppc440speB_pcie_hwops;
+	}
 #endif /* CONFIG_44x    */
 #ifdef CONFIG_40x
 	if (of_device_is_compatible(np, "ibm,plb-pciex-405ex"))

^ permalink raw reply

* [PATCH 19/20] [POWERPC] pci32: 4xx embedded platforms want to reassign all PCI resources
From: Benjamin Herrenschmidt @ 2007-12-13  7:38 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev

This makes 4xx embedded platforms re-assign all PCI resources as we
pretty much never care about what the various firmwares have done on
these, it's generally not compatible with the way the kernel will map
the bridges.

We still need to also enable bus renumbering on some of them, but I
will do that from a separate patch after I've fixed 4xx PCIe to handle
all bus numbers.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

 arch/powerpc/platforms/40x/ep405.c   |    2 ++
 arch/powerpc/platforms/40x/kilauea.c |    3 +++
 arch/powerpc/platforms/40x/walnut.c  |    3 +++
 arch/powerpc/platforms/44x/bamboo.c  |    4 ++++
 arch/powerpc/platforms/44x/ebony.c   |    3 +++
 arch/powerpc/platforms/44x/katmai.c  |    3 +++
 arch/powerpc/platforms/44x/sequoia.c |    5 ++++-
 arch/powerpc/platforms/44x/taishan.c |    2 ++
 8 files changed, 24 insertions(+), 1 deletion(-)

--- linux-work.orig/arch/powerpc/platforms/44x/bamboo.c	2007-12-10 16:51:42.000000000 +1100
+++ linux-work/arch/powerpc/platforms/44x/bamboo.c	2007-12-10 16:55:06.000000000 +1100
@@ -21,6 +21,8 @@
 #include <asm/udbg.h>
 #include <asm/time.h>
 #include <asm/uic.h>
+#include <asm/pci-bridge.h>
+
 #include "44x.h"
 
 static struct of_device_id bamboo_of_bus[] = {
@@ -48,6 +50,8 @@ static int __init bamboo_probe(void)
 	if (!of_flat_dt_is_compatible(root, "amcc,bamboo"))
 		return 0;
 
+	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+
 	return 1;
 }
 
Index: linux-work/arch/powerpc/platforms/40x/ep405.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/40x/ep405.c	2007-12-10 16:51:42.000000000 +1100
+++ linux-work/arch/powerpc/platforms/40x/ep405.c	2007-12-10 16:55:06.000000000 +1100
@@ -101,6 +101,8 @@ static void __init ep405_setup_arch(void
 {
 	/* Find & init the BCSR CPLD */
 	ep405_init_bcsr();
+
+	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
 }
 
 static int __init ep405_probe(void)
Index: linux-work/arch/powerpc/platforms/40x/kilauea.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/40x/kilauea.c	2007-12-10 16:51:42.000000000 +1100
+++ linux-work/arch/powerpc/platforms/40x/kilauea.c	2007-12-10 16:55:06.000000000 +1100
@@ -19,6 +19,7 @@
 #include <asm/udbg.h>
 #include <asm/time.h>
 #include <asm/uic.h>
+#include <asm/pci-bridge.h>
 
 static struct of_device_id kilauea_of_bus[] = {
 	{ .compatible = "ibm,plb4", },
@@ -45,6 +46,8 @@ static int __init kilauea_probe(void)
 	if (!of_flat_dt_is_compatible(root, "amcc,kilauea"))
 		return 0;
 
+	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+
 	return 1;
 }
 
Index: linux-work/arch/powerpc/platforms/40x/walnut.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/40x/walnut.c	2007-12-10 16:51:42.000000000 +1100
+++ linux-work/arch/powerpc/platforms/40x/walnut.c	2007-12-10 16:55:06.000000000 +1100
@@ -24,6 +24,7 @@
 #include <asm/udbg.h>
 #include <asm/time.h>
 #include <asm/uic.h>
+#include <asm/pci-bridge.h>
 
 static struct of_device_id walnut_of_bus[] = {
 	{ .compatible = "ibm,plb3", },
@@ -51,6 +52,8 @@ static int __init walnut_probe(void)
 	if (!of_flat_dt_is_compatible(root, "ibm,walnut"))
 		return 0;
 
+	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+
 	return 1;
 }
 
Index: linux-work/arch/powerpc/platforms/44x/ebony.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/44x/ebony.c	2007-12-10 16:51:42.000000000 +1100
+++ linux-work/arch/powerpc/platforms/44x/ebony.c	2007-12-10 16:55:06.000000000 +1100
@@ -24,6 +24,7 @@
 #include <asm/udbg.h>
 #include <asm/time.h>
 #include <asm/uic.h>
+#include <asm/pci-bridge.h>
 
 #include "44x.h"
 
@@ -55,6 +56,8 @@ static int __init ebony_probe(void)
 	if (!of_flat_dt_is_compatible(root, "ibm,ebony"))
 		return 0;
 
+	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+
 	return 1;
 }
 
Index: linux-work/arch/powerpc/platforms/44x/katmai.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/44x/katmai.c	2007-12-10 16:51:42.000000000 +1100
+++ linux-work/arch/powerpc/platforms/44x/katmai.c	2007-12-10 16:55:06.000000000 +1100
@@ -21,6 +21,7 @@
 #include <asm/udbg.h>
 #include <asm/time.h>
 #include <asm/uic.h>
+#include <asm/pci-bridge.h>
 
 #include "44x.h"
 
@@ -49,6 +50,8 @@ static int __init katmai_probe(void)
 	if (!of_flat_dt_is_compatible(root, "amcc,katmai"))
 		return 0;
 
+	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+
 	return 1;
 }
 
Index: linux-work/arch/powerpc/platforms/44x/sequoia.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/44x/sequoia.c	2007-12-10 16:51:42.000000000 +1100
+++ linux-work/arch/powerpc/platforms/44x/sequoia.c	2007-12-10 16:55:06.000000000 +1100
@@ -21,7 +21,8 @@
 #include <asm/udbg.h>
 #include <asm/time.h>
 #include <asm/uic.h>
-#include "44x.h"
+#include <asm/pci-bridge.h>
+
 
 static struct of_device_id sequoia_of_bus[] = {
 	{ .compatible = "ibm,plb4", },
@@ -48,6 +49,8 @@ static int __init sequoia_probe(void)
 	if (!of_flat_dt_is_compatible(root, "amcc,sequoia"))
 		return 0;
 
+	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+
 	return 1;
 }
 
Index: linux-work/arch/powerpc/platforms/44x/taishan.c
===================================================================
--- linux-work.orig/arch/powerpc/platforms/44x/taishan.c	2007-12-10 16:51:42.000000000 +1100
+++ linux-work/arch/powerpc/platforms/44x/taishan.c	2007-12-10 16:55:06.000000000 +1100
@@ -60,6 +60,8 @@ static int __init taishan_probe(void)
 	if (!of_flat_dt_is_compatible(root, "amcc,taishan"))
 		return 0;
 
+	ppc_pci_flags = PPC_PCI_REASSIGN_ALL_RSRC;
+
 	return 1;
 }
 

^ permalink raw reply

* [PATCH 18/20] [POWERPC] 4xx PCI-E Link setup improvements
From: Benjamin Herrenschmidt @ 2007-12-13  7:38 UTC (permalink / raw)
  To: Josh Boyer; +Cc: linuxppc-dev

This improves the way the 4xx PCI-E code handles checking for a link
and adds explicit testing of CRS result codes on config space accesses.

This should make it more reliable.

Also, bridges with no link are now still created, though config space
accesses beyond the root complex are filtered. This is one step toward
eventually supporting hotplug.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

 arch/powerpc/sysdev/ppc4xx_pci.c |  222 +++++++++++++++++++++++----------------
 arch/powerpc/sysdev/ppc4xx_pci.h |    2 
 2 files changed, 134 insertions(+), 90 deletions(-)

--- linux-merge.orig/arch/powerpc/sysdev/ppc4xx_pci.c	2007-12-11 16:51:20.000000000 +1100
+++ linux-merge/arch/powerpc/sysdev/ppc4xx_pci.c	2007-12-11 16:51:24.000000000 +1100
@@ -16,6 +16,8 @@
  *
  */
 
+#undef DEBUG
+
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/init.h>
@@ -531,10 +533,13 @@ struct ppc4xx_pciex_port
 	struct device_node	*node;
 	unsigned int		index;
 	int			endpoint;
+	int			link;
+	int			has_ibpre;
 	unsigned int		sdr_base;
 	dcr_host_t		dcrs;
 	struct resource		cfg_space;
 	struct resource		utl_regs;
+	void __iomem		*utl_base;
 };
 
 static struct ppc4xx_pciex_port *ppc4xx_pciex_ports;
@@ -706,29 +711,44 @@ static int ppc440spe_pciex_init_port_hw(
 	return 0;
 }
 
-static int ppc440speA_pciex_init_utl(struct ppc4xx_pciex_port *port)
+static int ppc440speA_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
+{
+	return ppc440spe_pciex_init_port_hw(port);
+}
+
+static int ppc440speB_pciex_init_port_hw(struct ppc4xx_pciex_port *port)
 {
-	void __iomem *utl_base;
+	int rc = ppc440spe_pciex_init_port_hw(port);
+
+	port->has_ibpre = 1;
+
+	return rc;
+}
 
+static int ppc440speA_pciex_init_utl(struct ppc4xx_pciex_port *port)
+{
 	/* XXX Check what that value means... I hate magic */
 	dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x68782800);
 
-	utl_base = ioremap(port->utl_regs.start, 0x100);
-	BUG_ON(utl_base == NULL);
-
 	/*
 	 * Set buffer allocations and then assert VRB and TXE.
 	 */
-	out_be32(utl_base + PEUTL_OUTTR,   0x08000000);
-	out_be32(utl_base + PEUTL_INTR,    0x02000000);
-	out_be32(utl_base + PEUTL_OPDBSZ,  0x10000000);
-	out_be32(utl_base + PEUTL_PBBSZ,   0x53000000);
-	out_be32(utl_base + PEUTL_IPHBSZ,  0x08000000);
-	out_be32(utl_base + PEUTL_IPDBSZ,  0x10000000);
-	out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000);
-	out_be32(utl_base + PEUTL_PCTL,    0x80800066);
+	out_be32(port->utl_base + PEUTL_OUTTR,   0x08000000);
+	out_be32(port->utl_base + PEUTL_INTR,    0x02000000);
+	out_be32(port->utl_base + PEUTL_OPDBSZ,  0x10000000);
+	out_be32(port->utl_base + PEUTL_PBBSZ,   0x53000000);
+	out_be32(port->utl_base + PEUTL_IPHBSZ,  0x08000000);
+	out_be32(port->utl_base + PEUTL_IPDBSZ,  0x10000000);
+	out_be32(port->utl_base + PEUTL_RCIRQEN, 0x00f00000);
+	out_be32(port->utl_base + PEUTL_PCTL,    0x80800066);
 
-	iounmap(utl_base);
+	return 0;
+}
+
+static int ppc440speB_pciex_init_utl(struct ppc4xx_pciex_port *port)
+{
+	/* Report CRS to the operating system */
+	out_be32(port->utl_base + PEUTL_PBCTL,    0x08000000);
 
 	return 0;
 }
@@ -736,14 +756,15 @@ static int ppc440speA_pciex_init_utl(str
 static struct ppc4xx_pciex_hwops ppc440speA_pcie_hwops __initdata =
 {
 	.core_init	= ppc440spe_pciex_core_init,
-	.port_init_hw	= ppc440spe_pciex_init_port_hw,
+	.port_init_hw	= ppc440speA_pciex_init_port_hw,
 	.setup_utl	= ppc440speA_pciex_init_utl,
 };
 
 static struct ppc4xx_pciex_hwops ppc440speB_pcie_hwops __initdata =
 {
 	.core_init	= ppc440spe_pciex_core_init,
-	.port_init_hw	= ppc440spe_pciex_init_port_hw,
+	.port_init_hw	= ppc440speB_pciex_init_port_hw,
+	.setup_utl	= ppc440speB_pciex_init_utl,
 };
 
 
@@ -821,30 +842,21 @@ static int ppc405ex_pciex_init_port_hw(s
 
 static int ppc405ex_pciex_init_utl(struct ppc4xx_pciex_port *port)
 {
-	void __iomem *utl_base;
-
 	dcr_write(port->dcrs, DCRO_PEGPL_SPECIAL, 0x0);
 
-	utl_base = ioremap(port->utl_regs.start, 0x100);
-	BUG_ON(utl_base == NULL);
-
 	/*
 	 * Set buffer allocations and then assert VRB and TXE.
 	 */
-	out_be32(utl_base + PEUTL_OUTTR,   0x02000000);
-	out_be32(utl_base + PEUTL_INTR,    0x02000000);
-	out_be32(utl_base + PEUTL_OPDBSZ,  0x04000000);
-	out_be32(utl_base + PEUTL_PBBSZ,   0x21000000);
-	out_be32(utl_base + PEUTL_IPHBSZ,  0x02000000);
-	out_be32(utl_base + PEUTL_IPDBSZ,  0x04000000);
-	out_be32(utl_base + PEUTL_RCIRQEN, 0x00f00000);
-	out_be32(utl_base + PEUTL_PCTL,    0x80800066);
-
-	out_be32(utl_base + PEUTL_PBCTL,   0x0800000c);
-	out_be32(utl_base + PEUTL_RCSTA,
-		 in_be32(utl_base + PEUTL_RCSTA) | 0x000040000);
+	out_be32(port->utl_base + PEUTL_OUTTR,   0x02000000);
+	out_be32(port->utl_base + PEUTL_INTR,    0x02000000);
+	out_be32(port->utl_base + PEUTL_OPDBSZ,  0x04000000);
+	out_be32(port->utl_base + PEUTL_PBBSZ,   0x21000000);
+	out_be32(port->utl_base + PEUTL_IPHBSZ,  0x02000000);
+	out_be32(port->utl_base + PEUTL_IPDBSZ,  0x04000000);
+	out_be32(port->utl_base + PEUTL_RCIRQEN, 0x00f00000);
+	out_be32(port->utl_base + PEUTL_PCTL,    0x80800066);
 
-	iounmap(utl_base);
+	out_be32(port->utl_base + PEUTL_PBCTL,   0x08000000);
 
 	return 0;
 }
@@ -926,17 +938,29 @@ static void __init ppc4xx_pciex_port_ini
 	dcr_write(port->dcrs, DCRO_PEGPL_MSGMSK, 0);
 }
 
-static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
+static int __init ppc4xx_pciex_wait_on_sdr(struct ppc4xx_pciex_port *port,
+					   unsigned int sdr_offset,
+					   unsigned int mask,
+					   unsigned int value,
+					   int timeout_ms)
 {
-	int attempts, rc = 0;
 	u32 val;
 
-	/* Check if it's endpoint or root complex
-	 *
-	 * XXX Do we want to use the device-tree instead ? --BenH.
-	 */
-	val = mfdcri(SDR0, port->sdr_base + PESDRn_DLPSET);
-	port->endpoint = (((val >> 20) & 0xf) != PTYPE_ROOT_PORT);
+	while(timeout_ms--) {
+		val = mfdcri(SDR0, port->sdr_base + sdr_offset);
+		if ((val & mask) == value) {
+			pr_debug("PCIE%d: Wait on SDR %x success with tm %d (%08x)\n",
+				 port->index, sdr_offset, timeout_ms, val);
+			return 0;
+		}
+		msleep(1);
+	}
+	return -1;
+}
+
+static int __init ppc4xx_pciex_port_init(struct ppc4xx_pciex_port *port)
+{
+	int rc = 0;
 
 	/* Init HW */
 	if (ppc4xx_pciex_hwops->port_init_hw)
@@ -944,44 +968,40 @@ static int __init ppc4xx_pciex_port_init
 	if (rc != 0)
 		return rc;
 
-	/*
-	 * Notice: the following delay has critical impact on device
-	 * initialization - if too short (<50ms) the link doesn't get up.
-	 *
-	 * XXX FIXME: There are various issues with that link up thingy,
-	 * we could just wait for the link with a timeout but Stefan says
-	 * some cards need more time even after the link is up. I'll
-	 * investigate. For now, we keep a fixed 1s delay.
-	 *
-	 * Ultimately, it should be made asynchronous so all ports are
-	 * brought up simultaneously though.
-	 */
-	printk(KERN_INFO "PCIE%d: Waiting for link to go up...\n",
+	printk(KERN_INFO "PCIE%d: Checking link...\n",
 	       port->index);
-	msleep(1000);
-
-	/*
-	 * Check that we exited the reset state properly
-	 */
-	val = mfdcri(SDR0, port->sdr_base + PESDRn_RCSSTS);
-	if (val & (1 << 20)) {
-		printk(KERN_WARNING "PCIE%d: PGRST failed %08x\n",
-		       port->index, val);
-		return -1;
-	}
 
-	/*
-	 * Verify link is up
-	 */
-	val = mfdcri(SDR0, port->sdr_base + PESDRn_LOOP);
-	if (!(val & 0x00001000)) {
-		printk(KERN_INFO "PCIE%d: link is not up !\n",
+	/* Wait for reset to complete */
+	if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS, 1 << 20, 0, 10)) {
+		printk(KERN_WARNING "PCIE%d: PGRST failed\n",
 		       port->index);
 		return -1;
 	}
 
-	printk(KERN_INFO "PCIE%d: link is up !\n",
-	       port->index);
+	/* Check for card presence detect if supported, if not, just wait for
+	 * link unconditionally.
+	 *
+	 * note that we don't fail if there is no link, we just filter out
+	 * config space accesses. That way, it will be easier to implement
+	 * hotplug later on.
+	 */
+	if (!port->has_ibpre ||
+	    !ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
+				      1 << 28, 1 << 28, 100)) {
+		printk(KERN_INFO
+		       "PCIE%d: Device detected, waiting for link...\n",
+		       port->index);
+		if (ppc4xx_pciex_wait_on_sdr(port, PESDRn_LOOP,
+					     0x1000, 0x1000, 2000))
+			printk(KERN_WARNING
+			       "PCIE%d: Link up failed\n", port->index);
+		else {
+			printk(KERN_INFO
+			       "PCIE%d: link is up !\n", port->index);
+			port->link = 1;
+		}
+	} else
+		printk(KERN_INFO "PCIE%d: No device detected.\n", port->index);
 
 	/*
 	 * Initialize mapping: disable all regions and configure
@@ -990,12 +1010,13 @@ static int __init ppc4xx_pciex_port_init
 	ppc4xx_pciex_port_init_mapping(port);
 
 	/*
-	 * Setup UTL registers - but only on revA!
-	 * We use default settings for revB chip.
-	 *
-	 * To be reworked. We may also be able to move that to
-	 * before the link wait
-	 * --BenH.
+	 * Map UTL
+	 */
+	port->utl_base = ioremap(port->utl_regs.start, 0x100);
+	BUG_ON(port->utl_base == NULL);
+
+	/*
+	 * Setup UTL registers --BenH.
 	 */
 	if (ppc4xx_pciex_hwops->setup_utl)
 		ppc4xx_pciex_hwops->setup_utl(port);
@@ -1003,15 +1024,13 @@ static int __init ppc4xx_pciex_port_init
 	/*
 	 * Check for VC0 active and assert RDY.
 	 */
-	attempts = 10;
-	while (!(mfdcri(SDR0, port->sdr_base + PESDRn_RCSSTS) & (1 << 16))) {
-		if (!(attempts--)) {
-			printk(KERN_INFO "PCIE%d: VC0 not active\n",
-			       port->index);
-			return -1;
-		}
-		msleep(1000);
+	if (port->link &&
+	    ppc4xx_pciex_wait_on_sdr(port, PESDRn_RCSSTS,
+				     1 << 16, 1 << 16, 5000)) {
+		printk(KERN_INFO "PCIE%d: VC0 not active\n", port->index);
+		port->link = 0;
 	}
+
 	mtdcri(SDR0, port->sdr_base + PESDRn_RCSSET,
 	       mfdcri(SDR0, port->sdr_base + PESDRn_RCSSET) | 1 << 20);
 	msleep(100);
@@ -1048,6 +1067,10 @@ static int ppc4xx_pciex_validate_bdf(str
 	    PCI_SLOT(devfn) != 0)
 		return PCIBIOS_DEVICE_NOT_FOUND;
 
+	/* Check if we have a link */
+	if ((bus->number != port->hose->first_busno) && !port->link)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
 	return 0;
 }
 
@@ -1092,6 +1115,9 @@ static int ppc4xx_pciex_read_config(stru
 	gpl_cfg = dcr_read(port->dcrs, DCRO_PEGPL_CFG);
 	dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg | GPL_DMER_MASK_DISA);
 
+	/* Make sure no CRS is recorded */
+	out_be32(port->utl_base + PEUTL_RCSTA, 0x00040000);
+
 	switch (len) {
 	case 1:
 		*val = in_8((u8 *)(addr + offset));
@@ -1109,6 +1135,14 @@ static int ppc4xx_pciex_read_config(stru
 		 bus->number, hose->first_busno, hose->last_busno,
 		 devfn, offset, len, addr + offset, *val);
 
+	/* Check for CRS (440SPe rev B does that for us but heh ..) */
+	if (in_be32(port->utl_base + PEUTL_RCSTA) & 0x00040000) {
+		pr_debug("Got CRS !\n");
+		if (len != 0 && offset != 0)
+			return PCIBIOS_DEVICE_NOT_FOUND;
+		*val = 0xffff0001;
+	}
+
 	dcr_write(port->dcrs, DCRO_PEGPL_CFG, gpl_cfg);
 
 	return PCIBIOS_SUCCESSFUL;
@@ -1278,8 +1312,11 @@ static void __init ppc4xx_pciex_port_set
 	void __iomem *mbase = NULL, *cfg_data = NULL;
 
 	/* XXX FIXME: Handle endpoint mode properly */
-	if (port->endpoint)
+	if (port->endpoint) {
+		printk(KERN_WARNING "PCIE%d: Port in endpoint mode !\n",
+		       port->index);
 		return;
+	}
 
 	/* Check if primary bridge */
 	if (of_get_property(port->node, "primary", NULL))
@@ -1424,6 +1461,9 @@ static void __init ppc4xx_probe_pciex_br
 	}
 	port->sdr_base = *pval;
 
+	/* XXX Currently, we only support root complex mode */
+	port->endpoint = 0;
+
 	/* Fetch config space registers address */
 	if (of_address_to_resource(np, 0, &port->cfg_space)) {
 		printk(KERN_ERR "%s: Can't get PCI-E config space !",
@@ -1447,8 +1487,10 @@ static void __init ppc4xx_probe_pciex_br
 	port->dcrs = dcr_map(np, dcrs, dcr_resource_len(np, 0));
 
 	/* Initialize the port specific registers */
-	if (ppc4xx_pciex_port_init(port))
+	if (ppc4xx_pciex_port_init(port)) {
+		printk(KERN_WARNING "PCIE%d: Port init failed\n", port->index);
 		return;
+	}
 
 	/* Setup the linux hose data structure */
 	ppc4xx_pciex_port_setup_hose(port);
Index: linux-merge/arch/powerpc/sysdev/ppc4xx_pci.h
===================================================================
--- linux-merge.orig/arch/powerpc/sysdev/ppc4xx_pci.h	2007-12-11 16:51:20.000000000 +1100
+++ linux-merge/arch/powerpc/sysdev/ppc4xx_pci.h	2007-12-11 16:51:24.000000000 +1100
@@ -330,6 +330,8 @@
 /*
  * Config space register offsets
  */
+#define PECFG_ECRTCTL		0x074
+
 #define PECFG_BAR0LMPA		0x210
 #define PECFG_BAR0HMPA		0x214
 #define PECFG_BAR1MPA		0x218

^ 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